diff --git a/doc/src/release_notes.rst b/doc/src/release_notes.rst index 8927b7f..2c22a0c 100644 --- a/doc/src/release_notes.rst +++ b/doc/src/release_notes.rst @@ -69,6 +69,8 @@ Common Changes and scale allow for it -- in the same way that numbers are fetched from the database (`issue 99 `__). +#) Fixed bug with binding boolean values with Oracle Database 23c + (`issue 263 `__). #) Fixed bug with getting unknown attributes from DbObject instances. #) Error ``DPY-4029: errors in array DML exceed 65535`` is now raised when the number of batch errors exceeds 65535 when calling diff --git a/src/oracledb/base_impl.pxd b/src/oracledb/base_impl.pxd index 2b5024b..2664825 100644 --- a/src/oracledb/base_impl.pxd +++ b/src/oracledb/base_impl.pxd @@ -243,6 +243,8 @@ cdef class BaseConnImpl: public object outputtypehandler public bint autocommit public bint invoke_session_callback + readonly tuple server_version + readonly bint supports_bool cdef object _check_value(self, DbType dbtype, BaseDbObjectTypeImpl objtype, object value, bint* is_ok) diff --git a/src/oracledb/connection.py b/src/oracledb/connection.py index e7fd13c..988d7ec 100644 --- a/src/oracledb/connection.py +++ b/src/oracledb/connection.py @@ -1081,7 +1081,7 @@ class Connection: """ if self._version is None: self._verify_connected() - self._version = self._impl.get_version() + self._version = ".".join(str(c) for c in self._impl.server_version) return self._version def xid( diff --git a/src/oracledb/impl/base/connection.pyx b/src/oracledb/impl/base/connection.pyx index fa9ba9f..265975d 100644 --- a/src/oracledb/impl/base/connection.pyx +++ b/src/oracledb/impl/base/connection.pyx @@ -264,10 +264,6 @@ cdef class BaseConnImpl: def get_type(self, object conn, str name): pass - @utils.CheckImpls("getting the database version") - def get_version(self): - pass - @utils.CheckImpls("pinging the database") def ping(self): pass diff --git a/src/oracledb/impl/base/var.pyx b/src/oracledb/impl/base/var.pyx index 2b1492c..d14ec3e 100644 --- a/src/oracledb/impl/base/var.pyx +++ b/src/oracledb/impl/base/var.pyx @@ -220,7 +220,9 @@ cdef class BaseVarImpl: dbtype = DB_TYPE_VARCHAR size = 1 elif isinstance(value, PY_TYPE_BOOL): - dbtype = DB_TYPE_BOOLEAN if is_plsql else DB_TYPE_BINARY_INTEGER + dbtype = DB_TYPE_BOOLEAN \ + if self._conn_impl.supports_bool or is_plsql \ + else DB_TYPE_BINARY_INTEGER elif isinstance(value, str): size = len(value) dbtype = DB_TYPE_VARCHAR diff --git a/src/oracledb/impl/thick/connection.pyx b/src/oracledb/impl/thick/connection.pyx index 236ebc2..d0a823c 100644 --- a/src/oracledb/impl/thick/connection.pyx +++ b/src/oracledb/impl/thick/connection.pyx @@ -270,6 +270,7 @@ cdef class ThickConnImpl(BaseConnImpl): dpiConnCreateParams conn_params ConnectParamsImpl pool_params dpiAccessToken access_token + dpiVersionInfo version_info ConnectionParams params int status @@ -387,8 +388,20 @@ cdef class ThickConnImpl(BaseConnImpl): params.password_len, params.dsn_ptr, params.dsn_len, &common_params, &conn_params, &self._handle) + if status == DPI_SUCCESS: + status = dpiConn_getServerVersion(self._handle, NULL, NULL, + &version_info) if status < 0: _raise_from_odpi() + self.server_version = ( + version_info.versionNum, + version_info.releaseNum, + version_info.updateNum, + version_info.portReleaseNum, + version_info.portUpdateNum + ) + self.supports_bool = client_version_info.versionNum >= 23 \ + and version_info.versionNum >= 23 # determine if session callback should be invoked; this takes place if # the connection is newly created by the pool or if the requested tag @@ -581,20 +594,6 @@ cdef class ThickConnImpl(BaseConnImpl): finally: dpiObjectType_release(handle) - def get_version(self): - cdef: - dpiVersionInfo version_info - int status - with nogil: - status = dpiConn_getServerVersion(self._handle, NULL, NULL, - &version_info) - if status < 0: - _raise_from_odpi() - return "%d.%d.%d.%d.%d" % \ - (version_info.versionNum, version_info.releaseNum, - version_info.updateNum, version_info.portReleaseNum, - version_info.portUpdateNum) - def set_action(self, str value): self._set_text_attr(dpiConn_setAction, value) diff --git a/src/oracledb/impl/thick/utils.pyx b/src/oracledb/impl/thick/utils.pyx index b873c2b..c82e91b 100644 --- a/src/oracledb/impl/thick/utils.pyx +++ b/src/oracledb/impl/thick/utils.pyx @@ -433,21 +433,15 @@ def clientversion(): The five values are the major version, minor version, update number, patch number and port update number. """ - cdef dpiVersionInfo info - global client_version - if client_version is None: - if driver_context == NULL: - errors._raise_err(errors.ERR_INIT_ORACLE_CLIENT_NOT_CALLED) - if dpiContext_getClientVersion(driver_context, &info) < 0: - _raise_from_odpi() - client_version = ( - info.versionNum, - info.releaseNum, - info.updateNum, - info.portReleaseNum, - info.portUpdateNum - ) - return client_version + if driver_context == NULL: + errors._raise_err(errors.ERR_INIT_ORACLE_CLIENT_NOT_CALLED) + return ( + client_version_info.versionNum, + client_version_info.releaseNum, + client_version_info.updateNum, + client_version_info.portReleaseNum, + client_version_info.portUpdateNum + ) def init_oracle_client(lib_dir=None, config_dir=None, error_url=None, @@ -494,6 +488,9 @@ def init_oracle_client(lib_dir=None, config_dir=None, error_url=None, ¶ms, &driver_context, &error_info) < 0: _raise_from_info(&error_info) + if dpiContext_getClientVersion(driver_context, + &client_version_info) < 0: + _raise_from_odpi() driver_context_params = params_tuple diff --git a/src/oracledb/impl/thin/connection.pyx b/src/oracledb/impl/thin/connection.pyx index b0f4741..4c447e5 100644 --- a/src/oracledb/impl/thin/connection.pyx +++ b/src/oracledb/impl/thin/connection.pyx @@ -36,7 +36,6 @@ cdef class ThinConnImpl(BaseConnImpl): uint32_t _statement_cache_size object _statement_cache_lock Protocol _protocol - str _server_version uint32_t _session_id uint32_t _serial_num str _action @@ -353,9 +352,6 @@ cdef class ThinConnImpl(BaseConnImpl): get_dbobject_type_cache(self._dbobject_type_cache_num) return cache.get_type(conn, name) - def get_version(self): - return self._server_version - def ping(self): cdef Message message message = self._create_message(PingMessage) diff --git a/src/oracledb/impl/thin/messages.pyx b/src/oracledb/impl/thin/messages.pyx index 60ad96d..ac0a0cb 100644 --- a/src/oracledb/impl/thin/messages.pyx +++ b/src/oracledb/impl/thin/messages.pyx @@ -1538,9 +1538,9 @@ cdef class AuthMessage(Message): self.session_data.get("AUTH_SC_SERVICE_NAME") self.conn_impl._instance_name = \ self.session_data.get("AUTH_INSTANCENAME") - - self.conn_impl._server_version = \ - "%d.%d.%d.%d.%d" % self._get_version_tuple(buf) + self.conn_impl.server_version = self._get_version_tuple(buf) + self.conn_impl.supports_bool = \ + buf._caps.ttc_field_version >= TNS_CCAP_FIELD_VERSION_23_1 cdef int _set_params(self, ConnectParamsImpl params, Description description) except -1: diff --git a/src/oracledb/thick_impl.pyx b/src/oracledb/thick_impl.pyx index d1b5d83..e7e381a 100644 --- a/src/oracledb/thick_impl.pyx +++ b/src/oracledb/thick_impl.pyx @@ -67,9 +67,9 @@ cdef type PY_TYPE_LOB cdef type PY_TYPE_TIMEDELTA = datetime.timedelta cdef dpiContext *driver_context = NULL +cdef dpiVersionInfo client_version_info driver_context_params = None -client_version = None include "impl/thick/buffer.pyx" include "impl/thick/connection.pyx" diff --git a/tests/test_3100_boolean_var.py b/tests/test_3100_boolean_var.py index e91cbab..e39abf4 100644 --- a/tests/test_3100_boolean_var.py +++ b/tests/test_3100_boolean_var.py @@ -106,6 +106,21 @@ class TestCase(test_env.BaseTestCase): ) self.assertIsNone(result) + @unittest.skipUnless( + test_env.get_client_version() >= (23, 1), "unsupported client" + ) + @unittest.skipUnless( + test_env.get_server_version() >= (23, 1), "unsupported server" + ) + def test_3109_bind_and_fetch_boolean_23c(self): + "3109 - test binding and fetching boolean with 23c" + for value in (True, False): + with self.subTest(value=value): + self.cursor.execute("select not :1 from dual", [value]) + (fetched_value,) = self.cursor.fetchone() + self.assertIsInstance(fetched_value, bool) + self.assertEqual(fetched_value, not value) + if __name__ == "__main__": test_env.run_test_cases() diff --git a/utils/templates/connection.py b/utils/templates/connection.py index c409bfe..dcdea2f 100644 --- a/utils/templates/connection.py +++ b/utils/templates/connection.py @@ -1079,7 +1079,7 @@ class Connection: """ if self._version is None: self._verify_connected() - self._version = self._impl.get_version() + self._version = ".".join(str(c) for c in self._impl.server_version) return self._version def xid(