228 lines
9.0 KiB
Python
228 lines
9.0 KiB
Python
#------------------------------------------------------------------------------
|
|
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
|
|
#
|
|
# This software is dual-licensed to you under the Universal Permissive License
|
|
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
|
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
|
# either license.
|
|
#
|
|
# If you elect to accept the software under the Apache License, Version 2.0,
|
|
# the following applies:
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# https://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#------------------------------------------------------------------------------
|
|
|
|
#------------------------------------------------------------------------------
|
|
# oracledb_upgrade.py
|
|
#
|
|
# Example module to assist upgrading large applications from cx_Oracle 8 to
|
|
# python-oracledb (the renamed major new release of cx_Oracle).
|
|
#
|
|
# An environment variable ORA_PYTHON_DRIVER_TYPE can be set to determine
|
|
# whether to use cx_Oracle, python-oracledb Thin mode, or python-oracledb Thick
|
|
# mode.
|
|
#
|
|
# NOTE
|
|
#
|
|
# Most users DO NOT need this file. Instead you can do:
|
|
#
|
|
# - Install python-oracledb:
|
|
#
|
|
# python -m pip install oracledb
|
|
#
|
|
# - Change "import cx_Oracle" to:
|
|
#
|
|
# import oracledb as cx_Oracle
|
|
#
|
|
# - Remove any call to init_oracle_client() if you want to use
|
|
# python-oracledb Thin mode. Conversely add a call if you want to use
|
|
# Thick mode.
|
|
#
|
|
# - Use named parameters in calls to connect(), Connection() and
|
|
# SessionPool():
|
|
#
|
|
# c = oracledb.connect(user="un", password="pw", dsn="cs")
|
|
#
|
|
# Other updates noted in the upgrade documentation may also need to be
|
|
# made.
|
|
#
|
|
# However, if you want to toggle which driver to use or have code where
|
|
# changes are not easy, then this file may help.
|
|
#
|
|
# USAGE
|
|
#
|
|
# - Install python-oracledb:
|
|
#
|
|
# python -m pip install oracledb
|
|
#
|
|
# - Change your code's first "import cx_Oracle" to:
|
|
#
|
|
# import oracledb_upgrade as cx_Oracle
|
|
#
|
|
# This needs to be imported before cx_Oracle is ever imported for it to
|
|
# take effect. Subsequent imports do not need to be changed but may be,
|
|
# if desired.
|
|
#
|
|
# - Remove any call to init_oracle_client() from your existing code base.
|
|
#
|
|
# - Set lib_dir (in the module code below) to your Oracle Client library
|
|
# directory if you are calling init_oracle_client() with that parameter in
|
|
# your existing cx_Oracle code on Windows or macOS, and you intend to use
|
|
# python-oracledb Thick mode or cx_Oracle.
|
|
#
|
|
# - Review python-oracledb documentation for additional changes that may be
|
|
# needed in your code.
|
|
#
|
|
# - Set the environment variable ORA_PYTHON_DRIVER_TYPE to "cx", "thin", or
|
|
# "thick" to choose which module to use:
|
|
#
|
|
# thin -> python-oracledb Thin mode (the default)
|
|
#
|
|
# thick -> python-oracledb Thick mode
|
|
#
|
|
# cx -> cx_Oracle
|
|
#
|
|
# - Run your application
|
|
#
|
|
# An example application showing this module in use is:
|
|
#
|
|
# import oracledb_upgrade as cx_Oracle
|
|
# import os
|
|
#
|
|
# un = os.environ.get("PYTHON_USERNAME")
|
|
# pw = os.environ.get("PYTHON_PASSWORD")
|
|
# cs = os.environ.get("PYTHON_CONNECTSTRING")
|
|
#
|
|
# connection = cx_Oracle.connect(user=un, password=pw, dsn=cs)
|
|
# with connection.cursor() as cursor:
|
|
# sql = """SELECT UNIQUE CLIENT_DRIVER
|
|
# FROM V$SESSION_CONNECT_INFO
|
|
# WHERE SID = SYS_CONTEXT('USERENV', 'SID')"""
|
|
# for r, in cursor.execute(sql):
|
|
# print(r)
|
|
#
|
|
#------------------------------------------------------------------------------
|
|
|
|
import os
|
|
import sys
|
|
import platform
|
|
|
|
import cx_Oracle
|
|
import oracledb
|
|
|
|
# Set True to print which driver and mode is being used
|
|
MODE_TRACE = False
|
|
|
|
# Enable a 'shim' if your cx_Oracle code makes connect(), Connection() or
|
|
# SessionPool() calls that use positional parameters e.g. like:
|
|
# cx_Oracle.connect(username, password, connect_string)
|
|
ALLOW_POSITIONAL_CONNECT_ARGS = True
|
|
|
|
# On macOS and Windows set lib_dir to your Instant Client path if you are
|
|
# currently calling init_oracle_client() in your application. On Linux do not
|
|
# set lib_dir; instead set LD_LIBRARY_PATH or configure ldconfig before running
|
|
# Python.
|
|
lib_dir = None
|
|
if platform.system() == "Darwin" and platform.machine() == "x86_64":
|
|
lib_dir = os.environ.get("HOME")+"/Downloads/instantclient_19_8"
|
|
elif platform.system() == "Windows":
|
|
lib_dir = r"C:\oracle\instantclient_19_14"
|
|
|
|
# Determine which module and mode to use.
|
|
# The default is python-oracledb Thin mode.
|
|
driver_type = os.environ.get("ORA_PYTHON_DRIVER_TYPE", "thin")
|
|
|
|
if driver_type.lower() == "cx":
|
|
if MODE_TRACE: print("Using cx_Oracle")
|
|
from cx_Oracle import *
|
|
sys.modules["oracledb"] = cx_Oracle
|
|
sys.modules["cx_Oracle"] = cx_Oracle
|
|
oracledb.init_oracle_client(lib_dir=lib_dir)
|
|
else:
|
|
from oracledb import *
|
|
sys.modules["oracledb"] = oracledb
|
|
sys.modules["cx_Oracle"] = oracledb
|
|
if driver_type.lower() == "thick":
|
|
if MODE_TRACE: print("Using python-oracledb thick")
|
|
# For python-oracledb Thick mode, init_oracle_client() MUST be called
|
|
# on all operating systems. Whether to use a lib_dir value depends on
|
|
# how your system library search path is configured.
|
|
oracledb.init_oracle_client(lib_dir=lib_dir)
|
|
else:
|
|
if MODE_TRACE: print("Using python-oracledb thin")
|
|
|
|
# If your existing cx_Oracle code never used positional arguments for
|
|
# connection and pool creation calls then inject_connect_shim() is not
|
|
# necessary and you can set ALLOW_POSITIONAL_CONNECT_ARGS to False
|
|
def inject_connect_shim():
|
|
"""
|
|
Allow python-oracledb to use positional arguments in connect(),
|
|
Connection() and SessionPool() signatures as allowed by cx_Oracle.
|
|
"""
|
|
|
|
class ShimConnection(oracledb.Connection):
|
|
|
|
def __init__(self, user=None, password=None, dsn=None,
|
|
mode=oracledb.DEFAULT_AUTH, handle=0, pool=None,
|
|
threaded=False, events=False, cclass=None,
|
|
purity=oracledb.ATTR_PURITY_DEFAULT,
|
|
newpassword=None, encoding=None, nencoding=None,
|
|
edition=None, appcontext=[], tag=None,
|
|
matchanytag=False, shardingkey=[],
|
|
supershardingkey=[], stmtcachesize=20):
|
|
if dsn is None and password is None:
|
|
dsn = user
|
|
user = None
|
|
super().__init__(dsn=dsn, user=user, password=password,
|
|
mode=mode, handle=handle, pool=pool,
|
|
threaded=threaded, events=events, cclass=cclass,
|
|
purity=purity, newpassword=newpassword,
|
|
edition=edition, appcontext=appcontext, tag=tag,
|
|
matchanytag=matchanytag, shardingkey=shardingkey,
|
|
supershardingkey=supershardingkey,
|
|
stmtcachesize=stmtcachesize)
|
|
|
|
class ShimPool(oracledb.SessionPool):
|
|
|
|
def __init__(self, user=None, password=None, dsn=None, min=1, max=2,
|
|
increment=1, connectiontype=oracledb.Connection,
|
|
threaded=True, getmode=oracledb.SPOOL_ATTRVAL_NOWAIT,
|
|
events=False, homogeneous=True, externalauth=False,
|
|
encoding=None, nencoding=None, edition=None, timeout=0,
|
|
wait_timeout=0, max_lifetime_session=0, session_callback=None,
|
|
max_sessions_per_shard=0, soda_metadata_cache=False,
|
|
stmtcachesize=20, ping_interval=60):
|
|
|
|
super().__init__(dsn=dsn, user=user, password=password,
|
|
min=min, max=max, increment=increment,
|
|
connectiontype=connectiontype, threaded=threaded,
|
|
getmode=getmode, events=events, homogeneous=homogeneous,
|
|
externalauth=externalauth, encoding=encoding,
|
|
nencoding=nencoding, edition=edition, timeout=timeout,
|
|
wait_timeout=wait_timeout,
|
|
max_lifetime_session=max_lifetime_session,
|
|
session_callback=session_callback,
|
|
max_sessions_per_shard=max_sessions_per_shard,
|
|
soda_metadata_cache=soda_metadata_cache,
|
|
stmtcachesize=stmtcachesize, ping_interval=ping_interval)
|
|
|
|
global connect
|
|
connect = ShimConnection
|
|
global Connection
|
|
Connection = ShimConnection
|
|
global SessionPool
|
|
SessionPool = ShimPool
|
|
|
|
if ALLOW_POSITIONAL_CONNECT_ARGS and driver_type.lower() != "cx":
|
|
inject_connect_shim()
|