4.Connecting to Oracle Database

Connections between python-oracledb and Oracle Database are used for executingSQL andPL/SQL, for callingSODA functions, for receiving databasenotifications andmessages, and forstarting and stopping the database.

This chapter covers python-oracledb’s synchronous programming model. Fordiscussion of asynchronous programming, seeConcurrent Programming with asyncio and Pipelining.

By default, python-oracledb runs in a ‘Thin’ mode which connects directly toOracle Database. This mode does not need Oracle Client libraries. However,someadditional functionality is available whenpython-oracledb uses them. Python-oracledb is said to be in ‘Thick’ mode whenOracle Client libraries are used. SeeEnabling python-oracledb Thick mode. Both modes havecomprehensive functionality supporting the Python Database API v2.0Specification.

If you intend to use the Thick mode, then youmust callinit_oracle_client() in the application before any standaloneconnection or pool is created. The python-oracledb Thick mode loads OracleClient libraries which communicate over Oracle Net to an existing database.The Oracle Client libraries need to be installed separately. SeeInstalling python-oracledb. Oracle Net is not a separate product: it is how theOracle Client and Oracle Database communicate.

There are two ways to create a connection to Oracle Database usingpython-oracledb:

Many connection behaviors can be controlled by python-oracledb connectionoptions. Other settings can be configured inOptional Oracle Net Configuration Files or inOptional Oracle Client Configuration File. These include limiting the amount of time that openinga connection can take, or enablingnetwork encryption.

4.1.Standalone Connections

Standalone connections are database connections that do not use apython-oracledb connection pool. They are useful for simple applications thatuse a single connection to a database. Simple connections are created bycallingoracledb.connect() and passing:

Python-oracledb also supportsexternal authentication sopasswords do not need to be in the application.

4.1.1.Creating a Standalone Connection

Standalone connections are created by callingoracledb.connect().

A simple standalone connection example:

importoracledbimportgetpassuserpwd=getpass.getpass("Enter password: ")connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb")

You could alternatively read the password from an environment variable:

userpwd=os.environ.get("PYTHON_PASSWORD")connection=oracledb.connect(user="hr",password=userpwd,dsn="localhost/orclpdb")

Theoracledb.connect() method allows the database host name anddatabase service name to be passed as separate parameters. The databaselistener port can also be passed:

importosuserpwd=os.environ.get("PYTHON_PASSWORD")connection=oracledb.connect(user="hr",password=userpwd,host="localhost",port=1521,service_name="orclpdb")

A single, combined connection string can be passed toconnect() but thismay cause complications if the password contains “@” or “/” characters:

username="hr"userpwd=os.environ.get("PYTHON_PASSWORD")host="localhost"port=1521service_name="orclpdb"dsn=f'{username}/{userpwd}@{host}:{port}/{service_name}'connection=oracledb.connect(dsn)

If you like to encapsulate values, parameters can be passed using aConnectParams Object:

params=oracledb.ConnectParams(host="my_host",port=my_port,service_name="my_service_name")conn=oracledb.connect(user="my_user",password="my_password",params=params)

Some values such as the database host name can be specified asconnect()parameters, as part of thedsn connection string, and in theparamsobject. A final connection string is internally constructed from anydsn,individual parameters, andparams object values. The precedence is thatvalues in adsn parameter override values passed as individual parameters,which themselves override values set in theparams object.

4.1.1.1.Closing Connections

Connections should be released when they are no longer needed. You may preferto let connections be automatically cleaned up when references to them go outof scope. This lets python-oracledb close dependent resources in the correctorder. For example, you can use a Pythoncontext managerwith block:

withoracledb.connect(user="hr",password=userpwd,dsn="myhostname/orclpdb")asconnection:withconnection.cursor()ascursor:cursor.execute("insert into SomeTable values (:1)",("Some string"))connection.commit()

This code ensures that once the block is completed, the connection is closedand resources have been reclaimed by the database. In addition, any attempt touse the variableconnection outside of the block will simply fail.

Alternatively, you can explicitly close a connection by calling.Connection.close():

connection=oracledb.connect(user="hr",password=userpwd,dsn="localhost/orclpdb")# do something with the connection...# close the connectionconnection.close()

If you explicitly close connections you may also need to close other resourcesfirst.

4.1.2.Common Connection Errors

Some of the common connection errors that you may encounter in thepython-oracledb’s default Thin mode are detailed below. Also seeError Handling in Thin and Thick Modes.

4.1.2.1.Use keyword parameters

If you use:

connection=oracledb.connect("hr",userpwd,"localhost/orclpdb")

then you will get the error:

TypeError:connect()takesfrom0to1positionalargumentsbut3weregiven

Theoracledb.connect() method requires keyword parameters to be used

connection=oracledb.connect(user="hr",password=userpwd,dsn="localhost/orclpdb")

The exception passing a single argument containing the combined credential andconnection string. This is supported:

connection=oracledb.connect("hr/userpwd@localhost/orclpdb")

4.1.2.2.Use the correct credentials

If your username or password are not known by the database that you attemptedto connect to, then you will get the error:

ORA-01017:invalidcredentialornotauthorized;logondenied

Find the correct username and password and try reconnecting.

4.1.2.3.Use the correct connection string

If the hostname, port, or service name are incorrect, then the connection will failwith the error:

DPY-6001:cannotconnecttodatabase.Service"doesnotexist"isnotregisteredwiththelistenerathost"localhost"port1521.(SimilartoORA-12514)

This error means that Python successfully reached a computer (in this case,“localhost” using the default port 1521) that is running a database. However,the database service you wanted (“doesnotexist”) does not exist there.

Technically, the error means the listener does not know about the service at themoment. So you might also get this error if the database is currently restarting.

This error is similar to theORA-12514 error that you may see when connectingwith python-oracledb in Thick mode, or with some other Oracle tools.

The solution is to use a valid service name in the connection string. You can:

  • Check and fix any typos in the service name you used

  • Check if the hostname and port are correct

  • Ask your database administrator (DBA) for the correct values

  • Wait a few moments and re-try in case the database is restarting

  • Review the connection information in your cloud console or cloud wallet, ifyou are using a cloud database

  • Runlsnrctl status on the database machine to find the known service names

4.2.Oracle Net Services Connection Strings

The data source name parameterdsn oforacledb.connect(),oracledb.create_pool(),oracledb.connect_async(), andoracledb.create_pool_async(), is the Oracle Database Oracle NetServices Connection String (commonly abbreviated as “connection string”) thatidentifies which database service to connect to. Thedsn value can be oneof Oracle Database’s naming methods:

Connection strings used for JDBC and Oracle SQL Developer need to be altered tobe usable as thedsn value, seeJDBC and Oracle SQL Developer Connection Strings.

For more information about naming methods, see theDatabase Net ServicesAdministrator’s Guide.

Note

Creating a connection in python-oracledb Thin mode always requires aconnection string, or the database host name and service name, to bespecified. The Thin mode cannot use “bequeath” connections and does notreference Oracle environment variablesORACLE_SID,TWO_TASK,orLOCAL.

4.2.1.Easy Connect Syntax for Connection Strings

AnEasy Connect string is often the simplestconnection string to use in the data source name parameterdsn ofconnection functions such asoracledb.connect(),oracledb.create_pool(),oracledb.connect_async(), andoracledb.create_pool_async().

Using Easy Connect strings means that an externaltnsnames.ora configuration file is not needed.

The Easy Connect syntax in python-oracledb is:

[[protocol:]//]host1{,host12}[:port1]{,host2:port2}{;host1{,host12}[:port1]}[/[service_name][:server][/instance_name]][?parameter_name=value{&parameter_name=value}]

See theDatabase Net Services Administrator’s Guideand the technical briefOracle Database Easy Connect Plus for more details.

For example, to connect to the Oracle Database serviceorclpdb that isrunning on the hostdbhost.example.com with the default OracleDatabase port 1521, use:

connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb")

If the database is using a non-default port, it must be specified:

connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com:1984/orclpdb")

The Easy Connect syntax supports Oracle Database service names. It cannot beused with the older System Identifiers (SID).

Oracle Net Settings in Easy Connect Strings

The Easy Connect syntax allows someOracle Network and database configuration options to beset. This means that asqlnet.ora file is not needed forcommon connection scenarios.

For example, to set a connection timeout and keep-alive value:

connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb?transport_connect_timeout=10&expire_time=2")

For more information, seeOracle Net Connect Descriptor and Easy Connect Keywords. Any Easy Connectparameters that are not known to python-oracledb are ignored and not passed tothe database.

Python-oracledb Settings in Easy Connect Strings

Many python-oracledb connection method API arguments can alternatively bepassed as Easy Connect parameters with a “pyo.” prefix. For example, to setthe statement cache size used by connections:

connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb?pyo.stmtcachesize=50")

SeePython-oracledb Parameters Settable in Easy Connect Strings or Centralized Configuration Providers for the usable attributes.

4.2.2.Connect Descriptors

Connect Descriptors can be embedded directly in python-oracledb applications,or referenced via aTNS Alias.

An example of direct use is:

dsn="""(DESCRIPTION=             (FAILOVER=on)             (ADDRESS_LIST=               (ADDRESS=(PROTOCOL=tcp)(HOST=sales1-svr)(PORT=1521))               (ADDRESS=(PROTOCOL=tcp)(HOST=sales2-svr)(PORT=1521)))             (CONNECT_DATA=(SERVICE_NAME=sales.example.com)))"""connection=oracledb.connect(user="hr",password=userpwd,dsn=dsn)

Theoracledb.ConnectParams() andConnectParams.get_connect_string() functions can be used to construct aconnect descriptor from the individual components, seeUsing the ConnectParams Builder Class.For example:

cp=oracledb.ConnectParams(host="dbhost.example.com",port=1521,service_name="orclpdb")dsn=cp.get_connect_string()print(dsn)

This prints:

(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dbhost.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orclpdb)))

Syntax is shown in theDatabase Net Services Reference.

AnyDESCRIPTION,CONNECT_DATA andSECURITY parameters of a fullconnect descriptor that are unrecognized by python-oracledb are passed to thedatabase unchanged.

4.2.3.TNS Aliases for Connection Strings

Connect Descriptors are commonly stored in atnsnames.ora file and associated with a TNS Alias. Thisalias can be used directly for the data source name parameterdsn oforacledb.connect(),oracledb.create_pool(),oracledb.connect_async(), andoracledb.create_pool_async().For example, given a file/opt/oracle/config/tnsnames.ora with thefollowing contents:

ORCLPDB=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dbhost.example.com)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orclpdb)))

Then you could connect by passing the TNS Alias “ORCLPDB” (case insensitive) asthedsn value:

connection=oracledb.connect(user="hr",password=userpwd,dsn="orclpdb",config_dir="/opt/oracle/config")

In python-oracledb Thick mode, the configuration directory can also be setduring library initialization:

oracledb.init_oracle_client(config_dir="/opt/oracle/config")connection=oracledb.connect(user="hr",password=userpwd,dsn="orclpdb")

More options for how python-oracledb locatestnsnames.orafiles are detailed inUsing Optional Oracle Configuration Files.

TNS Aliases may also be resolved byLDAP.

For more information about Net Service Names, seeDatabase Net ServicesReference.

4.2.4.LDAP URL Connection Strings

The python-oracledb connection string can be an LDAP URL like:

ldapurl="ldaps://ldapserver.example.com/cn=orcl,cn=OracleContext,dc=example,dc=com"connection=oracledb.connect(user="scott",password=pw,dsn=ldapurl)

This syntax removes the need for external LDAP andsqlnet.ora configurationfiles. See the technical briefOracle Client 23ai LDAP URL Syntax.

In python-oracledb Thin mode, an additionalconnection protocol hookfunction is required to handle this connectionprotocol, seeLDAP Directory Naming. A connection protocol hook function isalso required in python-oracledb Thick mode ifdefaults.thick_mode_dsn_passthrough isFalse.

To use LDAP URLs in python-oracledb Thick mode applications whendefaults.thick_mode_dsn_passthrough isTrue, the Oracle Clientlibraries must be 23.4, or later.

4.2.5.Centralized Configuration Provider URL Connection Strings

ACentralized Configuration Provider URLconnection string allows python-oracledb configuration information to be storedcentrally in OCI Object Storage, in Azure App Configuration, or in a localfile. Given a provider URL, python-oracledb will access the information storedin the configuration provider and use it to connect to Oracle Database.

The database connect descriptor and any database credentials stored in aconfiguration provider will be used by any language driver that accesses theconfiguration. Other driver-specific sections can exist. Python-oracledb willtake settings that are in a section with the prefix “pyo”, and will ignoreother sections.

For example, to use connection configuration stored in a local file/opt/oracle/my-config.json:

{"connect_descriptor":"localhost/orclpdb","pyo":{"min":5,"max":10,"increment":2"stmtcachesize":4}}

You could use this to create a connection pool by specifying thedsnconnection string parameter as:

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="config-file:///opt/oracle/my-config.json")

The pool will be created using the pool settings from the configuration.

The Centralized Configuration Provider URL must begin with“config-<configuration-provider>://” where the configuration-provider value canbe set toociobject,azure, orfile, depending on the location of yourconfiguration information.

SeeCentralized Configuration Providers for more information, particularly regardingusing python-oracledb Thick mode.

The valid keys for the “pyo” object are shown inPython-oracledb Parameters Settable in Easy Connect Strings or Centralized Configuration Providers.

4.2.6.JDBC and Oracle SQL Developer Connection Strings

The python-oracledb connection string syntax is different from Java JDBC and thecommon Oracle SQL Developer syntax. If these JDBC connection strings referencea service name like:

jdbc:oracle:thin:@hostname:port/service_name

For example:

jdbc:oracle:thin:@dbhost.example.com:1521/orclpdb

then use Oracle’s Easy Connect syntax in python-oracledb:

connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com:1521/orclpdb")

You may need to remove JDBC-specific parameters from the connection string anduse python-oracledb alternatives.

If a JDBC connection string uses an old-style Oracle Database SID “systemidentifier”, and the database does not have a service name:

jdbc:oracle:thin:@hostname:port:sid

For example:

jdbc:oracle:thin:@dbhost.example.com:1521:orcl

then connect by using thesid parameter:

connection=oracledb.connect(user="hr",password=userpwd,host="dbhost.example.com",port=1521,sid="orcl")

Alternatively, create atnsnames.ora entry (seeOptional Oracle Net Configuration Files), forexample:

finance=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dbhost.example.com)(PORT=1521))(CONNECT_DATA=(SID=ORCL)))

This can be referenced in python-oracledb:

connection=oracledb.connect(user="hr",password=userpwd,dsn="finance")

4.2.7.Oracle Net Connect Descriptor and Easy Connect Keywords

Easy Connect syntax is described inEasy Connect Syntax for Connection Strings.

Connect Descriptor keywords are shown in theDatabase Net Services Reference.

Notes on specific keywords

ThePOOL_CONNECTION_CLASS orPOOL_PURITY values will only work whenconnected to Oracle Database 21c, or later. Note ifPOOL_PURITY=SELF isused in a connect string, then python-oracledb Thick mode applications willignore the action to drop the session when attempting to remove an unusableconnections from a pool in some uncommon error cases. It is recommended toavoid usingPOOL_PURITY=SELF in a connect string with python-oracledb Thickmode. Instead, code python-oracledb Thick mode applications to explicitlyspecify the purity and connection class as attributes.

TheENABLE=BROKEN connect descriptor option is not supported bypython-oracledb Thin mode. UseEXPIRE_TIME instead.

If a name is given as a connect string, then python-oracledb will consider itas a Net Service Name and not as the minimal Easy Connect string of a hostname.The given connect string will be looked up in atnsnames.ora file. If supporting a bare name as a hostname is important toyou in python-oracledb, then you can alter the connection string to include aprotocol such astcp://hostname, or a port number such ashostname:1521.

In python-oracledb Thick mode, whendefaults.thick_mode_dsn_passthroughisFalse, anyDESCRIPTION,CONNECT_DATA andSECURITY parametersof a full connect descriptor that are unrecognized by python-oracledb arepassed to the database unchanged. Any Easy Connect parameters that are notknown to python-oracledb are discarded and not passed to the database.

4.2.8.Python-oracledb Parameters Settable in Easy Connect Strings or Centralized Configuration Providers

Some python-oracledb connection and pool creation parameters can be set inEasy Connect strings or via aCentralizedConfiguration Provider. This is an alternative topassing explicit arguments tooracledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async(). This allows application behavior to bechanged without needing application code to be updated.

The parameters are shown below inthis table. Parameters have a “pyo.” prefix or are under a“pyo” key. Each of these parameters that is defined in an Easy Connect stringor via a Centralized Configuration Provider will take precedence over the valuepassed as the equivalent python-oracledb API parameter.

Parameters that apply topool creation will be ignored ifthey are used in the context ofstandalone connections. Parameters with unknown names will be ignored in bothcases.

Python-oracledb Parameters in Easy Connect Strings

The Easy Connect parameter names are similar to the python-oracledb methodargument names, but have a “pyo.” prefix. For example:

cs="host.example.com:1522/orclpdb?pyo.stmtcachesize=30&pyo.mode=SYSDBA"connection=oracledb.connect(user="hr",password=userpwd,dsn=cs)

is the same as:

cs="host.example.com:1522/orclpdb"connection=oracledb.connect(user="hr",password=userpwd,dsn=cs,stmtcachesize=30,mode=oracledb.AuthMode.SYSDBA)

If a parameter is specified multiple times in an Easy Connect string, then thelast value of that parameter is used. For example, in“localhost/orclpdb?pyo.sdu=10&pyo.sdu=20” the SDU is set to 20.

Note some Oracle Net parameters can also be prefixed with “pyo.”.

Parameters with the prefix “pyo.” can only be used in Easy Connect strings andnot inConnect Descriptors.

Python-oracledb Parameters in Configuration Providers

With theFile Centralized Configuration Provider orOCI Object Storage Centralized Configuration Provider, the settable python-oracledb driver attributes shouldbe in the JSON file under the key “pyo”. An example is:

{"connect_descriptor":"localhost/orclpdb","pyo":{"min":5,"max":10,"increment":2"stmtcachesize":4}}

WithAzure App Configuration, values are setusing a key such as “<prefix>/pyo/<key name>”. This is similar to howOracleCall Interface settings use the key “<prefix>/oci/<key name>” as shown inOracle Net Service Administrator’s Guide.

Parameter Names

When used in Easy Connect Strings, the parameter names should be prefixed with“pyo.”. When used in a Centralized Configuration Provider, the parameternames are used to form the key names under a parent “pyo” key or with a “pyo/”prefix. The names are case insensitive.

Table 4.1Python-oracledb parameters usable in Easy Connect Strings or Centralized Configuration Providers

Base Parameter Name

Type/Value

Equivalent python-oracledb Connection Parameter Name

Notes

CCLASS

String

cclass

No relevant notes

CONNECTION_ID_PREFIX

String

connection_id_prefix

No relevant notes

DISABLE_OOB

String representing a boolean. Values may be one ofon oroff,true orfalse,yes orno (case insensitive).

disable_oob

No relevant notes

DRIVER_NAME

String

driver_name

No relevant notes

EDITION

String

edition

No relevant notes

EVENTS

String representing a boolean. Values may be one ofon oroff,true orfalse,yes orno (case insensitive).

events

No relevant notes

EXPIRE_TIME

Integer

expire_time

No relevant notes

EXTERNALAUTH

String representing a boolean. Values may be one ofon oroff,true orfalse,yes orno (case insensitive).

externalauth

No relevant notes

EXTRA_AUTH_PARAMS

A dictionary containing the configuration parameters necessary for Oracle Database authentication usingOCI orAzure cloud native authentication plugins.

extra_auth_params

For use by Centralized Configuration Providers only

GETMODE

String, values may be one ofFORCEGET,NOWAIT,WAIT, orTIMEDWAIT mapping toConnection Pool Get Modes.

getmode

Pool creation only

HOMOGENEOUS

String representing a boolean. Values may be one ofon oroff,true orfalse,yes orno (case insensitive).

homogeneous

Pool creation only

HTTPS_PROXY

String

https_proxy

No relevant notes

HTTPS_PROXY_PORT

Integer

https_proxy_port

No relevant notes

INCREMENT

Integer

increment

Pool creation only

MACHINE

String

machine

No relevant notes

MAX

Integer

max

Pool creation only

MAX_LIFETIME_SESSION

Integer

max_lifetime_session

Pool creation only

MAX_SESSIONS_PER_SHARD

Integer

max_sessions_per_shard

Pool creation only

MIN

Integer

min

Pool creation only

MODE

String, values may be one ofDEFAULT,PRELIM,SYSASM,SYSBKP,SYSDBA,SYSDGD,SYSKMT,SYSOPER, orSYSRAC mapping toConnection Authorization Modes.

mode

No relevant notes

OSUSER

String

osuser

No relevant notes

PING_INTERVAL

Integer

ping_interval

Pool creation only

PING_TIMEOUT

Integer

ping_timeout

Pool creation only

POOL_BOUNDARY

String

pool_boundary

No relevant notes

PROGRAM

String

program

No relevant notes

PURITY

String, values may be one ofDEFAULT,NEW, orSELF mapping toConnection Pool Purity Constants.

purity

No relevant notes

RETRY_COUNT

Integer

retry_count

No relevant notes

RETRY_DELAY

Integer

retry_delay

No relevant notes

SDU

Integer

sdu

No relevant notes

SODA_METADATA_CACHE

String representing a boolean. Values may be one ofon oroff,true orfalse,yes orno (case insensitive).

soda_metadata_cache

Pool creation only

SSL_SERVER_CERT_DN

String

ssl_server_cert_dn

No relevant notes

SSL_SERVER_DN_MATCH

String representing a boolean. Values may be one ofon oroff,true orfalse,yes orno (case insensitive).

ssl_server_dn_match

No relevant notes

STMTCACHESIZE

Integer

stmtcachesize

No relevant notes

TCP_CONNECT_TIMEOUT

Integer

tcp_connect_timeout

No relevant notes

TERMINAL

String

terminal

No relevant notes

TIMEOUT

Integer

timeout

Pool creation only

USE_TCP_FAST_OPEN

String representing a boolean. Values may be one ofon oroff,true orfalse,yes orno (case insensitive).

use_tcp_fast_open

No relevant notes

USE_SNI

String representing a boolean. Values may be one ofon oroff,true orfalse,yes orno (case insensitive).

use_sni

No relevant notes

WAIT_TIMEOUT

Integer

wait_timeout

Pool creation only

WALLET_LOCATION

String

wallet_location

Not recommended for use in Configuration Providers because the path name may not be valid on any particular application host.

4.3.Centralized Configuration Providers

Centralized Configuration Providers allow the storageand management of database connection credentials and application configurationinformation in a central location. Providers allow you to separately storeconfiguration information from the code of your application. The values thatcan be stored includes the database connection string, database credentials, acache time, and python-oracledb specific attributes such as connection poolsettings. Python-oracledb can use the centrally stored information to connectto Oracle Database withoracledb.connect(),oracledb.create_pool(),oracledb.connect_async(), andoracledb.create_pool_async().

The following configuration providers are supported by python-oracledb:

To use python-oracledbCentralized Configuration Provider functionality in Thick mode, you should setdefaults.thick_mode_dsn_passthrough toFalse. Alternatively useConnectParams.parse_connect_string(), seeUsing the ConnectParams Builder Class.

Note: In Thick mode, whendefaults.thick_mode_dsn_passthrough isTrue, it is the Oracle Client libraries that access the configurationprovider when python-oracledb connection or pool creation methods areinvoked. Any python-oracledb parameter section will be ignored. Any OracleClient Interface parameter section should beremoved from the configurationbecause its values may be different to those that python-oracledb assumes, andwill cause undefined behavior.

Precedence of Attributes

Defining attributes in multiple places is not recommended. However, ifyou have defined the values ofuser andpassword in both theapplication and the configuration provider, then the values defined in theapplication will have the higher precedence. If theexternalauth parameteris set toTrue, then theuser andpassword values specified in theconfiguration provider are ignored.

If other python-oracledb connection attributes have been defined in both theapplication and the configuration provider, then the values defined in theconfiguration provider will have higher precedence.

If you are using Thick mode, and have defined python-oracledb attributes in anoraaccess.xml file (seeOptional Oracle Client Configuration File), the configuration provider,and the application, then the values defined in the configuration provider willhave the higher precedence followed by theoraaccess.xml file settings, andthen application settings.

4.3.1.Using a File Centralized Configuration Provider

The File Centralized Configuration Provider enables the storage and managementof Oracle Database connection information using local files.

To use a File Centralized Configuration Provider, you must:

  1. Store the connection information in a JSON file on your local file system.

  2. Set the path to the file in thedsn parameter of connection and poolcreation methods.

File Centralized Configuration Provider JSON File Syntax

The configuration file must contain at least aconnect_descriptor key tospecify the database connection string. Optionally, you can store the databaseuser name, password, a cache time, andpython-oracledb settings. The keys that can be stored in the file are:

Table 4.2JSON keys for the File Configuration Provider

Key

Description

Required or Optional

user

The database user name.

Optional

password

The password of the database user as a dictionary containing the key “type” and password type-specific keys.

Warning

Storing passwords in the configuration file should only ever be used in development or test environments.

Optional

connect_descriptor

The databaseconnection string.

Required

config_time_to_live

The number of seconds the configuration is cached for. Defaults to 86,400 seconds (24 hours).

Optional

config_time_to_live_grace_period

The number of seconds an expired configuration can still be used if a new configuration cannot be obtained. Defaults to 1,800 seconds (30 minutes).

Optional

pyo

SeePython-oracledb Parameters Settable in Easy Connect Strings or Centralized Configuration Providers.

Optional

See theOracle Net Service Administrator’s Guide formore information on the generic provider sub-objects usable in JSON files.

Multiple configurations can be defined by specifying the above keys underuser-chosen, top-level keys, see the example further below.

File Centralized Configuration Provider DSN Syntax

To use a file provider, specify thedsn parameter oforacledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async() usingthe following format:

config-file://<file-path-and-name>[?key=<key_name>]

The elements of thedsn parameter are detailed in the table below.

Table 4.3Connection String Parameters for File Configuration Provider

Parameter

Description

config-file

Indicates that the centralized configuration provider is a file in your local system.

<file-name>

The file path and name of the JSON file that contains the configuration information. For relative paths, python-oracledb will use the connection or pool creationconfig_dir parameter, ordefaults.config_dir value, to create an absolute path.

key

The connection key name used to identify a specific configuration. If this parameter is specified, the file is assumed to contain multiple configurations that are indexed by the key value. If not specified, the file is assumed to contain a single configuration. See the example further below.

File Configuration Provider Examples

An example of File Configuration Provider file syntax is:

{"user":"scott","password":{"type":"base64","value":"dGlnZXI="},"connect_descriptor":"dbhost.example.com:1522/orclpdb","pyo":{"stmtcachesize":30,"min":2,"max":10}}

This encodes the password as base64. SeeUsing an OCI Object Storage Centralized Configuration Provider forother password examples. Plaintext passwords are not supported.

Note that python-oracledb caches configurations by default, seeCaching Configuration Information.

If you have this configuration file in/opt/oracle/my-config1.json, youcould use it like:

connection=oracledb.connect(dsn="config-file:///opt/oracle/my-config1.json")

Multiple configurations can be defined by specifying user-chosen top-levelkeys:

{"production":{"connect_descriptor":"localhost/orclpdb"},"testing":{"connect_descriptor":"localhost/orclpdb","user":"scott","password":{"type":"base64","value":"dGlnZXI="}}}

If you have this configuration file in/opt/oracle/my-config2.json, youcould use it like:

connection=oracledb.connect(user="hr",password=userpwd,dsn="config-file:///opt/oracle/my-config2.json?key=production")

4.3.2.Using an OCI Object Storage Centralized Configuration Provider

The Oracle Cloud Infrastructure (OCI)Object Storage configuration provider enables the storage and management of OracleDatabase connection information as JSON inOCI Object Storage.

To use an OCI Object Storage Centralized Configuration Provider, you must:

  1. Upload a JSON file that contains the connection information into an OCIObject Storage Bucket. SeeUploading an Object Storage Object to a Bucket and theOracle Net ServiceAdministrator’s Guide for the steps.SeeOCI Object Storage Centralized Configuration Provider Parameters for the configuration information that can be added.

  2. Install the PythonOCI module, seeInstall Modules for the OCI Object Storage Centralized Configuration Provider.

  3. Import theoracledb.plugins.oci_config_providerplugin in your application.

  4. Use an OCI Object Storage connection string URLin thedsn parameter of connection and pool creation methods.

OCI Object Storage Centralized Configuration Provider JSON File Syntax

The stored JSON configuration file must contain aconnect_descriptor key.Optionally, you can specify the database user name, password, a cache time, andpython-oracledb attributes. The database password can also be stored securelyusingOCI Vault orAzure Key Vault. Thekeys that can be in the JSON file are listed below.

Table 4.4JSON Keys for OCI Object Storage Configuration Provider

Key

Description

Required or Optional

user

The database user name.

Optional

password

The password of the database user as a dictionary containing the key “type” and password type-specific keys.

Optional

connect_descriptor

The databaseconnection string.

Required

config_time_to_live

The number of seconds the configuration is cached for. Defaults to 86,400 seconds (24 hours).

Optional

config_time_to_live_grace_period

The number of seconds an expired configuration can still be used if a new configuration cannot be obtained. Defaults to 1,800 seconds (30 minutes).

Optional

pyo

SeePython-oracledb Parameters Settable in Easy Connect Strings or Centralized Configuration Providers.

Optional

OCI Object Storage Centralized Configuration Provider DSN Syntax

Thedsn parameter fororacledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async() calls should use a connection string URLin the format:

config-ociobject:<objectstorage-name>/n/{namespaceName}/b/{bucketName}/o/<objectName>[/c/<networkServiceName>][?<option1>=<value1>&<option2>=<value2>...]

The elements of the connection string are detailed in the table below.

Table 4.5Connection String Parameters for OCI Object Storage

Parameter

Description

Required or Optional

config-ociobject

Indicates that the configuration provider is OCI Object Storage.

Required

<objectstorage-name>

The URL of OCI Object Storage endpoint.

Required

<namespaceName>

The OCI Object Storage namespace where the JSON file is stored.

Required

<bucketName>

The OCI Object Storage bucket name where the JSON file is stored.

Required

<objectName>

The JSON file name.

Required

<networkServiceName>

The network service name or alias if the JSON file contains one or more network service names.

Optional

<option>=<value>

The authentication method and its corresponding parameters to access the OCI Object Storage configuration provider. Depending on the specified authentication method, you must also set the corresponding authentication parameters in the connection string. You can specify one of the following authentication methods:

  • API Key-based Authentication: The authentication to OCI is done using API key-related values. This is the default authentication method. Note that this method is used when no authentication value is set or by setting the option value toOCI_DEFAULT. The optional authentication parameters that can be set for this method includeOCI_PROFILE,OCI_TENANCY,OCI_USER,OCI_FINGERPRINT,OCI_KEY_FILE, andOCI_PASS_PHRASE. These authentication parameters can also be set in an OCI Authentication Configuration file which can be stored in a default location~/.oci/config, or in location~/.oraclebmc/config, or in the location specified by the OCI_CONFIG_FILE environment variable. SeeAuthentication Parameters for Oracle Cloud Infrastructure (OCI) Object Storage.

  • Instance Principal Authentication: The authentication to OCI is done using VM instance credentials running on OCI. To use this method, set the option value toOCI_INSTANCE_PRINCIPAL. There are no optional authentication parameters that can be set for this method.

  • Resource Principal Authentication: The authentication to OCI is done using OCI resource principals. To use this method, you must set the option value to OCI_RESOURCE_PRINCIPAL. There are no optional authentication parameters that can be set for this method.

SeeOCI Authentication Methods for more information.

Optional

OCI Object Storage Centralized Configuration Provider Examples

An example of OCI Object Centralized Storage Configuration Provider JSON filesyntax is:

{"user":"scott","password":{"type":"ocivault","value":"oci.vaultsecret.my-secret-id""authentication":{"method":"OCI_INSTANCE_PRINCIPAL"}},"connect_descriptor":"dbhost.example.com:1522/orclpdb","pyo":{"stmtcachesize":30,"min":2,"max":10}}

Passwords can optionally be stored using the Azure Key Vault. To do this,you must import theoracledb.plugins.azure_config_provider python-oracledb plugin in your application and you mustdefine the Azure Key Vault credentials in thepassword key. In this, theazure_client_id andazure_tenant_id must be specified. Also, eitherazure_client_secret orazure_client_certificate_path should bespecified. For example:

"password":{"type":"azurevault","value":"<Azure Key Vault URI>","authentication":{"azure_tenant_id":"<tenant_id>","azure_client_id":"<client_id>","azure_client_secret":"<secret value>"}}

Or:

"password":{"type":"azurevault","value":"<Azure Key Vault URI>","authentication":{"azure_tenant_id":"<tenant_id>","azure_client_id":"<client_id>","azure_client_certificate_path":"<azure_client_certificate_path>"}}

Note that python-oracledb caches configurations by default, seeCaching Configuration Information.

An example of a connection string for the OCI Object Centralized Storageconfiguration provider is:

configociurl="config-ociobject://abc.oraclecloud.com/n/abcnamespace/b/abcbucket/o/abcobject?authentication=oci_default&oci_tenancy=abc123&oci_user=ociuser1&oci_fingerprint=ab:14:ba:13&oci_key_file=ociabc/ocikeyabc.pem"

To create astandalone connection you could usethis like:

importoracledb.plugins.oci_config_providerconfigociurl="config-ociobject://abc.oraclecloud.com/n/abcnamespace/b/abcbucket/o/abcobject?authentication=oci_default&oci_tenancy=abc123&oci_user=ociuser1&oci_fingerprint=ab:14:ba:13&oci_key_file=ociabc/ocikeyabc.pem"connection=oracledb.connect(dsn=configociurl)

The configuration can also be used to create aconnection pool, for example:

pool=oracledb.create_pool(dsn=configociurl)

4.3.3.Using an Azure App Centralized Configuration Provider

Azure App Configuration is a cloud-based service provided by MicrosoftAzure. It can be used for storage and management of Oracle Database connectioninformation as key-value pairs.

To use python-oracledb with Azure App Configuration, you must:

  1. Save your configuration information in your Azure App ConfigurationProvider. SeeAzure App Centralized Configuration Provider Parameters.

  2. Install the Azure App modules, seeInstall Modules for the Azure App Centralized Configuration Provider.

  3. Import theoracledb.plugins.azure_config_providerplugin in your application.

  4. Use an Azure App Configuration connection string URL in thedsn parameter of connection and pool creationmethods.

Azure App Centralized Configuration Provider Parameters

Key-value pairs for stored connection information can be added using theConfiguration explorer page of your Azure App Configuration. SeeCreate akey-value in Azure App Configuration for more information. Alternatively,they can be set by makingREST calls. Also see theOracle Net ServiceAdministrator’s Guide.

You can organize the key-value pairs under a prefix based on yourapplication’s needs. For example, if you have two applications, Sales andHuman Resources, then you can store the relevant configuration informationunder the prefixsales and the prefixhr.

The key-value pairs must contain the keyconnect_descriptor which specifiesthe database connection string. This can be set using a prefix as“<prefix>/connect_descriptor”, for example,sales/connect_descriptor.

You can additionally store the database user name using a key such as“<prefix>/user”, and store the password using “<prefix>/password”. For example,sales/user andsales/password. The database password can also be storedsecurely usingAzure Key Vault. A cache time can optionally be storedusing “<prefix>/config_time_to_live”. For example,sales/60000. SeeCaching Configuration Information.

Optional python-oracledb settings can be set using a key such as“<prefix>/pyo/<key name>”, for examplesales/pyo/min. This is similar to howOracle Call Interface settings use keys like “<prefix>/oci/<key name>” as shown inOracle Net Service Administrator’s Guide.

The keys that can be added in Azure App Configuration are listed below:

Table 4.6Keys for Azure App Configuration

Key

Description

Required or Optional

user

The database user name.

Optional

password

The password of the database user as a dictionary containing the key “type” and password type-specific keys. If using Azure Key Vault, this can be the URI to the vault containing the secret key, specified using the key “uri”

Optional

connect_descriptor

The databaseconnection string.

Required

config_time_to_live

The number of seconds the configuration is cached for. Defaults to 86,400 seconds (24 hours).

Optional

config_time_to_live_grace_period

The number of seconds an expired configuration can still be used if a new configuration cannot be obtained. Defaults to 1,800 seconds (30 minutes).

Optional

pyo

SeePython-oracledb Parameters Settable in Easy Connect Strings or Centralized Configuration Providers.

Optional

Azure App Centralized Configuration Provider DSN Syntax

You must define a connection string URL in a specific format in thedsnparameter oforacledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async() toaccess the information stored in Azure App Configuration. The syntax is:

config-azure://<appconfigname>[?key=<prefix>&label=<value>&<option1>=<value1>&<option2>=<value2>...]

The elements of the connection string are detailed in the table below.

Table 4.7Connection String Parameters for Azure App Centralized Configuration Provider

Parameter

Description

Required or Optional

config-azure

Indicates that the configuration provider is Azure App Configuration.

Required

<appconfigname>

The URL of the Azure App Configuration endpoint. The suffix “.azconfig.io” in the name is optional.

Required

key=<prefix>

A key prefix to identify the connection. You can organize configuration information under a prefix as per application requirements.

Required

label=<value>

The Azure App Configuration label name.

Optional

<option>=<value>

The authentication method and its corresponding parameters to access the Azure App Configuration provider. Depending on the specified authentication method, you must also set the corresponding authentication parameters in the connection string. You can specify one of the following authentication methods:

  • Default Azure Credential: The authentication to Azure App Configuration is done as a service principal (using either a client secret or client certificate) or as a managed identity depending on which parameters are set. This authentication method also supports reading the parameters as environment variables. This is the default authentication method. This method is used when no authentication value is set or by setting the option value toAZURE_DEFAULT. The optional parameters that can be set for this option includeAZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_CLIENT_CERTIFICATE_PATH,AZURE_TENANT_ID, andAZURE_MANAGED_IDENTITY_CLIENT_ID.

  • Service Principal with Client Secret: The authentication to Azure App Configuration is done using the client secret. To use this method, you must set the option value toAZURE_SERVICE_PRINCIPAL. The required parameters that must be set for this option includeAZURE_SERVICE_PRINCIPAL,AZURE_CLIENT_ID,AZURE_CLIENT_SECRET, andAZURE_TENANT_ID.

  • Service Principal with Client Certificate: The authentication to Azure App Configuration is done using the client certificate. To use this method, you must set the option value toAZURE_SERVICE_PRINCIPAL. The required parameters that must be set for this option areAZURE_SERVICE_PRINCIPAL,AZURE_CLIENT_ID,AZURE_CLIENT_CERTIFICATE_PATH, andAZURE_TENANT_ID.

  • Managed Identity: The authentication to Azure App Configuration is done using managed identity or managed user identity credentials. To use this method, you must set the option value toAZURE_MANAGED_IDENTITY. If you want to use a user-assigned managed identity for authentication, then you must specify the required parameterAZURE_MANAGED_IDENTITY_CLIENT_ID.

SeeAuthentication Parameters for Azure App Configuration Store for more information. Note that the Azure service principal with client certificate overrides Azure service principal with client secret.

Optional

Azure App Centralized Configuration Examples

The following table shows sample configuration information defined using theConfiguration explorer page of your Azure App Configuration provider. Theexample uses the prefixtest/.

Sample Azure App Configuration Key

Sample Value

test/connect_descriptor

dbhost.example.com:1522/orclpdb

test/user

scott

test/password

{"uri":"https://mykeyvault.vault.azure.net/secrets/passwordsales"}

test/pyo/max

20

Note that python-oracledb caches configurations by default, seeCaching Configuration Information.

An example of a connection string for the Azure App Configuration provider is:

configazureurl="config-azure://aznetnamingappconfig.azconfig.io/?key=test/&azure_client_id=123-456&azure_client_secret=MYSECRET&azure_tenant_id=789-123"

An example using astandalone connection is:

importoracledb.plugins.azure_config_providerconfigazureurl="config-azure://aznetnamingappconfig.azconfig.io/?key=test/&azure_client_id=123-456&azure_client_secret=MYSECRET&azure_tenant_id=789-123"oracledb.connect(dsn=configazureurl)

The configuration can also be used to create aconnection pool, for example:

oracledb.create_pool(dsn=configazureurl)

4.3.4.Caching Configuration Information

Python-oracledb caches configurations obtained from Centralized ConfigurationProviders to reduce access overheads.

You can use theconfig_time_to_live configuration key to specify the numberof seconds that python-oracledb should keep the information cached. The defaulttime is 86,400 seconds (24 hours).

Whenconfig_time_to_live is reached, the configuration is considered to be“softly expired” and subsequent python-oracledb connections will attempt toobtain the configuration again from the configuration provider. If it cannot beretrieved, python-oracledb will continue to use the previous configuration forup toconfig_time_to_live_grace_period seconds which defaults to 1,800seconds (30 minutes). After this grace period the cached configuration fullyexpires. Future connection attempts will try to retrieve the configuration fromthe provider but will fail if the new configuration cannot be obtained.

An example of changing the cache time to 12 hours with an additional grace timeof 10 minutes for the File or OCI Object Storage Centralized ConfigurationProviders is:

{"connect_descriptor":"dbhost.example.com:1522/orclpdb","config_time_to_live":43200,"config_time_to_live_grace_period":600,"pyo":{"stmtcachesize":30,"min":2,"max":10}}

4.4.Using the ConnectParams Builder Class

TheConnectParams class allows you to define connectionparameters in a single place. Theoracledb.ConnectParams() functionreturns aConnectParams object. The object can be passed tooracledb.connect() ororacledb.connect_async(). For example:

cp=oracledb.ConnectParams(user="hr",password=userpwd,host="dbhost",port=1521,service_name="orclpdb")connection=oracledb.connect(params=cp)

For connection pools, seeUsing the PoolParams Builder Class.

The use of the ConnectParams class is optional because you can pass the sameparameters directly toconnect(). For example, the codeabove is equivalent to:

connection=oracledb.connect(user="hr",password=userpwd,host="dbhost",port=1521,service_name="orclpdb")

If you want to keep credentials separate, you can use ConnectParams just toencapsulate connection string components:

cp=oracledb.ConnectParams(host="dbhost",port=1521,service_name="orclpdb")connection=oracledb.connect(user="hr",password=userpwd,params=cp)

You can useConnectParams.get_connect_string() to get a connectionstring from a ConnectParams object:

cp=oracledb.ConnectParams(host="dbhost",port="my_port",service_name="my_service_name")dsn=cp.get_connect_string()connection=oracledb.connect(user="hr",password=userpwd,dsn=dsn)

Some values such as the database host name can be specified asconnect()parameters, as part of thedsn connection string, and in theparamsobject. A final connection string is internally constructed from anydsn,individual parameters, andparams object values. The precedence is thatvalues in adsn parameter override values passed as individual parameters,which themselves override values set in theparams object.

To parse a connection string and store its components as attributes of aConnectParams instance, useConnectParams.parse_connect_string(). Forexample:

dsn="host.example.com:1522/orclpdb?transport_connect_timeout=15&pyo.stmtcachesize=30"cp=oracledb.ConnectParams()cp.parse_connect_string(dsn)connection=oracledb.connect(user="hr",password=userpwd,params=cp)

Most parameter values oforacledb.ConnectParams() are gettable asattributes. For example, to get the stored host name:

print(cp.host)

Attributes such as the password are not gettable.

You can set individual default attributes usingConnectParams.set():

cp=oracledb.ConnectParams(host="localhost",port=1521,service_name="orclpdb")# set a new portcp.set(port=1522)# change both the port and service namecp.set(port=1523,service_name="orclpdb")

NoteConnectParams.set() has no effect afterConnectParams.parse_connect_string() has been called.

The methodConnectParams.parse_dsn_with_credentials() can be used toextract the username, password, and connection string from a DSN:

cp=oracledb.ConnectParams()(un,pw,cs)=cp.parse_dsn_with_credentials("scott/tiger@localhost/orclpdb")print(un)# scottprint(pw)# tigerprint(cs)# localhost/orclpdb

Any component not found in the DSN is returned asNone.

The methodConnectParams.get_network_service_names() can be used to geta list of the network service names that are defined in thetnsnames.ora file. The directory that contains file can be specified in theconfig_dir attribute.

cp=oracledb.ConnectParams(host="my_host",port=my_port,dsn="orclpdb",config_dir="/opt/oracle/config")cp.get_network_service_names()

IfConnectParams.get_network_service_names() is called but atnsnames.ora file does not exist, then an error such asthe following is returned:

DPY-4026:filetnsnames.oranotfoundin/opt/oracle/config

Ifconfig_dir is not specified, then the followingerror is returned:

DPY-4027:noconfigurationdirectoryspecified

When creating a standalone connection (or connection pool with aPoolParams class) the equivalent internal extraction is doneautomatically when a value is passed for thedsn parameter oforacledb.connect(),oracledb.connect_async(),oracledb.create_pool(), ororacledb.create_pool_async() but novalue is passed for theuser parameter.

4.5.Connection Hook Functions

Python-oracledb supports protocol, password, and parameter hook functions thatcan be used to customize connection logic.

4.5.1.Using Protocol Hook Functions

Theoracledb.register_protocol() method registers a user protocol hookfunction that will be called internally by python-oracledb Thin mode prior toconnection or pool creation. The hook function will be invoked whenoracledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async() arecalled with adsn parameter value prefixed with a specified protocol. Yourhook function is expected to construct valid connection details, whichpython-oracledb will use to complete the connection or pool creation.

You can also make use of a protocol hook function in python-oracledb Thick modeconnection calls by settingdefaults.thick_mode_dsn_passthrough toFalse. Alternatively useConnectParams.parse_connect_string(), seeUsing the ConnectParams Builder Class.

For example, the following hook function handles connection strings prefixedwith thetcp:// protocol. Whenoracledb.connect() is called, thesample hook is invoked internally. It prints the parameters, and sets theconnection information in theparams parameter (without passing thetcp:// prefix toparse_connect_string() otherwiserecursion would occur). This modified ConnectParams object is used bypython-oracledb to establish the database connection:

defmyprotocolhook(protocol,arg,params):print(f"In myprotocolhook: protocol={protocol} arg={arg}")params.parse_connect_string(arg)oracledb.register_protocol("tcp",myprotocolhook)connection=oracledb.connect(user="scott",password=userpwd,dsn="tcp://localhost/orclpdb")withconnection.cursor()ascursor:for(r,)incursor.execute("select user from dual"):print(r)

The output would be:

Inmyprotocolhook:protocol=tcparg=localhost/orclpdbSCOTT

Theparamsattributes can be set withConnectParams.parse_connect_string(), as shown, or by usingConnectParams.set().

SeeLDAP Directory Naming for a fuller example.

Internal protocol hook functions for the “tcp” and “tcps” protocols arepre-registered but can be overridden, if needed. If any other protocol has notbeen registered, then connecting will result in an error.

Callingregister_protocol() with thehook_functionparameter set to None will result in a previously registered user functionbeing removed and the default behavior restored.

Connection Hooks and parse_connect_string()

A registered user protocol hook function will also be invoked inpython-oracledb Thin or Thick modes whenConnectParams.parse_connect_string() is called with aconnect_string parameter beginning with the registered protocol. The hookfunctionparams value will be the invoking ConnectParams instance that youcan update usingConnectParams.set() orConnectParams.parse_connect_string().

For example, with the hookmyprotocolhook shown previously, then the code:

cp=oracledb.ConnectParams()cp.set(port=1234)print(f"host is{cp.host}, port is{cp.port}, service name is{cp.service_name}")cp.parse_connect_string("tcp://localhost/orclpdb")print(f"host is{cp.host}, port is{cp.port}, service name is{cp.service_name}")

prints:

hostisNone,portis1234,servicenameisNoneInmyprotocolhook:protocol=tcparg=localhost/orclpdbhostislocalhost,portis1234,servicenameisorclpdb

If you have an application that can run in either python-oracledb Thin or Thickmodes, and you want a registered connection protocol hook function to be usedin both modes, your connection code can be like:

dsn="tcp://localhost/orclpdb"cp=oracledb.ConnectParams()cp.parse_connect_string(dsn)connection=oracledb.connect(user="hr",password=userpwd,params=cp)

4.5.2.Using Password Hook Functions

Theoracledb.register_password_type() method registers a user passwordhook function that will be called internally by python-oracledb prior toconnection or pool creation whenoracledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async() are called. If thepassword,newpassword, orwallet_password parameters to those methods are adictionary containing the key “type”, then the registered user password hookfunction for the specific type will be invoked. Your hook function is expectedto accept the dictionary and return the actual password string.

Below is an example of a password hook function that handles passwords of typebase64 stored in a dict like “dict(type=’base64’, value=’dGlnZXI=’)”. Notethis specific hook function is already included and registered inpython-oracledb:

defmypasswordhook(args):returnbase64.b64decode(args["value"].encode()).decode()oracledb.register_password_type("base64",mypasswordhook)

Whenoracledb.connect() is called as shown below, the sample hook isinvoked internally. It decodes the base64-encoded string in the key “value” andreturns the password which is then used by python-oracledb to establish aconnection to the database:

connection=oracledb.connect(user="scott",password=dict(type="base64",value="dGlnZXI="),dsn="localhost/orclpdb")

Callingregister_password_type() with thehook_functionparameter set toNone will result in a previously registered user functionbeing removed.

4.5.3.Using Parameter Hook Functions

Theoracledb.register_params_hook() method registers a user parameterhook function that will be called internally by python-oracledb prior toconnection or pool creation whenoracledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async() are called. Your parameter hook functionshould accept a copy of the parameters that will be used to create the pool orstandalone connections. The function can access and modify them in any waynecessary to allow python-oracledb to subsequently complete the connection orpool creation request.

Pre-supplied python-oracledb plugins such as theOCI Cloud NativeAuthentication Plugin (oci_tokens) make use oforacledb.register_params_hook(). This plugin uses the information foundin a connection method’sextra_auth_params parameter and modifies theaccess_token parameter with a function that will acquire the authenticationtoken needed to complete a connection. Refer to the complete pluginimplementation inoci_tokens.py. The key code section showingregistering of a parameter hook function is:

defoci_token_hook(params:oracledb.ConnectParams):ifparams.extra_auth_paramsisnotNone:deftoken_callback(refresh):returngenerate_token(params.extra_auth_params,refresh)params.set(access_token=token_callback)oracledb.register_params_hook(oci_token_hook)

Your code might then try to connect like:

token_based_auth={"auth_type":"SimpleAuthentication","user":<user>,"key_file":<key_file>,"fingerprint":<fingerprint>,"tenancy":<tenancy>,"region":<region>,"profile":<profile>}connection=oracledb.connect(dsn=mydb_low,extra_auth_params=token_based_auth)

To unregister a user function that was earlier registered, you can useoracledb.unregister_params_hook().

If you have registered user hook methods withoracledb.register_protocol() andoracledb.register_params_hook(), then the method registered withoracledb.register_protocol() is invoked first during connection or poolcreation calls. If you callConnectParams.parse_connect_string(), theregistered protocol hook method will be called but the parameter hook will notbe.

4.6.LDAP Directory Naming

Directory Naming centralizes the network names and addresses used forconnections in a single place. More details can be found inConfiguring OracleDatabase Clients for OID and OUD Directory NamingandConfiguring Oracle Database Clients for Microsoft Active Directory Naming.

The DSN for LDAP connections can be an alias, as shown in the above references.Alternatively it can be an LDAP URL. The URL syntax removes the need forexternal LDAP andsqlnet.ora configuration files. See the technical briefOracle Client 23ai LDAP URL Syntax.

Python-oracledb Thick Mode LDAP Aliases

Once a directory server is configured, and necessary configuration files havebeen created as explained in the above references, python-oracledb Thick modeapplications can use the LDAP alias as the python-oracledb connection DSN:

connection=oracledb.connect(user="scott",password=pw,dsn="myLdapAlias")

Python-oracledb Thick Mode LDAP URLs

Python-oracledb Thick mode applications using Oracle Client 23.4, or later, canconnect with an LDAP URL. For example:

ldapurl="ldaps://ldapserver.example.com/cn=orcl,cn=OracleContext,dc=example,dc=com"connection=oracledb.connect(user="scott",password=pw,dsn=ldapurl)

To use an LDAP URL in python-oracledb Thick mode whendefaults.thick_mode_dsn_passthrough isFalse, a connection hookfunction is required as shown below for Thin mode. This lets LDAP URLs beutilized when python-oracledb uses any supported Oracle Client library version.

Python-oracledb Thin Mode LDAP URLs

To use LDAP in python-oracledb Thin mode, calloracledb.register_protocol() to register your own userconnectionprotocol hook function that gets the databaseconnection string from your LDAP server. Your application can then specify anLDAP URL as the DSN in connection and pool creation calls.

For example:

importldap3importre# Get the Oracle Database connection string from an LDAP server when# connection calls use an LDAP URL.# In this example, "protocol"' will have the value "ldap", and "arg" will# be "ldapserver/dbname,cn=OracleContext,dc=dom,dc=com"defldap_hook(protocol,arg,params):pattern=r"^(.+)\/(.+)\,(cn=OracleContext.*)$"match=re.match(pattern,arg)ldap_server,db,ora_context=match.groups()server=ldap3.Server(ldap_server)conn=ldap3.Connection(server)conn.bind()conn.search(ora_context,f"(cn={db})",attributes=['orclNetDescString'])connect_string=conn.entries[0].orclNetDescString.valueparams.parse_connect_string(connect_string)oracledb.register_protocol("ldap",ldap_hook)connection=oracledb.connect(user="hr",password=userpwd,dsn="ldap://ldapserver/dbname,cn=OracleContext,dc=dom,dc=com")

You can modify or extend this as needed, for example to use an LDAP module thatsatisfies your business and security requirements, to handled LDAPS, or tocache the response from the LDAP server.

4.7.Connection Metadata and Application Contexts

During connection you can set additional metadata properties that can beaccessed in the database for tracing and for enforcing fine-grained dataaccess, for example with Oracle Virtual Private Database policies. Values mayappear in logs and audit trails.

End-to-End Tracing Attributes

The connection attributesConnection.client_identifier,Connection.clientinfo,Connection.dbop,Connection.module, andConnection.action set metadata about theconnection.

It is recommended to always set at leastclient_identifier,module, andaction for all applicationsbecause their availability in the database can greatly aid futuretroubleshooting.

SeeOracle Database End-to-End Tracing for more information.

Application Contexts

An application context stores user identification that can enable or prevent auser from accessing data in the database. See the Oracle DatabasedocumentationAbout Application Contexts.

A context has a namespace and a key-value pair. The namespace CLIENTCONTEXT isreserved for use with client session-based application contexts. Contexts areset during connection as an array of 3-tuples containing string values for thenamespace, key, and value. For example:

myctx=[("clientcontext","loc_id","1900")]connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",appcontext=myctx)

Context values set during connection can be directly queried in yourapplications. For example:

withconnection.cursor()ascursor:sql="""select * from locations             where location_id = sys_context('clientcontext', 'loc_id')"""forrincursor.execute(sql):print(r)

This will print:

(1900,'6092 Boxwood St','YSW 9T2','Whitehorse','Yukon','CA')

Multiple context values can be set when connecting. For example:

myctx=[("clientcontext","loc_id","1900"),("clientcontext","my_world","earth"),]connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",appcontext=myctx)withconnection.cursor()ascursor:sql="""select sys_context('clientcontext', 'loc_id'),                    sys_context('clientcontext', 'my_world')             from dual"""forrincursor.execute(sql):print(r)

will display:

('1900','earth')

You can use contexts to set up restrictive policies that are automaticallyapplied to any query executed. See Oracle Database documentationOracleVirtual Private Database (VPD).

4.8.Connection Pooling

Connection pooling can significantly improve application performance andscalability by allowing resource sharing. Pools also let applications useoptional advanced Oracle High Availability features.

Opening a connection to a database can be expensive: the connection string mustbe parsed, a network connection must be established, the Oracle Databasenetwork listener needs to be invoked, user authentication must be performed, adatabase server process must be created, and session memory must be allocated(and then the process is destroyed when the connection is closed). Connectionpools remove the overhead of repeatedly opening and closingstandaloneconnections by establishing a pool of open connectionsthat can be reused throughout the life of an application process.

The pooling solutions available to python-oracledb applications are:

  • Driver Connection Pools: These are managed by thedriver layer. They provide readily available database connections that can beshared by multiple users and are quick for applications to obtain. They helpmake applications scalable and highly available. They are created withoracledb.create_pool() ororacledb.create_pool_async().

    The main use case is for applications that hold connections for relativelyshort durations while doing database work, and that acquire and releaseconnections back to the pool as needed to do those database operations.Using a driver pool is recommended for applications that need to supportmultiple users. High availability benefits also make driver pools useful forsingle-user applications that do infrequent database operations.

  • Database Resident Connection Pooling (DRCP): This is pooling of server processes on the database host so theycan be shared between application connections. This reduces the number ofserver processes that the database host needs to manage.

    DRCP is useful if there are large number of application connections,typically from having multiple application processes, and those applicationsdo frequent connection acquire and release calls as needed to do databaseoperations. It is recommended to use DRCP in conjunction with a driverconnection pool, since this reduces the number of re-authentications andsession memory re-allocations.

  • Proxy Resident Connection Pooling (PRCP): This is connection pooling handled by Oracle’smid-tier connection proxy solution,CMAN-TDM.

    PRCP is useful for applications taking advantage of CMAN-TDM.

  • Implicit Connection Pooling: This can add pooling benefits to applications thatconnect when they start, and only close the connection when the applicationterminates — but relatively infrequently do database work. It makes use ofDRCP or PRCP, but instead of relying on the application to explicitly acquireand release connections, Implicit Connection Pooling automatically detectswhen applications are not performing database work. It then allows theassociated database server process to be used by another connection thatneeds to do a database operation.

    Implicit Connection Pooling is useful for legacy applications or third-partycode that cannot be updated to use a driver connection pool.

Python-oracledbdriver connection pools are the firstchoice for performance, scalability, and high availability. If your databaseis under memory pressure from having too many applications opening too manyconnections, then consider eitherDRCP orImplicitConnection Pooling, depending on your application’sconnection life-cycle. If you are utilizing CMAN-TDM, then usingPRCP can be considered.

4.8.1.Driver Connection Pooling

Python-oracledb’s driver connection pooling lets applications create andmaintain a pool of open connections to the database. Connection pooling isavailable in both Thin andThick modes. Connectionpooling is important for performance and scalability when applications need tohandle a large number of users who do database work for short periods of timebut have relatively long periods when the connections are not needed. The highavailability features of pools also make small pools useful for applicationsthat want a few connections available for infrequent use and requires them tobe immediately usable when acquired. Applications that would benefit fromconnection pooling but are too difficult to modify from the use ofstandalone connections can take advantage ofImplicit Connection Pooling.

In python-oracledb Thick mode, the pool implementation uses Oracle’ssessionpool technology which supports additionalOracle Database features, for example some advancedhigh availability features.

Note

Python-oracledb driver connection pools must be created, used, and closedwithin the same process. Sharing pools or connections across processes hasunpredictable behavior.

Using connection pools in multi-threaded architectures is supported.

Multi-process architectures that cannot be converted to threading may getsome benefit fromDatabase Resident Connection Pooling (DRCP).

4.8.1.1.Creating a Connection Pool

A driver connection pool is created by callingoracledb.create_pool().Various pool options can be specified as described increate_pool() and detailed below.

For example, to create a pool that initially contains one connection butcan grow up to five connections:

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",min=1,max=5,increment=1)

4.8.1.2.Getting Connections from a Pool

After a pool has been created, your application can get a connection fromit by callingConnectionPool.acquire():

connection=pool.acquire()

These connections can be used in the same way thatStandalone Connectionsare used.

By default,acquire() calls wait for a connectionto be available before returning to the application. A connection will beavailable if the pool currently has idle connections, when another userreturns a connection to the pool, or after the pool grows. Waiting allowsapplications to be resilient to temporary spikes in connection load. Usersmay have to wait a brief time to get a connection but will not experienceconnection failures.

You can change the behavior ofacquire() by setting thegetmode option during pool creation. For example, the option can beset so that if all the connections are currently in use by the application, anyadditionalacquire() call will return an errorimmediately.

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",min=2,max=5,increment=1,getmode=oracledb.POOL_GETMODE_NOWAIT)

Note that when using this option value in python-oracledb Thick mode withOracle Client libraries 12.2 or earlier, theacquire()call will still wait if the pool can grow. However, you will get an errorimmediately if the pool is at its maximum size. With newer Oracle Clientlibraries and with Thin mode, an error will be returned if the pool has to, orcannot, grow.

4.8.1.3.Returning Connections to a Pool

When your application has finished performing all required database operations,the pooled connection should be released back to the pool to make it availablefor other users. For example, you can use a Pythoncontext managerwith block which lets pooled connections be closed implicitly at the end ofscope and cleans up dependent resources:

withpool.acquire()asconnection:withconnection.cursor()ascursor:forresultincursor.execute("select * from mytab"):print(result)

Alternatively, you can explicitly return connections withConnectionPool.release() orConnection.close(), however you mayalso need to close other resources first.

If you need to force a connection to be closed and its associated databaseserver process to be released, useConnectionPool.drop():

withpool.acquire()asconnection:...pool.drop(connection)

Avoid doing this unnecessarily because it shrinks the pool. A futureacquire() call may suffer the overhead of establishinga new connection to the database, instead of being able to reuse a connectionalready available in the pool.

4.8.1.4.Closing a Connection Pool

At application shutdown, the connection pool can be completely closed usingConnectionPool.close():

pool.close()

To force immediate pool termination when connections are still in use, execute:

pool.close(force=True)

Seeconnection_pool.py for a runnable example of connection pooling.

4.8.2.Using the Connection Pool Cache

When your application architecture makes it difficult to pass aConnectionPool object between your code layers, you can usethe python-oracledb connection pool cache. This lets you store and retrievepools by name.

Adding a pool to the python-oracledb connection pool cache

To use the python-oracledb pool cache, specify thepool_alias parameterwhen you create a pool during application initialization. Its value should be auser-chosen string. For example:

importoracledbNAME="my_pool"oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",pool_alias=NAME)

This creates a pool and stores it in the cache under the name “my_pool”. Theapplication does not need to store or manage the reference to the pool so thecreate_pool() return value is not saved.

If a pool already exists with the name “my_pool”, the following error willbe raised:

DPY-2055:connectionpoolwithname"my_pool"alreadyexists

Getting a connection from a cached pool

Applications can get a connection from a cached pool by passing its namedirectly tooracledb.connect():

importoracledbNAME="my_pool"connection=oracledb.connect(pool_alias=NAME)

This is equivalent to callingConnectionPool.acquire(). You can passadditional parameters toconnect() that are allowed foracquire(). For example, with aheterogeneous pool you can pass the username and password:

importoracledbNAME="my_pool"connection=oracledb.connect(pool_alias=NAME,user="toto",password=pw)

If there is no pool namedmy_pool in the cache, you will get the followingerror:

DPY-2054:connectionpoolwithname"my_pool"doesnotexist

You cannot passpool_alias and the deprecatedpool parameter togethertooracledb.connect() ororacledb.connect_async(). If you do,the following error is raised:

DPY-2014:"pool_alias"and"pool"cannotbespecifiedtogether

Getting a pool from the connection pool cache

You can useoracledb.get_pool() to retrieve a pool and then access itdirectly:

importoracledbNAME="my_pool"pool=oracledb.get_pool(NAME)connection=pool.acquire()

This allows any connection poolmethod orattribute from a cached pool to be used, as normal.

If there is no pool namedmy_pool in the cache, thenget_pool() will return None.

Removing a pool from the cache

A pool is automatically removed from the cache when the pool is closed:

importoracledbNAME="my_pool"pool=oracledb.get_pool(NAME)pool.close()

4.8.3.Connection Pool Sizing

The Oracle Real-World Performance Group’s recommendation is to use fixed sizeconnection pools. The values ofmin andmax should be the same. Whenusing older versions of Oracle Client libraries theincrement parameterwill need to be zero (which is internally treated as a value of one), butotherwise you may prefer a larger size since this will affect how theconnection pool is re-established after, for example, a network dropoutinvalidates all connections.

Fixed size pools avoid connection storms on the database which can decreasethroughput. SeeGuideline for Preventing Connection Storms: Use Static Pools, which contains more details about sizing of pools.Having a fixed size will also guarantee that the database can handle the upperpool size. For example, if a dynamically sized pool needs to grow but thedatabase resources are limited, thenConnectionPool.acquire() mayreturn errors such asORA-28547. With a fixed pool size, this class of error will occur when thepool is created, allowing you to change the pool size or reconfigure thedatabase before users access the application. With a dynamically growing pool,the error may occur much later while the application is in use.

The Real-World Performance Group also recommends keeping pool sizes smallbecause they often can perform better than larger pools. The pool attributesshould be adjusted to handle the desired workload within the bounds ofavailable resources in python-oracledb and the database.

4.8.3.1.Connection Pool Growth

At pool creation,min connections are established to the database. When apool needs to grow, new connections are created automatically limited by themax size. The poolmax size restricts the number of application usersthat can do work in parallel on the database.

The number of connections opened by a pool can shown with the attribute.ConnectionPool.opened. The number of connections the application hasobtained withacquire() can be shown withConnectionPool.busy. The difference in values is the number ofconnections unused or ‘idle’ in the pool. These idle connections may becandidates for the pool to close, depending on the pool configuration.

Pool growth is normally initiated whenacquire() iscalled and there are no idle connections in the pool that can be returned tothe application. The number of new connections created internally will be thevalue of thecreate_pool() parameterincrement.

Depending on whether Thin or Thick mode is used and on the pool creationgetmode value that is set, anyacquire() call thatinitiates pool growth may wait until allincrement new connections areinternally opened. However, in this case the cost is amortized because lateracquire() calls may not have to wait and canimmediately return an available connection. Some users set largerincrement values even for fixed-size pools because it can help a poolre-establish itself if all connections become invalid, for example after anetwork dropout. In the common case of Thin mode with the defaultgetmodeofPOOL_GETMODE_WAIT, anyacquire() call thatinitiates pool growth will return after the first new connection is created,regardless of how bigincrement is. The pool will then continue tore-establish connections in a background thread.

A connection pool can shrink back to its minimum sizemin when connectionsopened by the pool are not used by the application. This frees up databaseresources while allowing pools to retain open connections for active users. Ifthere are more thanmin connections open, and connections are idle in thepool (i.e. not currently acquired by the application) and unused for longerthan the pool creation attributetimeout value, then they will be closed.The check occurs everytimeout interval and hence in the worst case it maytake twice thetimeout time to close the idle connections. The defaulttimeout is0 seconds signifying an infinite time and meaning idleconnections will never be closed.

The pool creation parametermax_lifetime_session also allows pools toshrink. This parameter bounds the total length of time that a connection canexist starting from the time that it was created in the pool. It is mostly usedfor defensive programming to mitigate against unforeseeable problems that mayoccur with connections. If a connection was createdmax_lifetime_session orlonger seconds ago, then it will be a candidate for being closed. In the casewhentimeout andmax_lifetime_session are both set, the connection willbe terminated if either the idle timeout happens or the maximum lifetimesetting is exceeded. Note that when using python-oracledb in Thick mode withOracle Client libraries prior to 21c, pool shrinkage is only initiated when thepool is accessed so pools in fully dormant applications will not shrink untilthe application is next used. In Thick mode, Oracle Client libraries 12.1, orlater, are needed to usemax_lifetime_session.

For pools created withexternal authentication, withhomogeneous set to False, or when usingDatabase Resident Connection Pooling (DRCP) (inpython-oracledb Thick mode), then the number of connections opened at poolcreation is zero even if a larger value is specified formin. Also, inthese cases the pool increment unit is always 1 regardless of the value ofincrement.

4.8.4.Pool Connection Health

BeforeConnectionPool.acquire() returns, python-oracledb does alightweight check similar toConnection.is_healthy() to see if thenetwork transport for the selected connection is still open. If it is not,thenacquire() will clean up the connection and returna different one.

This check will not detect cases such as where the database session has beenterminated by the DBA, or reached a database resource manager quota limit. Tohelp in those cases,acquire() will also do a fullround-trip database ping similar toConnection.ping() when it is about to return a connection that was idlein the pool (i.e. not acquired by the application) forConnectionPool.ping_interval seconds. If the ping fails, theconnection will be discarded and another one obtained beforeacquire() returns to the application. Theping_timeout parameter tooracledb.create_pool() limits the amountof time that any internal ping is allowed to take. If it is exceeded, perhapsdue to a network hang, the connection is considered unusable and a differentconnection is returned to the application.

Because this full ping is time based and may not occur for eachacquire(), the application may still get an unusableconnection. Also, network timeouts and session termination may occur betweenthe calls toacquire() andCursor.execute().To handle these cases, applications need to check for errors after eachexecute() and make application-specific decisions aboutretrying work if there was a connection failure. When using python-oracledb inThick mode, Oracle Database features likeApplication Continuity can do this automatically in some cases.

You can explicitly initiate a full round-trip ping at any time withConnection.ping() to check connection liveness but the overuse willimpact performance and scalability. To avoid pings hanging due to networkerrors, useConnection.call_timeout to limit the amount of timeping() is allowed to take.

TheConnection.is_healthy() method is an alternative toConnection.ping(). It has lower overheads and may suit some uses, butit does not perform a full connection check.

If thegetmode parameter inoracledb.create_pool() is set tooracledb.POOL_GETMODE_TIMEDWAIT, then the maximum amount of time anacquire() call will wait to get a connection from thepool is limited by the value of theConnectionPool.wait_timeoutparameter. A call that cannot be immediately satisfied will wait no longerthanwait_timeout regardless of the value ofping_timeout.

Connection pool health can be impacted byfirewalls,resource managers or user profileIDLE_TIME values. For best efficiency, ensure these do notexpire idle sessions since this will require connections to be recreated whichwill impact performance and scalability.

A pool’s internal connection re-establishment after lightweight and full pingscan mask performance-impacting configuration issues such as firewallsterminating connections. You should monitorAWRreports for an unexpectedly large connection rate.

4.8.5.Connection Pool Reconfiguration

Some pool settings can be changed dynamically withConnectionPool.reconfigure(). This allows the pool size and otherattributes to be changed during application runtime without needing to restartthe pool or application.

For example a pool’s size can be changed like:

pool.reconfigure(min=10,max=10,increment=0)

After any size change has been processed, reconfiguration on the otherparameters is done sequentially. If an error such as an invalid value occurswhen changing one attribute, then an exception will be generated but any alreadychanged attributes will retain their new values.

During reconfiguration of a pool’s size, the behavior ofConnectionPool.acquire() depends on the pool creationgetmode valuein effect whenacquire() is called, seeConnectionPool.reconfigure(). Closing connections or closing the poolwill wait until after pool reconfiguration is complete.

Callingreconfigure() is the only way to change a pool’smin,maxandincrement values. Other attributes such aswait_timeout can be passed toreconfigure() or theycan be set directly, for example:

pool.wait_timeout=1000

4.8.6.Session Callbacks for Setting Pooled Connection State

Applications can set “session” state in each connection. Examples of sessionstate areNLS globalization settings fromALTERSESSION statements. Pooled connections will retain their session state afterthey have been released back to the pool. However, because pools can grow orconnections in the pool can be recreated, there is no guarantee a subsequentacquire() call will return a database connection thathas any particular state.

Thecreate_pool() parametersession_callback enablesefficient setting of session state so that connections have a known sessionstate, without requiring that state to be explicitly set after everyacquire() call. The callback is internally invokedwhenacquire() is called and runs first.

The session callback can be a Python function or a PL/SQL procedure.

Connections can also be tagged when they are released back to the pool. Thetag is a user-defined string that represents the session state of theconnection. When acquiring connections, a particular tag can be requested. Ifa connection with that tag is available, it will be returned. If not, thenanother session will be returned. By comparing the actual and requested tags,applications can determine what exact state a session has, and make anynecessary changes.

Connection tagging and PL/SQL callbacks are only available in python-oracledbThick mode. Python callbacks can be used in python-oracledb Thin and Thickmodes.

There are three common scenarios forsession_callback:

  • When all connections in the pool should have the same state, use aPython callback without tagging.

  • When connections in the pool require different state for different users, usea Python callback with tagging.

  • WithDatabase Resident Connection Pooling (DRCP), use a PL/SQL callback with tagging.

4.8.6.1.Python Callback

If thesession_callback parameter is a Python procedure, it will be calledwheneveracquire() will return a newly created databaseconnection that has not been used before. It is also called when connectiontagging is being used and the requested tag is not identical to the tag in theconnection returned by the pool.

An example is:

# Set the NLS_DATE_FORMAT for a sessiondefinit_session(connection,requested_tag):withconnection.cursor()ascursor:cursor.execute("alter session set nls_date_format = 'YYYY-MM-DD HH24:MI'")# Create the pool with session callback definedpool=oracledb.create_pool(user="hr",password=userpwd,dsn="localhost/orclpdb",session_callback=init_session)# Acquire a connection from the pool (will always have the new date format)connection=pool.acquire()

If needed, theinit_session() procedure is called internally beforeacquire() returns. It will not be called whenpreviously used connections are returned from the pool. This means that theALTER SESSION does not need to be executed after everyacquire() call. This improves performance andscalability.

In this example tagging was not being used, so therequested_tag parameteris ignored.

Note that if you need to execute multiple SQL statements in the callback, use ananonymous PL/SQL block to saveround-trips of repeatedexecute() calls. With ALTER SESSION, pass multiple settings in the onestatement:

cursor.execute("""        begin            execute immediate                    'alter session set nls_date_format = ''YYYY-MM-DD''                                       nls_language = AMERICAN';            -- other SQL statements could be put here        end;""")

4.8.6.2.Connection Tagging

Connection tagging is used when connections in a pool should have differingsession states. In order to retrieve a connection with a desired state, thetag attribute inacquire() needs to be set.

Note

Connection tagging is only supported in the python-oracledb Thick mode. SeeEnabling python-oracledb Thick mode .

When python-oracledb is using Oracle Client libraries 12.2 or later, thenpython-oracledb uses ‘multi-property tags’ and the tag string must be of theform of one or more “name=value” pairs separated by a semi-colon, for example"loc=uk;lang=cy".

When a connection is requested with a given tag, and a connection with that tagis not present in the pool, then a new connection, or an existing connectionwith cleaned session state, will be chosen by the pool and the session callbackprocedure will be invoked. The callback can then set desired session state andupdate the connection’s tag. However, if thematchanytag parameter ofacquire() is True, then any other tagged connection maybe chosen by the pool and the callback procedure should parse the actual andrequested tags to determine which bits of session state should be reset.

The example below demonstrates connection tagging:

definit_session(connection,requested_tag):ifrequested_tag=="NLS_DATE_FORMAT=SIMPLE":sql="ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'"elifrequested_tag=="NLS_DATE_FORMAT=FULL":sql="ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI'"cursor=connection.cursor()cursor.execute(sql)connection.tag=requested_tagpool=oracledb.create_pool(user="hr",password=userpwd,dsn="orclpdb",session_callback=init_session)# Two connections with different session state:connection1=pool.acquire(tag="NLS_DATE_FORMAT=SIMPLE")connection2=pool.acquire(tag="NLS_DATE_FORMAT=FULL")

Seesession_callback.py for an example.

4.8.6.3.PL/SQL Callback

Note

PL/SQL Callbacks are only supported in the python-oracledb Thick mode. SeeEnabling python-oracledb Thick mode.

When python-oracledb uses Oracle Client 12.2 or later, the session callback canalso be the name of a PL/SQL procedure. A PL/SQL callback will be initiatedonly when the tag currently associated with a connection does not match the tagthat is requested. A PL/SQL callback is most useful when usingDatabase Resident Connection Pooling (DRCP)because DRCP does not require around-trip to invoke aPL/SQL session callback procedure.

The PL/SQL session callback should accept two VARCHAR2 arguments:

PROCEDUREmyPlsqlCallback(requestedTagINVARCHAR2,actualTagINVARCHAR2);

The logic in this procedure can parse the actual tag in the session that hasbeen selected by the pool and compare it with the tag requested by theapplication. The procedure can then change any state required before theconnection is returned to the application fromacquire().

If thematchanytag attribute ofacquire() isTrue, then a connection with any state may be chosen by the pool.

Oracle ‘multi-property tags’ must be used. The tag string must be of the formof one or more “name=value” pairs separated by a semi-colon, for example"loc=uk;lang=cy".

In python-oracledb setsession_callback to the name of the PL/SQLprocedure. For example:

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb:pooled",session_callback="MyPlsqlCallback")connection=pool.acquire(tag="NLS_DATE_FORMAT=SIMPLE",# DRCP options, if you are using DRCPcclass='MYCLASS',purity=oracledb.PURITY_SELF)

Seesession_callback_plsql.py for an example.

4.8.7.Heterogeneous and Homogeneous Connection Pools

Homogeneous Pools

By default, connection pools are ‘homogeneous’, meaning that all connectionsuse the same database credentials. Both python-oracledb Thin andThick modes support homogeneous pools.

Heterogeneous Pools

The python-oracledb Thick mode additionally supports Heterogeneous pools,allowing different user names and passwords to be passed to eachacquire() call.

To create an heterogeneous pool, set thecreate_pool()parameterhomogeneous to False:

pool=oracledb.create_pool(dsn="dbhost.example.com/orclpdb",homogeneous=False)connection=pool.acquire(user="hr",password=userpwd)

4.8.8.Using the PoolParams Builder Class

ThePoolParams class allows you to define connection andpool parameters in a single place. Theoracledb.PoolParams() functionreturns aPoolParams object. This is a subclass of theConnectParams class (seeUsing the ConnectParams Builder Class) withadditional pool-specific attributes such as the maximum pool size. APoolParams object can be passed tooracledb.create_pool(). Forexample:

pp=oracledb.PoolParams(min=1,max=2,increment=1)pool=oracledb.create_pool(user="hr",password=userpw,dsn="dbhost.example.com/orclpdb",params=pp)

The use of the PoolParams class is optional because you can pass the sameparameters directly tocreate_pool(). For example, the codeabove is equivalent to:

pool=oracledb.create_pool(user="hr",password=userpw,dsn="dbhost.example.com/orclpdb",min=1,max=2,increment=1)

Some values such as the database host name can be specified asoracledb.create_pool() parameters, as part of thedsn connectionstring, and in theparams object. A final connection string is internallyconstructed from anydsn, individual parameters, andparams objectvalues. The precedence is that values in adsn parameter override valuespassed as individual parameters, which themselves override values set in theparams object.

Most PoolParams arguments are gettable as properties. They may be setindividually using theset() method:

pp=oracledb.PoolParams()pp.set(min=5)print(pp.min)# 5

4.9.Database Resident Connection Pooling (DRCP)

Database Resident Connection Pooling (DRCP) enables database resourcesharing for applications which use a large number of connections that run inmultiple client processes or run on multiple middle-tier application servers.By default, each connection from Python will use one database server process.DRCP allows pooling of these server processes. This reduces the amount ofmemory required on the database host. A DRCP pool can be shared by multipleapplications.

DRCP is useful for applications which share the same database credentials, havesimilar session settings (for example date format settings or PL/SQL packagestate), and where the application gets a database connection, works on it for arelatively short duration, and then releases it.

For efficiency, it is recommended that DRCP connections should be used inconjunction with python-oracledb’s localconnection pool.Using DRCP withstandalone connections is not asefficient but does allow the database to reuse database server processes whichcan provide a performance benefit for applications that cannot use a localconnection pool. In this scenario, make sure to configure enough DRCPauthentication servers to handle the connection load.

Although applications can choose whether or not to use DRCP pooled connectionsat runtime, care must be taken to configure the database appropriately for thenumber of expected connections, and also to stop inadvertent use of non-DRCPconnections leading to a database server resource shortage. Conversely, avoidusing DRCP connections for long-running operations.

For more information about DRCP, see the technical briefExtreme OracleDatabase Connection Scalability with Database Resident Connection Pooling(DRCP), the userdocumentationOracle Database Concepts Guide, and for DRCP ConfigurationseeOracle Database Administrator’s Guide.

Using DRCP with python-oracledb applications involves the following steps:

  1. Enabling DRCP in the database

  2. Configuring the application to use DRCP pooled servers

4.9.1.Enabling DRCP in Oracle Database

Oracle Database versions prior to 21c can have a single DRCP connection pool.From Oracle Database 21c, each pluggable database can optionally have its ownpool, or can use the container level pool. From Oracle Database 23ai, you cancreate multiple pools at the pluggable, or container, database level. Thismulti-pool feature is useful where different applications connect to the samedatabase, but there is a concern that one application’s use of the pool mayimpact other applications. If this is not the case, a single pool may allowbest resource sharing on the database host.

Note that DRCP is already enabled in Oracle Autonomous Database and poolmanagement is different to the steps below.

In the basic scenario, DRCP pools can be configured and administered by a DBAusing theDBMS_CONNECTION_POOL package:

EXECUTEDBMS_CONNECTION_POOL.CONFIGURE_POOL(pool_name=>'SYS_DEFAULT_CONNECTION_POOL',minsize=>4,maxsize=>40,incrsize=>2,session_cached_cursors=>20,inactivity_timeout=>300,max_think_time=>600,max_use_session=>500000,max_lifetime_session=>86400)

Alternatively, the methodDBMS_CONNECTION_POOL.ALTER_PARAM() canset a single parameter:

EXECUTEDBMS_CONNECTION_POOL.ALTER_PARAM(pool_name=>'SYS_DEFAULT_CONNECTION_POOL',param_name=>'MAX_THINK_TIME',param_value=>'1200')

Theinactivity_timeout setting terminates idle pooled servers, helpingoptimize database resources. To avoid pooled servers permanently being heldonto by a selfish Python script, themax_think_time parameter can be set.The parametersnum_cbrok andmaxconn_cbrok can be used to distributethe persistent connections from the clients across multiple brokers. This maybe needed in cases where the operating system per-process descriptor limit issmall. Some customers have found that having several connection brokersimproves performance. Themax_use_session andmax_lifetime_sessionparameters help protect against any unforeseen problems affecting serverprocesses. The default values will be suitable for most users. See theOracle DRCP documentation for details on parameters.

In general, if pool parameters are changed, then the pool should be restarted.Otherwise, server processes will continue to use old settings.

There is aDBMS_CONNECTION_POOL.RESTORE_DEFAULTS() procedure toreset all values.

When DRCP is used withOracle RAC, each databaseinstance has its own connection broker and pool of servers. Each pool has theidentical configuration. For example, all pools start withminsize serverprocesses. A single DBMS_CONNECTION_POOL command will alter the pool of eachinstance at the same time. The pool needs to be started before connectionrequests begin. The command below does this by bringing up the broker, whichregisters itself with the database listener:

EXECUTEDBMS_CONNECTION_POOL.START_POOL()

Once enabled this way, the pool automatically restarts when the databaseinstance restarts, unless explicitly stopped with theDBMS_CONNECTION_POOL.STOP_POOL() command:

EXECUTEDBMS_CONNECTION_POOL.STOP_POOL()

Oracle Database 23ai allows aDRAINTIME argument to be passed toSTOP_POOL(), indicating that the pool will only be closed after thespecified time. This allows in-progress application work to continue. Adraintime value of 0 can be used to immediately close the pool. See thedatabase documentation onDBMS_CONNECTION_POOL.STOP_POOL().

In older database versions, the pool cannot be stopped while connections areopen.

4.9.2.Coding Applications to use DRCP

To use DRCP, application connection establishment must request a DRCP pooledserver and should specify a user-chosen connection class name. A ‘purity’ ofthe connection session state can optionally be specified. See the OracleDatabase documentation onbenefiting from scalability for more informationon purity and connection classes.

The best practice is to use DRCP in conjunction with a local driverconnection pool created withoracledb.create_pool() ororacledb.create_pool_async(). Thepython-oracledb connection pool size does not need to match the DRCP pool size.The limit on overall execution parallelism is determined by the DRCP poolsize. Note that when using DRCP with a python-oracledb local connection pool inThick mode, the local connection poolmin value is ignored and the poolwill be created with zero connections.

Seedrcp_pool.pyfor a runnable example of DRCP.

Requesting Pooled Servers be Used

To enable connections to use DRCP pooled servers, you can:

  • Use a specific connection string inoracledb.create_pool() ororacledb.connect() to request a pooled server. For example with theEasy Connect syntax:

    pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb:pooled",min=2,max=5,increment=1,cclass="MYAPP")
  • Alternatively, add(SERVER=POOLED) to theConnect Descriptor such as used in an Oracle Network configuration filetnsnames.ora:

    customerpool=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dbhost.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=CUSTOMER)(SERVER=POOLED)))
  • Another way to use a DRCP pooled server is to set theserver_typeparameter during standalone connection creation or python-oracledbconnection pool creation. For example:

    pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",min=2,max=5,increment=1,server_type="pooled",cclass="MYAPP")

DRCP Connection Classes

The best practice is to specify acclass class name when creating apython-oracledb connection pool. This user-chosen name provides somepartitioning of DRCP session memory so reuse is limited to similarapplications. It provides maximum pool sharing if multiple applicationprocesses are started and use the same class name. A class name also allowsbetter DRCP usage tracking in the database. In the database monitoring views,the class name shown will be the value specified in the application prefixedwith the user name.

Ifcclass was not specified during pool creation, then the python-oracledbThin mode generates a unique connection class with the prefix “DPY” while theThick mode generates a unique connection class with the prefix “OCI”.

To create a connection pool requesting DRCP pooled servers be used, andspecifying a class name, you can call:

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb:pooled",min=2,max=5,increment=1,cclass="MYAPP")

Ifcclass is not set, then the pooled server sessions will not be reusedoptimally, and theDRCP statistic views may recordlarge values for NUM_MISSES.

DRCP Connection Purity

DRCP allows the connection session memory to be reused or cleaned each time aconnection is acquired from the pool. The pool or connection creationpurity parameter can be one ofPURITY_NEW,PURITY_SELF, orPURITY_DEFAULT. The valuePURITY_SELF allows reuse of both the pooledserver process and session memory, giving maximum benefit from DRCP. Bydefault, python-oracledb pooled connections usePURITY_SELF and standaloneconnections usePURITY_NEW.

To limit session sharing, you can explicitly require that new session memory beallocated each timeacquire() is called. Do this whencreating a driver connection pool by specifying thepurity asPURITY_NEW:

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb:pooled",min=2,max=5,increment=1,cclass="MYAPP",purity=oracledb.PURITY_NEW)

The overheads can impact ultimate scalability.

DRCP Pool Names

From Oracle Database 23ai, multiple DRCP pools can be created by setting a poolname at DRCP pool creation time. Applications can then specifiy which DRCP poolto use by passing thepool_name parameter during connection, or connectionpool, creation, for example:

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb:pooled",min=2,max=5,increment=1,cclass="MYAPP",pool_name="MYPOOL")

When specifying a pool name, you should still set a connection class name toallow efficient use of the pool’s resources.

Acquiring a DRCP Connection

Once DRCP has been enabled and the driver connection pool has been created withthe appropriate connection string, then your application can get a connectionthat uses DRCP by calling:

connection=pool.acquire()

Connection class names can also be passed toacquire()if you want to use a connection with a different class:

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb:pooled",min=2,max=5,increment=1,cclass="MYAPP")connection=mypool.acquire(cclass="OTHERAPP")

If a pooled server of a requested class is not available, a server with newsession state is used. If the DRCP pool cannot grow, a server with a differentclass may be used and its session state cleared.

Closing Connections when using DRCP

Similar to using a python-oracledb connection pool, Python scripts wherepython-oracledb connections do not go out of scope quickly (which releasesthem), or do not currently useConnection.close() orConnectionPool.release() should be examined to see if the connectionscan be closed earlier. This allows maximum reuse of DRCP pooled servers byother users:

pool=oracledb.create_pool(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb:pooled",min=2,max=5,increment=1,cclass="MYAPP")# Do some database operationsconnection=mypool.acquire()...connection.close()# <- Add this to release the DRCP pooled server# Do lots of non-database work...# Do some more database operationsconnection=mypool.acquire()# <- And get a new pooled server only when needed...connection.close()

4.9.3.Setting DRCP Parameters in Connection Strings

Setting the DRCP connection class, purity, and pool name as function parametersin the application is preferred, but sometimes it is not possible to modify anexisting code base. For these applications, you can specify the values alongwith the pooled server option in the connection string.

You can specify the class and purity options in connection strings when usingOracle Database 21c, or later. You can specify the pool name when using OracleDatabase 23ai, or later.

For example with theEasy Connect syntax:

dbhost.example.com/orclpdb:pooled?pool_connection_class=MYAPP&pool_purity=self&pool_name=MYPOOL

Or by using aTNS Alias in atnsnames.ora file:

customerpool=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dbhost.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orclpdb)(SERVER=POOLED)(POOL_CONNECTION_CLASS=MYAPP)(POOL_PURITY=SELF)(POOL_NAME=MYPOOL)))

Explicitly specifying the purity asSELF in a connection string may causesome unusable connections in a python-oracledb Thick mode connection pool tonot be terminated, potentially eventually rendering all connections in the poolto be unusable. If you cannot programmatically set the class name and purity,or cannot use python-oracledb Thin mode, then avoid explicitly setting thepurity as a connection string parameter when using a local python-oracledbThick mode connection pool.

4.9.4.Monitoring DRCP

Data dictionary views are available to monitor the performance of DRCP.Database administrators can check statistics such as the number of busy andfree servers, and the number of hits and misses in the pool against the totalnumber of requests from clients. The views include:

  • DBA_CPOOL_INFO

  • V$PROCESS

  • V$SESSION

  • V$CPOOL_STATS

  • V$CPOOL_CC_STATS

  • V$CPOOL_CONN_INFO

DBA_CPOOL_INFO View

DBA_CPOOL_INFO displays configuration information about the DRCP pool. Thecolumns are equivalent to thedbms_connection_pool.configure_pool()settings described in the table of DRCP configuration options, with theaddition of a STATUS column. The status isACTIVE if the pool has beenstarted andINACTIVE otherwise. Note that the pool name column is calledCONNECTION_POOL. This example checks whether the pool has been started andfinds the maximum number of pooled servers:

SQL>SELECTconnection_pool,status,maxsizeFROMdba_cpool_info;CONNECTION_POOLSTATUSMAXSIZE------------------------------------------------SYS_DEFAULT_CONNECTION_POOLACTIVE40

V$PROCESS and V$SESSION Views

The V$SESSION view shows information about the currently active DRCPsessions. It can also be joined with V$PROCESS throughV$SESSION.PADDR=V$PROCESS.ADDR to correlate the views.

V$CPOOL_STATS View

The V$CPOOL_STATS view displays information about the DRCP statistics foran instance. The V$CPOOL_STATS view can be used to assess how efficient thepool settings are. This example query shows an application using the pooleffectively. The low number of misses indicates that servers and sessions werereused. The wait count shows just over 1% of requests had to wait for a pooledserver to become available:

NUM_REQUESTSNUM_HITSNUM_MISSESNUM_WAITS------------------------------------------1003199990401055

Ifcclass was set (allowing pooled servers and sessions to bereused), then NUM_MISSES will be low. If the pool maxsize is too small forthe connection load, then NUM_WAITS will be high.

V$CPOOL_CC_STATS View

The view V$CPOOL_CC_STATS displays information about the connection classlevel statistics for the pool per instance:

SQL> select cclass_name, num_requests, num_hits, num_misses     from v$cpool_cc_stats;CCLASS_NAME                      NUM_REQUESTS   NUM_HITS NUM_MISSES-------------------------------- ------------ ---------- ----------HR.MYCLASS                             100031      99993         38

The class name columns shows the database user name appended with theconnection class name.

V$CPOOL_CONN_INFO View

The V$POOL_CONN_INFO view gives insight into client processes that areconnected to the connection broker, making it easier to monitor and traceapplications that are currently using pooled servers or are idle. This view wasintroduced in Oracle 11gR2.

You can monitor the view V$CPOOL_CONN_INFO to, for example, identifymisconfigured machines that do not have the connection class set correctly.This view maps the machine name to the class name. In python-oracledb Thickmode, the class name will be default to one like shown below:

SQL> select cclass_name, machine from v$cpool_conn_info;CCLASS_NAME                             MACHINE--------------------------------------- ------------CJ.OCI:SP:wshbIFDtb7rgQwMyuYvodA        cjlinux

In this example, you would examine applications oncjlinux and make themsetcclass.

When connecting to Oracle Autonomous Database on Shared Infrastructure (ADB-S),the V$CPOOL_CONN_INFO view can be used to track the number of connectionhits and misses to show the pool efficiency.

4.10.Implicit Connection Pooling

Implicit connection pooling is useful for applications that cause excess database serverload due to the number ofstandalone connectionsopened. When these applications cannot be rewritten to usepython-oracledb connection pooling, then implicitconnection pooling may be an option to reduce the load on the database system.

Implicit connection pooling allows application connections to share pooledservers inDRCP or Oracle Connection Manager in Traffic DirectorMode’s (CMAN-TDM)Proxy Resident Connection Pooling (PRCP). Applications do not need to be modified. Thefeature is enabled by adding apool_boundary parameter to the application’sconnection string. Applications do not need to explicitlyacquire, or release, connections to be able use a DRCP or PRCP pool.

Implicit connection pooling is available in python-oracledb Thin andThick modes. It requires Oracle Database23ai. Python-oracledb Thick mode additionally requires Oracle Client 23ailibraries.

With implicit connection pooling, connections are internally acquired from theDRCP or PRCP pool when they are actually used by the application to do databasework. They are internally released back to pool when not in use. This mayoccur between the application’s explicitoracledb.connect() call andConnection.close() (or the application’s equivalent connection releaseat end-of-scope). The internal connection release can be controlled by thevalue of thepool_boundary connection string parameter, which can beeither:

  • statement: If this boundary is specified, then the connection is releasedback to the DRCP or PRCP connection pool when the connection is implicitlystateless. A connection is implicitly stateless when there are no activecursors in the connection (that is, all the rows of the cursors have beeninternally fetched), no active transactions, no temporary tables, and notemporary LOBs.

  • transaction: If this boundary is specified, then the connection is releasedback to the DRCP or PRCP connection pool when either one of the methodsConnection.commit() orConnection.rollback() arecalled. It is recommended to not set theConnection.autocommitattribute totrue when using implicit connection pooling. If you do setthis attribute, then you will be unable to:

    • Fetch any data that requires multipleround-trips tothe database

    • Run queries that fetchLOB andJSONdata

Inline with DRCP and PRCP best practices regarding session sharing acrossdiffering applications, you should add a connection stringpool_connection_class parameter, using the same value for all applicationsthat are alike.

The DRCP and PRCP “purity” used by Implicit Connection Pooling defaults toSELF, which allows reuse of the server process session memory for bestperformance. Adding the connection string parameterpool_purity=new willchange this and cause each use of a connection to recreate the session memory.

Configuring Implicit Connection Pooling

To use implicit connection pooling in python-oracledb with DRCP:

  1. Enable DRCP in the database. For example in SQL*Plus:

    SQL>EXECUTEDBMS_CONNECTION_POOL.START_POOL()
  2. Specify to use a pooled server in:

    • Thedsn parameter oforacledb.connect() ororacledb.create_pool(). For example with theEasy Connect syntax:

      cs="dbhost.example.com/orclpdb:pooled"pool=oracledb.create_pool(user="hr",password=userpwd,dsn=cs,min=2,max=5,increment=1,cclass="MYAPP")
    • Or in theConnect Descriptor used in an OracleNetwork configuration file such astnsnames.ora byadding(SERVER=POOLED). For example:

      customerpool=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dbhost.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=CUSTOMER)(SERVER=POOLED)))
    • Or in theserver_type parameter duringstandaloneconnectioncreationorconnectionpoolcreation. For example:

      pool=oracledb.create_pool(user="hr",password=userpwd,host="dbhost.example.com",service_name="orclpdb",min=2,max=5,increment=1,server_type="pooled",cclass="MYAPP")
  3. Set the pool boundary to eitherstatement ortransaction in:

    • TheEasy Connect string. For example, to use thestatement boundary:

      dsn="localhost:1521/orclpdb:pooled?pool_boundary=statement"
    • Or theCONNECT_DATA section of theConnect Descriptor. For example, to use thetransaction boundary:

      tnsalias=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=mymachine.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)(SERVER=POOLED)(POOL_BOUNDARY=TRANSACTION)))
    • Or thepool_boundary parameter inoracledb.connect() ororacledb.create_pool()

    Note

    Implicit connection pooling is not enabled if the application sets thepool_boundary attribute totransaction orstatement but doesnot specify to use a pooled server.

  4. Set the connection class in:

    • TheEasy Connect string. For example, to use a classname ‘myapp’:

      dsn="localhost:1521/orclpdb:pooled?pool_boundary=statement&pool_connection_class=myapp"
    • Or theCONNECT_DATA section of theConnect Descriptor. For example, to use a class name ‘myapp’:

      tnsalias=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=mymachine.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)(SERVER=POOLED)(POOL_BOUNDARY=TRANSACTION)(POOL_CONNECTION_CLASS=myapp)))

    Use the same connection class name for application processes of the sametype where you want session memory to be reused for connections.

    The pool purity can also optionally be changed by addingPOOL_PURITY=NEWto the Easy Connect string or Connect Descriptor.

Similar steps can be used with PRCP. For general information on PRCP, see thetechnical briefCMAN-TDM — An Oracle Database connection proxy for scalableand highly available applications.

Implicit Pooling Notes

You should thoroughly test your application when using implicit connectionpooling to ensure that the internal reuse of database servers does not causeany problems. For example, any session state such as the connectionsession idand serial number will vary throughout the lifetime of theapplication connection because different servers may be used at differenttimes. Another example is when using a statement boundary oftransaction. Inthis scenario, any commit can invalidate open cursors.

It is recommended to use python-oracledb’s localConnection Pooling wherepossible instead of implicit connection pooling. This gives multi-userapplications more control over pooled server reuse.

4.11.Connecting Using Proxy Authentication

Proxy authentication allows a user (the “session user”) to connect to OracleDatabase using the credentials of a “proxy user”. Statements will run as thesession user. Proxy authentication is generally used in three-tier applicationswhere one user owns the schema while multiple end-users access the data. Formore information about proxy authentication, see theOracle documentation.

An alternative to using proxy users is to setConnection.client_identifier after connecting and use its value instatements and in the database, for example formonitoring.

The following proxy examples use these schemas. Themysessionuser schema isgranted access to use the password ofmyproxyuser:

CREATEUSERmyproxyuserIDENTIFIEDBYmyproxyuserpw;GRANTCREATESESSIONTOmyproxyuser;CREATEUSERmysessionuserIDENTIFIEDBYitdoesntmatter;GRANTCREATESESSIONTOmysessionuser;ALTERUSERmysessionuserGRANTCONNECTTHROUGHmyproxyuser;

After connecting to the database, the following query can be used to show thesession and proxy users:

SELECTSYS_CONTEXT('USERENV','PROXY_USER'),SYS_CONTEXT('USERENV','SESSION_USER')FROMDUAL;

Standalone connection examples:

# Basic Authentication without a proxyconnection=oracledb.connect(user="myproxyuser",password="myproxyuserpw",dsn="dbhost.example.com/orclpdb")# PROXY_USER:   None# SESSION_USER: MYPROXYUSER# Basic Authentication with a proxyconnection=oracledb.connect(user="myproxyuser[mysessionuser]",password="myproxyuserpw",dsn="dbhost.example.com/orclpdb")# PROXY_USER:   MYPROXYUSER# SESSION_USER: MYSESSIONUSER

Pooled connection examples:

# Basic Authentication without a proxypool=oracledb.create_pool(user="myproxyuser",password="myproxyuserpw",dsn="dbhost.example.com/orclpdb")connection=pool.acquire()# PROXY_USER:   None# SESSION_USER: MYPROXYUSER# Basic Authentication with proxypool=oracledb.create_pool(user="myproxyuser[mysessionuser]",password="myproxyuserpw",dsn="dbhost.example.com/orclpdb",homogeneous=False)connection=pool.acquire()# PROXY_USER:   MYPROXYUSER# SESSION_USER: MYSESSIONUSER

Note the use of aheterogeneous pool in the exampleabove. This is required in this scenario.

4.12.Connecting Using External Authentication

Instead of storing the database username and password in Python scripts orenvironment variables, database access can be authenticated by an outsidesystem. External Authentication allows applications to validate user accesswith an external password store (such as anOracle Wallet), with theoperating system, or with an external authenticationservice.

Note

Connecting to Oracle Database using external authentication is onlysupported in the python-oracledb Thick mode. SeeEnabling python-oracledb Thick mode.

4.12.1.Using an Oracle Wallet for External Authentication

The following steps give an overview of using an Oracle Wallet. Wallets shouldbe kept securely. Wallets can be managed withOracle Wallet Manager.

In this example the wallet is created for themyuser schema in the directory/home/oracle/wallet_dir. Themkstore command is available from a fullOracle client or Oracle Database installation. If you have been given wallet byyour DBA, skip to step 3.

  1. First create a new wallet as theoracle user:

    mkstore-wrl"/home/oracle/wallet_dir"-create

    This will prompt for a new password for the wallet.

  2. Create the entry for the database user name and password that are currentlyhardcoded in your Python scripts. Use either of the methods shown below.They will prompt for the wallet password that was set in the first step.

    Method 1 - Using an Easy Connect string:

    mkstore-wrl"/home/oracle/wallet_dir"-createCredentialdbhost.example.com/orclpdbmyusermyuserpw

    Method 2 - Using a connect name identifier:

    mkstore-wrl"/home/oracle/wallet_dir"-createCredentialmynetaliasmyusermyuserpw

    The alias keymynetalias immediately following the-createCredential option will be the connect name to be used in Pythonscripts. If your application connects with multiple different databaseusers, you could create a wallet entry with different connect names foreach.

    You can see the newly created credential with:

    mkstore-wrl"/home/oracle/wallet_dir"-listCredential
  3. Skip this step if the wallet was created using an Easy Connect String.Otherwise, add an entry intnsnames.ora for theconnect name as follows:

    mynetalias=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dbhost.example.com)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orclpdb)))

    The file uses the description for your existing database and sets theconnect name alias tomynetalias, which is the identifier used whenadding the wallet entry.

  4. Add the following wallet location entry in thesqlnet.ora file, using theDIRECTORY you created the wallet in:

    WALLET_LOCATION=(SOURCE=(METHOD=FILE)(METHOD_DATA=(DIRECTORY=/home/oracle/wallet_dir)))SQLNET.WALLET_OVERRIDE=TRUE

    Examine the Oracle documentation for full settings and values.

  5. Ensure the configuration files are in a default location or TNS_ADMIN isset to the directory containing them. SeeOptional Oracle Net Configuration Files.

With an Oracle wallet configured, and readable by you, your scriptscan connect to Oracle Database with:

  • Standalone connections by setting theexternalauth parameter toTrueinoracledb.connect():

    connection=oracledb.connect(externalauth=True,dsn="mynetalias")
  • Or pooled connections by setting theexternalauth parameter toTrueinoracledb.create_pool(). Additionally in python-oracledb Thickmode, you must set thehomogeneous parameter toFalse as shown belowsince heterogeneous pools can only be used with external authentication:

    pool=oracledb.create_pool(externalauth=True,homogeneous=False,dsn="mynetalias")pool.acquire()

Thedsn used inoracledb.connect() andoracledb.create_pool() must match the one used in the wallet.

After connecting, the query:

SELECTSYS_CONTEXT('USERENV','SESSION_USER')FROMDUAL;

will show:

MYUSER

Note

Wallets are also used to configure Transport Layer Security (TLS) connections.If you are using a wallet like this, you may need a database username and passwordinoracledb.connect() andoracledb.create_pool() calls.

External Authentication and Proxy Authentication

The following examples show external wallet authentication combined withproxy authentication. These examples use the walletconfiguration from above, with the addition of a grant to another user:

ALTERUSERmysessionuserGRANTCONNECTTHROUGHmyuser;

After connection, you can check who the session user is with:

SELECTSYS_CONTEXT('USERENV','PROXY_USER'),SYS_CONTEXT('USERENV','SESSION_USER')FROMDUAL;

Standalone connection example:

# External Authentication with proxyconnection=oracledb.connect(user="[mysessionuser]",dsn="mynetalias")# PROXY_USER:   MYUSER# SESSION_USER: MYSESSIONUSER

You can also set theexternalauth parameter toTrue in standaloneconnections:

# External Authentication with proxy when externalauth is set to Trueconnection=oracledb.connect(user="[mysessionuser]",dsn="mynetalias",externalauth=True)# PROXY_USER:   MYUSER# SESSION_USER: MYSESSIONUSER

A connection pool example is:

# External Authentication with proxypool=oracledb.create_pool(externalauth=True,homogeneous=False,dsn="mynetalias")pool.acquire(user="[mysessionuser]")# PROXY_USER:   MYUSER# SESSION_USER: MYSESSIONUSER

The following usage is not supported:

pool=oracledb.create_pool(user="[mysessionuser]",externalauth=True,homogeneous=False,dsn="mynetalias")pool.acquire()

4.12.2.Operating System Authentication

WithOperating System authentication, Oracle allowsuser authentication to be performed by the operating system. The followingsteps give an overview of how to implement OS Authentication on Linux.

  1. Log in to your computer. The commands used in these steps assume theoperating system user name is “oracle”.

  2. Log in to SQL*Plus as the SYSTEM user and verify the value for theOS_AUTHENT_PREFIX parameter:

    SQL> SHOW PARAMETER os_authent_prefixNAME                                 TYPE        VALUE------------------------------------ ----------- ------------------------------os_authent_prefix                    string      ops$
  3. Create an Oracle database user using theos_authent_prefix determined instep 2, and the operating system user name:

CREATEUSERops$oracleIDENTIFIEDEXTERNALLY;GRANTCONNECT,RESOURCETOops$oracle;

In Python, connect using the following code:

connection=oracledb.connect(dsn="mynetalias")

Your session user will beOPS$ORACLE.

If your database is not on the same computer as Python, you can perform testingby setting the database configuration parameterremote_os_authent=true.Beware of security concerns because this is insecure.

SeeOracle Database Security Guide for more information aboutOperating System Authentication.

4.13.Token-Based Authentication

Token-Based Authentication allows users to connect to a database by using anencrypted authentication token without having to enter a database username andpassword. The authentication token must be valid and not expired for theconnection to be successful. Users already connected will be able to continuework after their token has expired but they will not be able to reconnectwithout getting a new token.

The two authentication methods supported by python-oracledb areOpen Authorization (OAuth 2.0) andOracleCloud Infrastructure (OCI) Identity and Access Management (IAM).These authentication methods can use Cloud Native Authentication with thesupport of the Azure SDK or OCI SDK to generate access tokens and connect toOracle Database. Alternatively, these methods can use a Python script thatcontains a class to generate access tokens to connect to Oracle Database.

4.13.1.Connecting Using OAuth 2.0 Token-Based Authentication

Oracle Cloud Infrastructure (OCI) users can be centrally managed in a MicrosoftEntra ID (formerly Microsoft Azure Active Directory) service. OpenAuthorization (OAuth 2.0) token-based authentication allows users toauthenticate to Oracle Database using Entra ID OAuth2 tokens. Ensure that youhave a Microsoft Azure account and your Oracle Database is registered withMicrosoft Entra ID. SeeConfiguring the Oracle Database for Microsoft EntraID Integration for more information. Both Thinand Thick modes of the python-oracledb driver support OAuth 2.0 token-basedauthentication.

When using python-oracledb in Thick mode, Oracle Client libraries 19.15 (orlater), or 21.7 (or later) are needed.

Standalone connections and pooled connections can be created in python-oracledbThick and Thin modes using OAuth 2.0 token-based authentication. This can bedone or by using a class such as the exampleTokenHandlerOAuth Class or by using python-oracledb’sAzure Cloud NativeAuthentication Plugin (azure_tokens). Tokens can bespecified using the connection parameter introduced in python-oracledb 1.1.Users of earlier python-oracledb versions can alternatively useOAuth 2.0Token-Based Authentication Connection Strings.

4.13.1.1.OAuth2 Token Generation And Extraction

There are different ways to retrieve Entra ID OAuth2 tokens. You can usepython-oracledb’sazure_tokens plugin to generatetokens. Some of the other ways to retrieve OAuth2 tokens are detailed inExamples of Retrieving Entra ID OAuth2 Tokens. Youcan also retrieve Entra ID OAuth2 tokens by usingAzure Identity clientlibrary for Python.

Example of Generating an OAuth2 Token

An example of automating the process of generating and reading Entra ID OAuth2tokens is:

importjsonimportosimportoracledbimportrequestsclassTokenHandlerOAuth:def__init__(self,file_name="cached_token_file_name",api_key="api_key",client_id="client_id",client_secret="client_secret"):self.token=Noneself.file_name=file_nameself.url= \f"https://login.microsoftonline.com/{api_key}/oauth2/v2.0/token"self.scope= \f"https://oracledevelopment.onmicrosoft.com/{client_id}/.default"ifos.path.exists(file_name):withopen(file_name)asf:self.token=f.read().strip()self.api_key=api_keyself.client_id=client_idself.client_secret=client_secretdef__call__(self,refresh):ifself.tokenisNoneorrefresh:post_data=dict(client_id=self.client_id,grant_type="client_credentials",scope=self.scope,client_secret=self.client_secret)r=requests.post(url=self.url,data=post_data)result=json.loads(r.text)self.token=result["access_token"]withopen(self.file_name,"w")asf:f.write(self.token)returnself.token

The TokenHandlerOAuth class uses a callable to generate and read OAuth2tokens. When the callable in the TokenHandlerOAuth class is invoked for thefirst time to create a standalone connection or pool, therefresh parameterisFalse which allows the callable to return a cached token, if desired. Theexpiry date is then extracted from this token and compared with the currentdate. If the token has not expired, then it will be used directly. If the tokenhas expired, the callable is invoked the second time with therefreshparameter set toTrue.

The TokenHandlerOAuth class defined here is used in the examples shown inConnection Creation with OAuth2 Access Tokens.

Example of Using a Curl Command

See using acurl command for an alternative way to generate thetokens.

4.13.1.2.Connection Creation with OAuth2 Access Tokens

For OAuth 2.0 Token-Based Authentication using a class such as the sampleTokenHandlerOAuth class, theaccess_token connectionparameter must be specified. This parameter should be a string (or a callablethat returns a string) specifying an Entra ID OAuth2 token. In the examplesused below, theaccess_token parameter is set to a callable.

The examples used in the subsequent sections use theTokenHandlerOAuth class to generate OAuth2 tokens toconnect to Oracle Autonomous Database with mutual TLS (mTLS). SeeConnecting to Oracle Cloud Autonomous Databases.

Standalone Connections in Thin Mode Using OAuth2 Tokens

When using a class such as theTokenHandlerOAuth class togenerate OAuth2 tokens to connect to Oracle Autonomous Database in Thin mode,you need to explicitly set theaccess_token, and also any desiredconfig_dir,wallet_location, andwallet_password parameters ofconnect(). For example:

connection=oracledb.connect(access_token=TokenHandlerOAuth(),dsn=mydb_low,config_dir="path_to_unzipped_wallet",wallet_location="location_of_pem_file",wallet_password=wp)

Connection Pools in Thin Mode Using OAuth2 Tokens

When using a class such as theTokenHandlerOAuth class togenerate OAuth2 tokens to connect to Oracle Autonomous Database in Thin mode,you need to explicitly set theaccess_token parameter ofcreate_pool(), and also any desiredconfig_dir,wallet_location, andwallet_password parameters. Thehomogeneousparameter must beTrue (its default value). For example:

connection=oracledb.create_pool(access_token=TokenHandlerOAuth(),homogeneous=True,# must always be True for connection poolsdsn=mydb_low,config_dir="path_to_unzipped_wallet",wallet_location="location_of_pem_file",wallet_password=wpmin=1,max=5,increment=2)

Note that theaccess_token parameter should be set to a callable. This isuseful when the connection pool needs to expand and create new connections butthe current token has expired. In such a case, the callable should return astring specifying the new, valid Entra ID OAuth2 token.

Standalone Connections Thick Mode Using OAuth2 Tokens

When using a class such as theTokenHandlerOAuth classto generate OAuth2 tokens to connect to Oracle Autonomous Database in Thickmode, you need to explicitly set theaccess_token andexternalAuthparameters ofconnect(). For example:

connection=oracledb.connect(access_token=TokenHandlerOAuth(),externalauth=True,# must always be True in Thick modedsn=mydb_low)

Connection Pools in Thick Mode Using OAuth2 Tokens

When using a class such as theTokenHandlerOAuth class togenerate OAuth2 tokens to connect to Oracle Autonomous Database in Thick mode,you need to explicitly set theaccess_token andexternalauth parametersofcreate_pool(). Thehomogeneous parameter must beTrue(which is its default value). For example:

pool=oracledb.create_pool(access_token=TokenHandlerOAuth(),externalauth=True,# must always be True in Thick modehomogeneous=True,# must always be True for connection poolsdsn=mydb_low,min=1,max=5,increment=2)

Note that theaccess_token parameter should be set to a callable. This isuseful when the connection pool needs to expand and create new connections butthe current token has expired. In such a case, the callable should return astring specifying the new, valid Entra ID OAuth2 token.

4.13.1.3.OAuth 2.0 Token-Based Authentication Connection Strings

The connection string used by python-oracledb can specify the directory wherethe token file is located. This syntax is usable with older versions ofpython-oracledb. However, it is recommended to use connection parametersintroduced in python-oracledb 1.1 instead. SeeOAuth 2.0 Token-Based Authentication.

Note

OAuth 2.0 Token-Based Authentication Connection Strings is only supported inthe python-oracledb Thick mode. SeeEnabling python-oracledb Thick mode.

There are different ways to retrieve Entra ID OAuth2 tokens. Some of the ways toretrieve OAuth2 tokens are detailed inExamples of Retrieving Entra ID OAuth2Tokens. You can also retrieve Entra ID OAuth2tokens by usingAzure Identity client library for Python.

Example of Using a Curl Command

Here, as an example, we are using Curl with a Resource OwnerPassword Credential (ROPC) Flow, that is, acurl command is used againstthe Entra ID API to get the Entra ID OAuth2 token:

curl-XPOST-H'Content-Type: application/x-www-form-urlencoded'https://login.microsoftonline.com/your_tenant_id/oauth2/v2.0/token-d'client_id=your_client_id'-d'grant_type=client_credentials'-d'scope=https://oracledevelopment.onmicrosoft.com/your_client_id/.default'-d'client_secret=your_client_secret'

This command generates a JSON response with token type, expiration, and accesstoken values. The JSON response needs to be parsed so that only the accesstoken is written and stored in a file. You can save the value ofaccess_token generated to a file and setTOKEN_LOCATION to the locationof token file. SeeTokenHandlerOAuth class for an exampleof generating tokens.

The Oracle Net parametersTOKEN_AUTH andTOKEN_LOCATION must be set whenyou are using the connection string syntax. Also, thePROTOCOLparameter must betcps andSSL_SERVER_DN_MATCH should beON.

You can setTOKEN_AUTH=OAUTH. There is no default location set in thiscase, so you must setTOKEN_LOCATION to either of the following:

  • A directory, in which case, you must create a file namedtoken whichcontains the token value

  • A fully qualified file name, in which case, you must specify the entire pathof the file which contains the token value

You can either setTOKEN_AUTH andTOKEN_LOCATION in asqlnet.ora file or alternatively, you can specify it inside aConnectDescriptor, for example when using atnsnames.ora file:

db_alias=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=xxx.oraclecloud.com))(CONNECT_DATA=(SERVICE_NAME=xxx.adb.oraclecloud.com))(SECURITY=(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com,\             O=Oracle Corporation,L=Redwood City,ST=California,C=US")(TOKEN_AUTH=OAUTH)(TOKEN_LOCATION="/home/user1/mytokens/oauthtoken")))

TheTOKEN_AUTH andTOKEN_LOCATION values in a connection string takeprecedence over thesqlnet.ora settings.

Standalone connection example:

connection=oracledb.connect(dsn=db_alias,externalauth=True)

Connection pool example:

pool=oracledb.create_pool(dsn=db_alias,externalauth=True,homogeneous=False,min=1,max=2,increment=1)connection=pool.acquire()

4.13.1.4.Azure Cloud Native Authentication with the azure_tokens Plugin

With Cloud Native Authentication, python-oracledb’sazure_tokens plugin can automatically generate and refreshOAuth2 tokens when required with the support of theMicrosoft AuthenticationLibrary (MSAL).

Theazure_tokens plugin can be importedlike:

importoracledb.plugins.azure_tokens

The plugin has a Python package dependency which needs to be installedseparately before the plugin can be used, seeInstall Modules for the Azure Cloud Native Authentication Plugin.

Theazure_tokens plugin defines and registers aparameter hook function which uses the connection parameterextra_auth_params passed tooracledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async(). Using this parameter’s values, the hookfunction sets theaccess_token parameter of aConnectParams object to a callable which generates an OAuth2 token. Python-oracledbthen acquires and uses a token to transparently complete connection or poolcreation calls.

For OAuth 2.0 Token-Based Authentication connection and pool creation, theextra_auth_params parameter should be a dictionary with keys as shown inthe following table.

Table 4.8Azure Cloud Native Authentication Configuration Keys

Key

Description

Required or Optional

auth_type

The authentication type.

This must be the string “AzureServicePrincipal”. This type makes the plugin acquire Azure service principal access tokens through a client credential flow.

Required

authority

This parameter must be set as a string in the URI format with the tenant ID, for examplehttps://{identityproviderinstance}/{tenantId}.

The tenantId is the directory tenant against which the application operates, in either GUID or domain-name format.

Required

client_id

The application ID that is assigned to your application.

This information can be found in the portal where the application was registered.

Required

client_credential

The client secret that was generated for your application in the application registration portal.

Required

scopes

This parameter represents the value of the scope for the request.

It should be the resource identifier (application ID URI) of the desired resource, with the suffix “.default”. For example,https://{uri}/clientID/.default.

Required

All keys and values other thanauth_type are used by theMicrosoftAuthentication Library (MSAL) API calls in the plugin. The pluginimplementation can be seen inplugins/azure_tokens.py.

For information on the Azure specific configuration parameters, seeMSAL.

The examples in the subsequent sections use theazure_tokens plugin to generate OAuth2 tokens to connect toOracle Autonomous Database with mutual TLS (mTLS). SeeConnecting to Oracle Cloud Autonomous Databases.

Standalone Connections in Thin Mode Using OAuth2 Tokens

When using theazure_tokens plugin togenerate OAuth2 tokens to connect to Oracle Autonomous Database in Thin mode,you need to explicitly set theextra_auth_params parameter, and also anyrequiredconfig_dir,wallet_location, andwallet_passwordparameters ofconnect(). For example:

importoracledb.plugins.azure_tokenstoken_based_auth={"auth_type":"AzureServicePrincipal",# Azure specific configuration"authority":<authority>,# parameters to be set when using"client_id":<client_id>,# the azure_tokens plugin"client_credential":<client_credential>,"scopes":<scopes>}connection=oracledb.connect(dsn=mydb_low,config_dir="path_to_unzipped_wallet",wallet_location="location_of_pem_file",wallet_password=wp,extra_auth_params=token_based_auth)

Connection Pools in Thin Mode Using OAuth2 Tokens

When using theazure_tokens plugin togenerate OAuth2 tokens to connect to Oracle Autonomous Database in Thin mode,you need to explicitly set theextra_auth_params parameter ofcreate_pool(), and also any desiredconfig_dir,wallet_location, andwallet_password parameters. Thehomogeneousparameter must beTrue (its default value). For example:

importoracledb.plugins.azure_tokenstoken_based_auth={"auth_type":"AzureServicePrincipal",# Azure specific configuration"authority":<authority>,# parameters to be set when using"client_id":<client_id>,# the azure_tokens plugin"client_credential":<client_credential>,"scopes":<scopes>}connection=oracledb.create_pool(dsn=mydb_low,config_dir="path_to_unzipped_wallet",homogeneous=true,# must always be True for connection poolswallet_location="location_of_pem_file",wallet_password=wp,extra_auth_params=token_based_auth)

Standalone Connections Thick Mode Using OAuth2 Tokens

When using theazure_tokens plugin togenerate OAuth2 tokens to connect to Oracle Autonomous Database in Thick mode,you need to explicitly set theextra_auth_params andexternalauthparameters ofconnect(). For example:

importoracledb.plugins.azure_tokenstoken_based_auth={"auth_type":"AzureServicePrincipal",# Azure specific configuration"authority":<authority>,# parameters to be set when using"client_id":<client_id>,# the azure_tokens plugin"client_credential":<client_credential>,"scopes":<scopes>}connection=oracledb.connect(externalauth=True,# must always be True in Thick modedsn=mydb_low,extra_auth_params=token_based_auth)

Connection Pools in Thick Mode Using OAuth2 Tokens

When using theazure_tokens plugin togenerate OAuth2 tokens to connect to Oracle Autonomous Database in Thick mode,you need to explicitly set theextra_auth_params andexternalauthparameters ofcreate_pool(). Thehomogeneous parameter mustbeTrue (its default value). For example:

importoracledb.plugins.azure_tokenstoken_based_auth={"auth_type":"AzureServicePrincipal",# Azure specific configuration"authority":<authority>,# parameters to be set when using"client_id":<client_id>,# the azure_tokens plugin"client_credential":<client_credential>,"scopes":<scopes>}connection=oracledb.create_pool(externalauth=True,# must always be True in Thick modehomogeneous=True,# must always be True for connection poolsdsn=mydb_low,extra_auth_params=token_based_auth)

4.13.2.Connecting Using OCI IAM Token-Based Authentication

Oracle Cloud Infrastructure (OCI) Identity and Access Management (IAM) providesits users with a centralized database authentication and authorization system.Using this authentication method, users can use the database access tokenissued by OCI IAM to authenticate to the Oracle Autonomous Database. Both Thinand Thick modes of the python-oracledb driver support OCI IAM token-basedauthentication.

When using python-oracledb in Thick mode, Oracle Client libraries 19.14 (orlater), or 21.5 (or later) are needed.

Standalone connections and pooled connections can be created in python-oracledbThick and Thin modes using OCI IAM token-based authentication. This can be doneby using a class like the sampleTokenHandlerIAM class orby using python-oracledb’sOCI Cloud Native Authentication Plugin(oci_tokens). Tokens can be specified using theconnection parameter introduced in python-oracledb 1.1. Users of earlierpython-oracledb versions can alternatively useOCI IAM Token-BasedAuthentication Connection Strings.

4.13.2.1.OCI IAM Token Generation and Extraction

Authentication tokens can be generated using python-oracledb’soci_tokens plugin.

Alternatively, authentication tokens can be generated through execution of anOracle Cloud Infrastructure command line interface (OCI-CLI) command

ociiamdb-tokenget

On Linux, a folder.oci/db-token will be created in your home directory.It will contain the token and private key files needed by python-oracledb.

Example of Generating an IAM Token

Here, as an example, we are using a Python script to automate the process ofgenerating and reading OCI IAM tokens.

importosimportoracledbclassTokenHandlerIAM:def__init__(self,dir_name="dir_name",command="oci iam db-token get"):self.dir_name=dir_nameself.command=commandself.token=Noneself.private_key=Nonedef__call__(self,refresh):ifrefresh:ifos.system(self.command)!=0:raiseException("token command failed!")ifself.tokenisNoneorrefresh:self.read_token_info()return(self.token,self.private_key)defread_token_info(self):token_file_name=os.path.join(self.dir_name,"token")pkey_file_name=os.path.join(self.dir_name,"oci_db_key.pem")withopen(token_file_name)asf:self.token=f.read().strip()withopen(pkey_file_name)asf:iforacledb.is_thin_mode():self.private_key=f.read().strip()else:lines=[sforsinf.read().strip().split("\n")ifsnotin('-----BEGIN PRIVATE KEY-----','-----END PRIVATE KEY-----')]self.private_key="".join(lines)

The TokenHandlerIAM class uses a callable to generate and read OCI IAM tokens.When the callable in the TokenHandlerIAM class is invoked for the first timeto create a standalone connection or pool, therefresh parameter isFalse which allows the callable to return a cached token, if desired. Theexpiry date is then extracted from this token and compared with the currentdate. If the token has not expired, then it will be used directly. If the tokenhas expired, the callable is invoked the second time with therefreshparameter set toTrue.

The TokenHandlerIAM class defined here is used in the examples shown inConnection Creation with OCI IAM Access Tokens.

4.13.2.2.Connection Creation with OCI IAM Access Tokens

For OCI IAM Token-Based Authentication with a class such as the sampleTokenHandlerIAM class, theaccess_token connectionparameter must be specified. This parameter should be a 2-tuple (or a callablethat returns a 2-tuple) containing the token and private key. In the examplesused below, theaccess_token parameter is set to a callable.

The examples used in the subsequent sections use theTokenHandlerIAM class to generate OCI IAM tokens to connectto Oracle Autonomous Database with mutual TLS (mTLS). SeeConnecting to Oracle Cloud Autonomous Databases.

Standalone Connections in Thin Mode Using OCI IAM Tokens

When using a class such as theTokenHandlerIAM class togenerate OCI IAM tokens to connect to Oracle Autonomous Database in Thin mode,you need to explicitly set theaccess_token parameter ofconnect(), and also any desiredconfig_dir,wallet_location, andwallet_password parameters. For example:

connection=oracledb.connect(access_token=TokenHandlerIAM(),dsn=mydb_low,config_dir="path_to_unzipped_wallet",wallet_location="location_of_pem_file",wallet_password=wp)

Connection Pools in Thin Mode Using OCI IAM Tokens

When using a class such asTokenHandlerIAM class togenerate OCI IAM tokens to connect to Oracle Autonomous Database in Thin mode,you need to explicitly set theaccess_token parameter ofcreate_pool(), and also any desiredconfig_dir,wallet_location, andwallet_password parameters. Thehomogeneousparameter must beTrue (its default value). For example:

connection=oracledb.create_pool(access_token=TokenHandlerIAM(),homogeneous=True,# must always be True for connection poolsdsn=mydb_low,config_dir="path_to_unzipped_wallet",wallet_location="location_of_pem_file",wallet_password=wpmin=1,max=5,increment=2)

Note that theaccess_token parameter should be set to a callable. This isuseful when the connection pool needs to expand and create new connections butthe current token has expired. In such a case, the callable should return astring specifying the new, valid access token.

Standalone Connections in Thick Mode Using OCI IAM Tokens

When using a class such asTokenHandlerIAM class togenerate OCI IAM tokens to connect to Oracle Autonomous Database in Thick mode,you need to explicitly set theaccess_token andexternalAuth parametersofconnect(). For example:

connection=oracledb.connect(access_token=TokenHandlerIAM(),externalauth=True,# must always be True in Thick modedsn=mydb_low)

Connection Pools in Thick Mode Using OCI IAM Tokens

When using a class such asTokenHandlerIAM class togenerate OCI IAM tokens to connect to Oracle Autonomous Database in Thick mode,you need to explicitly set theaccess_token andexternalauth parametersoforacledb.create_pool(). Thehomogeneous parameter must beTrue(its default value). For example:

pool=oracledb.create_pool(access_token=TokenHandlerIAM(),externalauth=True,# must always be True in Thick modehomogeneous=True,# must always be True for connection poolsdsn=mydb_low,min=1,max=5,increment=2)

Note that theaccess_token parameter should be set to a callable. This isuseful when the connection pool needs to expand and create new connections butthe current token has expired. In such a case, the callable should return astring specifying the new, valid access token.

4.13.2.3.OCI IAM Token-Based Authentication Connection Strings

The connection string used by python-oracledb can specify the directory wherethe token and private key files are located. This syntax is usable with olderversions of python-oracledb. However, it is recommended to use connectionparameters introduced in python-oracledb 1.1 instead. SeeOCI IAM Token-Based Authentication.

Note

OCI IAM Token-Based Authentication Connection Strings is only supported inthe python-oracledb Thick mode. SeeEnabling python-oracledb Thick mode.

The Oracle Cloud Infrastructure command line interface (OCI-CLI) can be usedexternally to get tokens and private keys from OCI IAM, for example with theOCI-CLIociiamdb-tokenget command.

The Oracle Net parameterTOKEN_AUTH must be set when you are using theconnection string syntax. Also, thePROTOCOL parameter must betcpsandSSL_SERVER_DN_MATCH should beON.

You can setTOKEN_AUTH=OCI_TOKEN in asqlnet.ora file. Alternatively,you can specify it in aConnect Descriptor, for examplewhen using atnsnames.ora file:

db_alias=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=xxx.oraclecloud.com))(CONNECT_DATA=(SERVICE_NAME=xxx.adb.oraclecloud.com))(SECURITY=(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com,\             O=Oracle Corporation,L=Redwood City,ST=California,C=US")(TOKEN_AUTH=OCI_TOKEN)))

The default location for the token and private key is the same default locationthat the OCI-CLI tool writes to. For example~/.oci/db-token/ on Linux.

If the token and private key files are not in the default location then theirdirectory must be specified with theTOKEN_LOCATION parameter in asqlnet.ora file or in aConnect Descriptor, for example when using atnsnames.orafile:

db_alias=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=xxx.oraclecloud.com))(CONNECT_DATA=(SERVICE_NAME=xxx.adb.oraclecloud.com))(SECURITY=(SSL_SERVER_CERT_DN="CN=xxx.oraclecloud.com,\             O=Oracle Corporation,L=Redwood City,ST=California,C=US")(TOKEN_AUTH=OCI_TOKEN)(TOKEN_LOCATION="/path/to/token/folder")))

TheTOKEN_AUTH andTOKEN_LOCATION values in a connection string takeprecedence over thesqlnet.ora settings.

Standalone connection example:

connection=oracledb.connect(dsn=db_alias,externalauth=True)

Connection pool example:

pool=oracledb.create_pool(dsn=db_alias,externalauth=True,homogeneous=False,min=1,max=2,increment=1)connection=pool.acquire()

4.13.2.4.OCI Cloud Native Authentication with the oci_tokens Plugin

With Cloud Native Authentication, python-oracledb’soci_tokens plugin can automatically generate and refresh OCIIAM tokens when required with the support of theOracle Cloud Infrastructure(OCI) Software Development Kit (SDK).

Theoci_tokens plugin can be importedlike:

importoracledb.plugins.oci_tokens

The plugin has a Python package dependency which needs to be installedseparately before the plugin can be used, seeInstall Modules for the OCI Cloud Native Authentication Plugin.

Theoci_tokens plugin defines and registers aparameter hook function which uses the connection parameterextra_auth_params passed tooracledb.connect(),oracledb.create_pool(),oracledb.connect_async(), ororacledb.create_pool_async(). Using this parameter’s values, the hookfunction sets theaccess_token parameter of aConnectParams object to a callable which generates an OCI IAM token. Python-oracledbthen acquires and uses a token to transparently complete connection or poolcreation calls.

For OCI Cloud Native Authentication connection and pool creation, theextra_auth_params parameter should be a dictionary with keys as shown inthe following table.

Table 4.9OCI Cloud Native Authentication Configuration Keys

Key

Description

Required or Optional

auth_type

The authentication type. The value should be the string “ConfigFileAuthentication”, “SimpleAuthentication”, or “InstancePrincipal”.

With Configuration File Authentication, the location of a configuration file containing the necessary information must be provided. By default, this file is located at/home/username/.oci/config, unless a custom location is specified during OCI IAM setup.

With Simple Authentication, the individual configuration parameters can be provided at runtime.

With Instance Principal Authentication, OCI compute instances can be authorized to access services on Oracle Cloud such as Oracle Autonomous Database. Python-oracledb applications running on such a compute instance are automatically authenticated, eliminating the need to provide database user credentials. This authentication method will only work on compute instances where internal network endpoints are reachable. SeeInstance Principal Authentication.

SeeOCI SDK Authentication Methods for more information.

Required

user

The Oracle Cloud Identifier (OCID) of the user invoking the API. For example,ocid1.user.oc1..<unique_ID>.

This parameter can be specified when the value of theauth_type key is “SimpleAuthentication”.

Required

key_file

The full path and filename of the private key.

This parameter can be specified when the value of theauth_type key is “SimpleAuthentication”.

Required

fingerprint

The fingerprint associated with the public key that has been added to this user.

This parameter can be specified when the value of theauth_type key is “SimpleAuthentication”.

Required

tenancy

The OCID of your tenancy. For example,ocid1.tenancy.oc1..<unique_ID>.

This parameter can be specified when the value of theauth_type key is “SimpleAuthentication”.

Required

region

The Oracle Cloud Infrastructure region. For example,ap-mumbai-1.

This parameter can be specified when the value of theauth_type key is “SimpleAuthentication”.

Required

profile

The configuration profile name to load.

Multiple profiles can be created, each with distinct values for necessary parameters. If not specified, the DEFAULT profile is used.

This parameter can be specified when the value of theauth_type key is “SimpleAuthentication” or “ConfigFileAuthentication”. If it is not specified when using “ConfigFileAuthentication”, the default value is taken.

Required

file_location

The configuration file location. The default value is~/.oci/config.

This parameter can be specified when the value of theauth_type key is “ConfigFileAuthentication”.

Optional

scope

This parameter identifies all databases in the cloud tenancy of the authenticated user. The default value isurn:oracle:db::id::*.

A scope that authorizes access to all databases within a compartment has the formaturn:oracle:db::id::<compartment-ocid>, for example,urn:oracle:db::id::ocid1.compartment.oc1..xxxxxxxx.

A scope that authorizes access to a single database within a compartment has the formaturn:oracle:db::id::<compartment-ocid>::<database-ocid>, for example,urn:oracle:db::id::ocid1.compartment.oc1..xxxxxx::ocid1.autonomousdatabase.oc1.phx.xxxxxx.

This parameter can be specified when the value of theauth_type key is “SimpleAuthentication”, “ConfigFileAuthentication”, or “InstancePrincipal”.

Optional

All keys and values other thanauth_type are used by theOCI SDK APIcalls in the plugin. The plugin implementation can be seen inplugins/oci_tokens.py.

For information on the OCI specific configuration parameters, seeOCI SDK.

The examples in the subsequent sections use theoci_tokens plugin to generate OCI IAM tokens to connect toOracle Autonomous Database with mutual TLS (mTLS). SeeConnecting to Oracle Cloud Autonomous Databases.

Standalone Connections in Thin Mode Using OCI IAM Tokens

When using theoci_tokens plugin to generateOCI IAM tokens to connect to Oracle Autonomous Database in Thin mode, you needto explicitly set theextra_auth_params parameter ofconnect(), and also any desiredconfig_dir,wallet_location, andwallet_password parameters. For example:

importoracledb.plugins.oci_tokenstoken_based_auth={# OCI specific configuration"auth_type":"ConfigFileAuthentication",# parameters to be set when using"profile":<profile>,# the oci_tokens plugin with"file_location":<filelocation>,# configuration file authentication}connection=oracledb.connect(dsn=mydb_low,config_dir="path_to_unzipped_wallet",wallet_location="location_of_pem_file",wallet_password=wp,extra_auth_params=token_based_auth)

Connection Pools in Thin Mode Using OCI IAM Tokens

When using theoci_tokens plugin to generateOCI IAM tokens to connect to Oracle Autonomous Database in Thin mode, you needto explicitly set theextra_auth_params parameter ofcreate_pool(), and also any desiredconfig_dir,wallet_location, andwallet_password parameters. Thehomogeneousparameter must beTrue (its default value). For example:

importoracledb.plugins.oci_tokenstoken_based_auth={"auth_type":"SimpleAuthentication",# OCI specific configuration"user":<user>,# parameters to be set when using"key_file":<key_file>,# the oci_tokens plugin with"fingerprint":<fingerprint>,# simple authentication"tenancy":<tenancy>,"region":<region>,"profile":<profile>}connection=oracledb.create_pool(dsn=mydb_low,config_dir="path_to_unzipped_wallet",homogeneous=true,# must always be True for connection poolswallet_location="location_of_pem_file",wallet_password=wp,extra_auth_params=token_based_auth)

Standalone Connections in Thick Mode Using OCI IAM Tokens

When using theoci_tokens plugin to generateOCI IAM tokens to connect to Oracle Autonomous Database in Thick mode, you needto explicitly set theexternalauth andextra_auth_params parameters oforacledb.connect(). For example:

importoracledb.plugins.oci_tokenstoken_based_auth={"auth_type":"SimpleAuthentication",# OCI specific configuration"user":<user>,# parameters to be set when using"key_file":<key_file>,# the oci_tokens plugin with"fingerprint":<fingerprint>,# simple authentication"tenancy":<tenancy>,"region":<region>,"profile":<profile>}connection=oracledb.connect(externalauth=True,dsn=mydb_low,extra_auth_params=token_based_auth)

Connection Pools in Thick Mode Using OCI IAM Tokens

When using theoci_tokens plugin to generateOCI IAM tokens to connect to Oracle Autonomous Database in Thick mode, you needto explicitly set theextra_auth_params andexternalauth parameters ofcreate_pool(). Thehomogeneous parameter must beTrue(its default value). For example:

importoracledb.plugins.oci_tokenstoken_based_auth={# OCI specific configuration"auth_type":"ConfigFileAuthentication",# parameters to be set when using"profile":<profile>,# the oci_tokens plugin with"file_location":<filelocation>,# configuration file authentication}connection=oracledb.create_pool(externalauth=True,# must always be True in Thick modehomogeneous=True,# must always be True for connection poolsdsn=mydb_low,extra_auth_params=token_based_auth)

4.14.Instance Principal Authentication

With Instance Principal Authentication, Oracle Cloud Infrastructure (OCI)compute instances can be authorized to access services on Oracle Cloud such asOracle Autonomous Database. Python-oracledb applications running on such acompute instance do not need to provide database user credentials.

Each compute instance behaves as a distinct type of Identity and AccessManagement (IAM) Principal, that is, each compute instance has a uniqueidentity in the form of a digital certificate which is managed by OCI. Whenusing Instance Principal Authentication, a compute instance authenticates withOCI IAM using this identity and obtains a short-lived token. This token isthen used to access Oracle Cloud services without storing or managing anysecrets in your application.

The example below demonstrates how to connect to Oracle AutonomousDatabase using Instance Principal authentication. To enable this, usepython-oracledb’soci_tokens plugin whichis pre-installed with theoracledb module.

Step 1: Create an OCI Compute Instance

AnOCI compute instance is a virtual machine runningwithin OCI that provides compute resources for your application. This computeinstance will be used to authenticate access to Oracle Cloud services whenusing Instance Principal Authentication.

To create an OCI compute instance, see the steps inCreating an Instance section of the Oracle Cloud Infrastructuredocumentation.

For more information on OCI compute instances, seeCalling Services from aCompute Instance.

Step 2: Install the OCI CLI on your compute instance

TheOCI Command Line Interface (CLI) that can be used on its own or withthe Oracle Cloud console to complete OCI tasks.

To install the OCI CLI on your compute instance, see the installationinstructions in theInstalling the CLI section of Oracle Cloud Infrastructuredocumentation.

Step 3: Create a Dynamic Group

A Dynamic Group is used to define rules to group the compute instances thatrequire access.

To create a dynamic group using the Oracle Cloud console, see the steps in theTo create a dynamic group section of the Oracle CloudInfrastructure documentation.

Step 4: Create an IAM Policy

An IAM Policy is used to grant a dynamic group permission to access therequired OCI services such as Oracle Autonomous Database.

To create an IAM policy using Oracle Cloud console, see the steps in theCreate an IAM Policy section of the Oracle CloudInfrastructure documentation.

Step 5: Map an Instance Principal to an Oracle Database User

You must map the Instance Principal to an Oracle Database user. For moreinformation, seeAccessing the Database Using an Instance Principal.

Also, make sure that external authentication is enabled on Oracle ADB andOracle Database parameterIDENTITY_PROVIDER_TYPE is set toOCI_IAM. Forthe steps, seeEnable IAM Authentication on ADB.

Step 6: Deploy your application on the Compute Instance

To use Instance Principal authentication, setextra_auth_params whencreating a standalone connection or a connection pool, for example:

importoracledbimportoracledb.plugins.oci_tokenstoken_based_auth={"auth_type":"InstancePrincipal"}connection=oracledb.connect(dsn=mydb_low,extra_auth_params=token_based_auth)

4.15.Privileged Connections

Themode parameter of the functionoracledb.connect() specifiesthe database privilege that you want to associate with the user.

The example below shows how to connect to Oracle Database as SYSDBA:

connection=oracledb.connect(user="sys",password=syspwd,dsn="dbhost.example.com/orclpdb",mode=oracledb.AuthMode.SYSDBA)# or mode=oracledb.AUTH_MODE_SYSDBAwithconnection.cursor()ascursor:cursor.execute("GRANT SYSOPER TO hr")

This is equivalent to executing the following in SQL*Plus:

CONNECTsys/syspwd@dbhost.example.com/orclpdbASSYSDBAGRANTSYSOPERTOhr;

In python-oracledb Thick mode, when python-oracledb uses Oracle Clientlibraries from a database software installation, you can use “bequeath”connections to databases that are also using the same Oracle libraries. Dothis by setting the standard Oracle environment variables such asORACLE_HOME andORACLE_SID and connecting in Python like:

oracledb.init_oracle_client()conn=oracledb.connect(mode=oracledb.AuthMode.SYSDBA)

This is equivalent to executing the following in SQL*Plus:

CONNECT/ASSYSDBA

4.16.Securely Encrypting Network Traffic to Oracle Database

You can encrypt data transferred between the Oracle Database andpython-oracledb so that unauthorized parties are not able to view plain textvalues as the data passes over the network.

Both python-oracledb Thin and Thick modes support TLS. Refer to theOracleDatabase Security Guide for more configurationinformation.

4.16.1.Native Network Encryption

The python-oracledbThick mode can additionally useOracle Database’snative network encryption.

With native network encryption, the client and database server negotiate a keyusing Diffie-Hellman key exchange. This provides protection againstman-in-the-middle attacks.

Native network encryption can be configured by editing Oracle Net’s optionalsqlnet.ora configuration file. The file on either thedatabase server and/or on each python-oracledb ‘client’ machine can beconfigured. Parameters control whether data integrity checking and encryptionis required or just allowed, and which algorithms the client and server shouldconsider for use.

As an example, to ensure all connections to the database are checked forintegrity and are also encrypted, create or edit the Oracle Database$ORACLE_HOME/network/admin/sqlnet.ora file. Set the checksum negotiationto always validate a checksum and set the checksum type to your desired value.The network encryption settings can similarly be set. For example, to use theSHA512 checksum and AES256 encryption use:

SQLNET.CRYPTO_CHECKSUM_SERVER=requiredSQLNET.CRYPTO_CHECKSUM_TYPES_SERVER=(SHA512)SQLNET.ENCRYPTION_SERVER=requiredSQLNET.ENCRYPTION_TYPES_SERVER=(AES256)

If you definitely know that the database server enforces integrity andencryption, then you do not need to configure python-oracledb separately. However,you can also, or alternatively do so, depending on your business needs. Createasqlnet.ora on your client machine and locate it with otherOptional Oracle Net Configuration Files:

SQLNET.CRYPTO_CHECKSUM_CLIENT=requiredSQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT=(SHA512)SQLNET.ENCRYPTION_CLIENT=requiredSQLNET.ENCRYPTION_TYPES_CLIENT=(AES256)

The client and server sides can negotiate the protocols used if the settingsindicate more than one value is accepted.

Note that these are example settings only. You must review your securityrequirements and read the documentation for your Oracle version. In particular,review the available algorithms for security and performance.

The NETWORK_SERVICE_BANNER column of the database viewV$SESSION_CONNECT_INFO can be used to verify theencryption status of a connection. For example with SQL*Plus:

SQL> select network_service_banner from v$session_connect_info;

If the connection is encrypted, then this query prints an output that includesthe available encryption service, the crypto-checksumming service, and thealgorithms in use, such as:

NETWORK_SERVICE_BANNER-------------------------------------------------------------------------------------TCP/IPNTProtocolAdapterforLinux:Version19.0.0.0.0-ProductionEncryptionserviceforLinux:Version19.0.1.0.0-ProductionAES256EncryptionserviceadapterforLinux:Version19.0.1.0.0-ProductionCrypto-checksummingserviceforLinux:Version19.0.1.0.0-ProductionSHA256Crypto-checksummingserviceadapterforLinux:Version19.0.1.0.0-Production

If the connection is unencrypted, then the query will only print theavailable encryption and crypto-checksumming services in the output. For example:

NETWORK_SERVICE_BANNER-------------------------------------------------------------------------------------TCP/IPNTProtocolAdapterforLinux:Version19.0.0.0.0-ProductionEncryptionserviceforLinux:Version19.0.1.0.0-ProductionCrypto-checksummingserviceforLinux:Version19.0.1.0.0-Production

For more information about Oracle Data Network Encryption and Integrity,and for information about configuring TLS network encryption, refer totheOracle Database Security Guide.

4.17.Resetting Passwords

After connecting to Oracle Database, passwords can be changed by callingConnection.changepassword():

# Get the passwords from somewhere, such as prompting the useroldpwd=getpass.getpass(f"Old Password for{username}: ")newpwd=getpass.getpass(f"New Password for{username}: ")connection.changepassword(oldpwd,newpwd)

When a password has expired and you cannot connect directly, you can connectand change the password in one operation by using thenewpassword parameterof the functionoracledb.connect() constructor:

# Get the passwords from somewhere, such as prompting the useroldpwd=getpass.getpass(f"Old Password for{username}: ")newpwd=getpass.getpass(f"New Password for{username}: ")connection=oracledb.connect(user=username,password=oldpwd,dsn="dbhost.example.com/orclpdb",newpassword=newpwd)

4.18.Connecting to Oracle Cloud Autonomous Databases

Python applications can connect to Oracle Autonomous Database (ADB) in OracleCloud using one-way TLS (Transport Layer Security) or mutual TLS(mTLS). One-way TLS and mTLS provide enhanced security for authentication andencryption.

A database username and password are still required for your applicationconnections. If you need to create a new database schema so you do not loginas the privileged ADMIN user, refer to the relevant Oracle Cloud documentation,for example seeCreate Database Users in theOracle Autonomous Database manual.

4.18.1.One-way TLS Connection to Oracle Autonomous Database

With one-way TLS, python-oracledb applications can connect to Oracle ADBwithout using a wallet. Both Thin and Thick modes of the python-oracledbdriver support one-way TLS. Applications that use the python-oracledb Thickmode, can connect to the Oracle ADB through one-way TLS only when using OracleClient library versions 19.14 (or later) or 21.5 (or later).

To enable one-way TLS for an ADB instance, complete the following steps in anOracle Cloud console in theAutonomous Database Information section of theADB instance details:

  1. Click theEdit link next toAccess Control List to update the AccessControl List (ACL). TheEdit Access Control List dialog box is displayed.

  2. In theEdit Access Control List dialog box, select the type of addresslist entries and the corresponding values. You can include the required IPaddresses, hostnames, or Virtual Cloud Networks (VCNs). The ACL limitsaccess to only the IP addresses or VCNs that have been defined and blocksall other incoming traffic.

  3. Navigate back to the ADB instance details page and click theEdit linknext toMutual TLS (mTLS) Authentication. TheEdit Mutual TLS Authenticationis displayed.

  4. In theEdit Mutual TLS Authentication dialog box, deselect theRequire mutual TLS (mTLS) authentication check box to disable the mTLSrequirement on Oracle ADB and clickSave Changes.

  5. Navigate back to the ADB instance details page and clickDB Connection onthe top of the page. ADatabase Connection dialog box is displayed.

  6. In the Database Connection dialog box, select TLS from theConnection Stringsdrop-down list.

  7. Copy the appropriate Connection String of the database instance used by your application.

Applications can connect to your Oracle ADB instance using the databasecredentials and the copiedConnect Descriptor. Forexample, to connect as the ADMIN user:

cs='''(description = (retry_count=20)(retry_delay=3)(address=(protocol=tcps)           (port=1522)(host=xxx.oraclecloud.com))(connect_data=(service_name=xxx.adb.oraclecloud.com))           (security=(ssl_server_dn_match=yes)(ssl_server_cert_dn="CN=xxx.oraclecloud.com,           O=Oracle Corporation, L=Redwood City, T=California, C=US")))'''connection=oracledb.connect(user="admin",password=pw,dsn=cs)

You can download the ADB connection wallet using theDB Connection buttonand extract thetnsnames.ora file, or create one yourselfif you prefer to keep connections strings out of application code, seeTNS Aliases for Connection Strings.

You may be interested in the blog postEasy wallet-less connections to OracleAutonomous Databases in Python.

4.18.2.Mutual TLS (mTLS) Connection to Oracle Autonomous Database

To enable python-oracledb connections to Oracle Autonomous Database in OracleCloud using mTLS, a wallet needs to be downloaded from the cloud console. mTLSis sometimes called Two-way TLS.

4.18.2.1.Install the Wallet and Network Configuration Files

From the Oracle Cloud console for the database, download the wallet zip fileusing theDB Connection button. The zip contains the wallet and networkconfiguration files. When downloading the zip, the cloud console will ask youto create a wallet password. This password is used by python-oracledb in Thinmode, but not in Thick mode.

Note: keep wallet files in a secure location and only share them and thepassword with authorized users.

In python-oracledb Thin mode

For python-oracledb in Thin mode, only two files from the zip are needed:

  • tnsnames.ora - Maps net service names used for application connectionstrings to your database services

  • ewallet.pem - Enables SSL/TLS connections in Thin mode. Keep this filesecure

If you do not have a PEM file, seeCreating a PEM File for python-oracledb Thin Mode.

Unzip the wallet zip file and move the required files to a location such as/opt/OracleCloud/MYDB.

Connection can be made using your database credentials and setting thedsnparameter to the desired network alias from thetnsnames.ora file. Theconfig_dir parameter indicates the directorycontainingtnsnames.ora. Thewallet_locationparameter is the directory containing the PEM file. In this example the filesare in the same directory. Thewallet_password parameter should be set tothe password created in the cloud console when downloading the wallet. Forexample, to connect as the ADMIN user using themydb_low network servicename:

connection=oracledb.connect(user="admin",password=pw,dsn="mydb_low",config_dir="/opt/OracleCloud/MYDB",wallet_location="/opt/OracleCloud/MYDB",wallet_password=wp)

In python-oracledb Thick mode

For python-oracledb in Thick mode, only these files from the zip are needed:

  • tnsnames.ora - Maps net service names used for application connectionstrings to your database services

  • sqlnet.ora - Configures Oracle Network settings

  • cwallet.sso - Enables SSL/TLS connections in Thick mode. Keep this filesecure

Unzip the wallet zip file. There are two options for placing the requiredfiles:

  • Move the three files to thenetwork/admin directory of the clientlibraries used by your application. For example if you are using InstantClient 19c and it is in$HOME/instantclient_19_15, then you would put thewallet files in$HOME/instantclient_19_15/network/admin/.

    Connection can be made using your database credentials and setting thedsn parameter to the desired network alias from thetnsnames.ora file. For example, to connect as the ADMIN user using themydb_low network service name:

    connection=oracledb.connect(user="admin",password=pw,dsn="mydb_low")
  • Alternatively, move the three files to any accessible directory, for example/opt/OracleCloud/MYDB.

    Then editsqlnet.ora and change the wallet location directory to thedirectory containing thecwallet.sso file. For example:

    WALLET_LOCATION=(SOURCE=(METHOD=file)(METHOD_DATA=(DIRECTORY="/opt/OracleCloud/MYDB")))SSL_SERVER_DN_MATCH=yes

    Since thetnsnames.ora andsqlnet.ora files are not in the defaultlocation, your application needs to indicate where they are, either with theconfig_dir parameter tooracledb.init_oracle_client(), or usingtheTNS_ADMIN environment variable. SeeOptional Oracle NetConfiguration Files. (Neither of these settings are needed,and you do not need to editsqlnet.ora, if you have put all the files inthenetwork/admin directory.)

    For example, to connect as the ADMIN user using themydb_low networkservice name:

    oracledb.init_oracle_client(config_dir="/opt/OracleCloud/MYDB")connection=oracledb.connect(user="admin",password=pw,dsn="mydb_low")

In python-oracle Thick mode, to create mTLS connections in one Python processto two or more Oracle Autonomous Databases, move eachcwallet.sso file toits own directory. For each connection use different connection stringWALLET_LOCATION parameters to specify the directory of eachcwallet.ssofile. It is recommended to use Oracle Client libraries 19.17 (or later) whenusingmultiple wallets.

4.18.2.2.Using the Easy Connect Syntax with Oracle Autonomous Database

When python-oracledb is using Oracle Client libraries 19c, or later, you canoptionally useEasy Connect syntax to connect to OracleAutonomous Database.

The mapping from the cloudtnsnames.ora entries to an EasyConnect string is:

protocol://host:port/service_name?wallet_location=/my/dir&retry_count=N&retry_delay=N

For example, if yourtnsnames.ora file had an entry:

cjjson_high=(description=(retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=xxx.oraclecloud.com))(connect_data=(service_name=abc_cjjson_high.adb.oraclecloud.com))(security=(ssl_server_cert_dn="CN=xxx.oraclecloud.com,O=Oracle Corporation,L=Redwood City,ST=California,C=US")))

Then your applications can connect using the connection string:

dsn="tcps://xxx.oraclecloud.com:1522/abc_cjjson_high.adb.oraclecloud.com?wallet_location=/Users/cjones/Cloud/CJJSON&retry_count=20&retry_delay=3"connection=oracledb.connect(user="hr",password=userpwd,dsn=dsn)

Thewallet_location parameter needs to be set to the directory containingthecwallet.sso orewallet.pem file from the wallet zip. The otherwallet files, includingtnsnames.ora, are not needed when you use the EasyConnect syntax.

You can add other Easy Connect parameters to the connection string, for example:

dsn=dsn+"&https_proxy=myproxy.example.com&https_proxy_port=80"

With python-oracledb Thin mode, the wallet password needs to be passed as aconnection parameter.

4.18.2.3.Creating a PEM File for python-oracledb Thin Mode

For mutual TLS in python-oracledb Thin mode, the certificate must be PrivacyEnhanced Mail (PEM) format. If you are using Oracle Autonomous Database yourwallet zip file will already include a PEM file.

If you have a PKCS12ewallet.p12 file and need to create PEM file, you canuse third party tools or the script below to do a conversion. For example, youcan invoke the script by passing the wallet password and the directorycontaining the PKCS12 file:

pythoncreate_pem.py--wallet-password'xxxxx'/Users/scott/cloud_configs/MYDBDIR

Once the PEM file has been created, you can use it by passing its directorylocation as thewallet_location parameter tooracledb.connect() ororacledb.create_pool(). These methods also accept awallet_password parameter. SeeMutual TLS (mTLS) Connection to Oracle Autonomous Database.

Script to convert from PKCS12 to PEM

# create_pem.pyimportargparseimportgetpassimportosfromcryptography.hazmat.primitives.serialization \importpkcs12,Encoding,PrivateFormat,BestAvailableEncryption,\NoEncryption# parse command lineparser=argparse.ArgumentParser(description="convert PKCS#12 to PEM")parser.add_argument("wallet_location",help="the directory in which the PKCS#12 encoded ""wallet file ewallet.p12 is found")parser.add_argument("--wallet-password",help="the password for the wallet which is used to ""decrypt the PKCS#12 encoded wallet file; if not ""specified, it will be requested securely")parser.add_argument("--no-encrypt",dest="encrypt",action="store_false",default=True,help="do not encrypt the converted PEM file with the ""wallet password")args=parser.parse_args()# validate arguments and acquire password if one was not specifiedpkcs12_file_name=os.path.join(args.wallet_location,"ewallet.p12")ifnotos.path.exists(pkcs12_file_name):msg=f"wallet location{args.wallet_location} does not contain " \"ewallet.p12"raiseException(msg)ifargs.wallet_passwordisNone:args.wallet_password=getpass.getpass()pem_file_name=os.path.join(args.wallet_location,"ewallet.pem")pkcs12_data=open(pkcs12_file_name,"rb").read()result=pkcs12.load_key_and_certificates(pkcs12_data,args.wallet_password.encode())private_key,certificate,additional_certificates=resultifargs.encrypt:encryptor=BestAvailableEncryption(args.wallet_password.encode())else:encryptor=NoEncryption()withopen(pem_file_name,"wb")asf:f.write(private_key.private_bytes(Encoding.PEM,PrivateFormat.PKCS8,encryptor))f.write(certificate.public_bytes(Encoding.PEM))forcertinadditional_certificates:f.write(cert.public_bytes(Encoding.PEM))print("PEM file",pem_file_name,"written.")

4.19.Connecting Through a Firewall via a Proxy

If you are behind a firewall, you can tunnel TLS/SSL connections via a proxy bysetting connection attributes, or by makingHTTPS_PROXY proxy name andHTTPS_PROXY_PORTport parameters available in yourconnection string.

Note

Oracle does not recommend connecting through a firewall via a proxy whenperformance is critical.

In python-oracledb Thin mode

  • Proxy settingshttps_proxy andhttps_proxy_port can be passed duringconnection or pool creation. Use appropriate values for your proxy:

    connection=oracledb.connect(user="admin",password=pw,dsn="mydb_low",config_dir="/opt/OracleCloud/MYDB",wallet_location="/opt/OracleCloud/MYDB",wallet_password=wp,https_proxy="myproxy.example.com",https_proxy_port=80)
  • Alternatively, add the parameters to yourEasy Connectstring:

    localhost/orclpdb&https_proxy=myproxy.example.com&https_proxy_port=80
  • Alternatively, update theConnect Descriptor (eitherbeing passed directly during connection or contained in yourtnsnames.ora file). If you are using atnsnames.ora file, a modified entry might look like:

    mydb_low=(description=(address=(https_proxy=myproxy.example.com)(https_proxy_port=80)(protocol=tcps)(port=1522)(host=...)

In python-oracledb Thick mode

  • If you are using anEasy Connect string, addHTTPS_PROXY andHTTPS_PROXY_PORT parameters with appropriate values foryour proxy. For example, you might pass parameters like:

    localhost/orclpdb&https_proxy=myproxy.example.com&https_proxy_port=80
  • Alternatively, update theConnect Descriptor (eitherbeing passed directly during connection or contained in yourtnsnames.ora file). If you are using atnsnames.ora file, a modified entry might look like:

    mydb_low=(description=(address=(https_proxy=myproxy.example.com)(https_proxy_port=80)(protocol=tcps)(port=1522)(host=...)

    Additionally create, or edit, asqlnet.ora file and adda line:

    SQLNET.USE_HTTPS_PROXY=on

4.20.Connecting using Multiple Wallets

You can make multiple connections with different wallets in one Pythonprocess.

In python-oracledb Thin mode

To use multiple wallets in python-oracledb Thin mode, pass the differentconnection strings, wallet locations, and wallet password (if required) in eachoracledb.connect() call or when creating aconnection pool:

connection=oracledb.connect(user=user_name,password=userpw,dsn=dsn,config_dir="path_to_unzipped_wallet",wallet_location="location_of_pem_file",wallet_password=walletpw)

Theconfig_dir parameter is the directory containing thetnsnames.ora file. Thewallet_location parameter is the directorycontaining theewallet.pem file. If you are using Oracle AutonomousDatabase, both of these paths are typically the same directory where thewallet.zip file was extracted. Thedsn should specify a TCPSconnection.

In python-oracledb Thick mode

To use multiple wallets in python-oracledb Thick mode, a TCPS connection stringcontaining theMY_WALLET_DIRECTORY option needs to be created:

dsn="mydb_high"# one of the network aliases from tnsnames.oraparams=oracledb.ConnectParams(config_dir="path_to_unzipped_wallet",wallet_location="path_location_of_sso_file")params.parse_connect_string(dsn)dsn=params.get_connect_string()connection=oracledb.connect(user=user_name,password=password,dsn=dsn)

Theconfig_dir parameter should be the directory containing thetnsnames.ora andsqlnet.ora files. Thewallet_location parameter is the directory containing thecwallet.ssofile. If you are using Oracle Autonomous Database, both of these paths aretypically the same directory where thewallet.zip file was extracted.

Note

Use Oracle Client libraries 19.17, or later, or use Oracle Client 21c or23ai. They contain important bug fixes for using multiple wallets inthe one process.

4.21.Connecting to Oracle Globally Distributed Database

Oracle Globally Distributed Database is a feature ofOracle Database that lets you automatically distribute and replicate dataacross a pool of Oracle databases that share no hardware or software. It waspreviously known as Oracle Sharding. It allows a database table to be split soeach database contains a table with the same columns but a different subset ofrows. These tables are known as sharded tables. From the perspective of anapplication, a sharded table in Oracle Globally Distributed Database looks likea single table: the distribution of data across those shards is completelytransparent to the application.

Sharding is configured inOracle Database, see theOracle Globally Distributed Database manual. Itrequires Oracle Database and Oracle Client libraries 12.2, or later.

Note

Oracle Globally Distributed Database is only supported in thepython-oracledb Thick mode. SeeEnabling python-oracledb Thick mode.

Theoracledb.connect() andConnectionPool.acquire() functionsacceptshardingkey andsupershardingkey parameters that are a sequenceof values used to route the connection directly to a given shard. A shardingkey is always required. A super sharding key is additionally required whenusing composite sharding, which is when data has been partitioned by a list orrange (the super sharding key), and then further partitioned by a sharding key.

When creating a connection pool, theoracledb.create_pool() attributemax_sessions_per_shard can be set. This is used to balance connections inthe pool equally across shards. It requires Oracle Client libraries 18.3 orlater.

Shard key values may be of type string (mapping to VARCHAR2 shard keys), number(NUMBER), bytes (RAW), or date (DATE). Multiple types may be used in eacharray. Sharding keys of TIMESTAMP type are not supported.

When connected to a shard, queries will only return data from that shard. Forqueries that need to access data from multiple shards, connections can beestablished to the coordinator shard catalog database. In this case, no shardkey or super shard key is used.

As an example of direct connection, if sharding had been configured on a singleVARCHAR2 column like:

CREATESHARDEDTABLEcustomers(cust_idNUMBER,cust_nameVARCHAR2(30),classVARCHAR2(10)NOTNULL,signup_dateDATE,cust_codeRAW(20),CONSTRAINTcust_name_pkPRIMARYKEY(cust_name))PARTITIONBYCONSISTENTHASH(cust_name)PARTITIONSAUTOTABLESPACESETts1;

then direct connection to a shard can be made by passing a single sharding key:

connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",shardingkey=["SCOTT"])

Numbers keys can be used in a similar way:

connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",shardingkey=[110])

When sharding by DATE, you can connect like:

importdatetimed=datetime.datetime(2014,7,3)connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",shardingkey=[d])

When sharding by RAW, you can connect like:

b=b'\x01\x04\x08';connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",shardingkey=[b])

Multiple keys can be specified, for example:

key_list=[70,"SCOTT","gold",b'\x00\x01\x02']connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",shardingkey=key_list)

A super sharding key example is:

connection=oracledb.connect(user="hr",password=userpwd,dsn="dbhost.example.com/orclpdb",supershardingkey=["goldclass"],shardingkey=["SCOTT"])