Skip to content

Commit

Permalink
Connecting to a database with national character set UTF8 is now
Browse files Browse the repository at this point in the history
supported; an error is now raised only when the first attempt to use
NCHAR, NVARCHAR2 or NCLOB data is made (#16).
  • Loading branch information
anthony-tuininga committed Jul 15, 2022
1 parent 53b041a commit 2f740ee
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 8 deletions.
4 changes: 4 additions & 0 deletions doc/src/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ oracledb 1.0.2 (July 2022)
Thin Mode Changes
+++++++++++++++++

#) Connecting to a database with national character set `UTF8` is now
supported; an error is now raised only when the first attempt to use
NCHAR, NVARCHAR2 or NCLOB data is made
(`issue 16 <https://github.com/oracle/python-oracledb/issues/16>`__).
#) When using the connection parameter `https_proxy` while using protocol
`tcp`, a more meaningful exception is now raised:
`DPY-2029: https_proxy requires use of the tcps protocol`.
Expand Down
11 changes: 11 additions & 0 deletions src/oracledb/impl/thin/capabilities.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ cdef class Capabilities:
cdef:
uint16_t protocol_version
uint8_t ttc_field_version
uint16_t charset_id
uint16_t ncharset_id
bytearray compile_caps
bytearray runtime_caps
bint char_conversion
Expand All @@ -58,6 +60,15 @@ cdef class Capabilities:
cdef void _adjust_for_server_runtime_caps(self, bytearray server_caps):
pass

cdef int _check_ncharset_id(self) except -1:
"""
Checks that the national character set id is AL16UTF16, which is the
only id that is currently supported.
"""
if self.ncharset_id != TNS_CHARSET_UTF16:
errors._raise_err(errors.ERR_NCHAR_CS_NOT_SUPPORTED,
charset_id=self.ncharset_id)

@cython.boundscheck(False)
cdef void _init_compile_caps(self):
self.ttc_field_version = TNS_CCAP_FIELD_VERSION_MAX
Expand Down
18 changes: 10 additions & 8 deletions src/oracledb/impl/thin/messages.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,8 @@ cdef class MessageWithData(Message):
elif ora_type_num == TNS_DATA_TYPE_VARCHAR \
or ora_type_num == TNS_DATA_TYPE_CHAR \
or ora_type_num == TNS_DATA_TYPE_LONG:
if csfrm == TNS_CS_NCHAR:
buf._caps._check_ncharset_id()
column_value = buf.read_str(csfrm)
elif ora_type_num == TNS_DATA_TYPE_RAW \
or ora_type_num == TNS_DATA_TYPE_LONG_RAW:
Expand Down Expand Up @@ -944,9 +946,10 @@ cdef class MessageWithData(Message):
elif ora_type_num == TNS_DATA_TYPE_VARCHAR \
or ora_type_num == TNS_DATA_TYPE_CHAR \
or ora_type_num == TNS_DATA_TYPE_LONG:
if var_impl.dbtype._csfrm == 1:
if var_impl.dbtype._csfrm == TNS_CS_IMPLICIT:
temp_bytes = (<str> value).encode()
else:
buf._caps._check_ncharset_id()
temp_bytes = (<str> value).encode(TNS_ENCODING_UTF16)
buf.write_bytes_chunked(temp_bytes)
elif ora_type_num == TNS_DATA_TYPE_RAW \
Expand Down Expand Up @@ -1976,6 +1979,7 @@ cdef class LobOpMessage(Message):
buf.write_bytes(self.dest_lob_impl._locator)
if self.operation == TNS_LOB_OP_CREATE_TEMP:
if self.source_lob_impl.dbtype._csfrm == TNS_CS_NCHAR:
buf._caps._check_ncharset_id()
buf.write_ub4(TNS_CHARSET_UTF16)
else:
buf.write_ub4(TNS_CHARSET_UTF8)
Expand Down Expand Up @@ -2068,9 +2072,10 @@ cdef class ProtocolMessage(Message):
cdef int _process_message(self, ReadBuffer buf,
uint8_t message_type) except -1:
cdef:
uint16_t num_elem, fdo_length, charset_id, ncharset_id
uint16_t num_elem, fdo_length
bytearray server_compile_caps
bytearray server_runtime_caps
Capabilities caps = buf._caps
const char_type *fdo
ssize_t ix
uint8_t c
Expand All @@ -2080,19 +2085,16 @@ cdef class ProtocolMessage(Message):
buf.read_ub1(&c)
if c == 0:
break
buf.read_uint16(&charset_id, BYTE_ORDER_LSB)
buf._caps.char_conversion = charset_id != TNS_CHARSET_UTF8
buf.read_uint16(&caps.charset_id, BYTE_ORDER_LSB)
buf._caps.char_conversion = caps.charset_id != TNS_CHARSET_UTF8
buf.skip_ub1() # skip server flags
buf.read_uint16(&num_elem, BYTE_ORDER_LSB)
if num_elem > 0: # skip elements
buf.skip_raw_bytes(num_elem * 5)
buf.read_uint16(&fdo_length)
fdo = buf.read_raw_bytes(fdo_length)
ix = 6 + fdo[5] + fdo[6]
ncharset_id = (fdo[ix + 3] << 8) + fdo[ix + 4]
if ncharset_id != TNS_CHARSET_UTF16:
errors._raise_err(errors.ERR_NCHAR_CS_NOT_SUPPORTED,
charset_id=ncharset_id)
caps.ncharset_id = (fdo[ix + 3] << 8) + fdo[ix + 4]
server_compile_caps = bytearray(buf.read_bytes())
server_runtime_caps = bytearray(buf.read_bytes())
if not server_compile_caps[TNS_CCAP_LOGON_TYPES] & TNS_CCAP_O7LOGON:
Expand Down

0 comments on commit 2f740ee

Please sign in to comment.