Eu criei uma solução usando
- Oracle Database 12c com Database Characterset AL32UTF8 (obrigatório armazenar Unicode !!)
- Esquema SCOTT
- Cliente instantâneo Oracle 12.2 com pacote ODBC (pode ser baixado gratuitamente da Oracle)
- Oracle SQL Developer (Ferramenta capaz de inserir caracteres Unicode e conectar por Java/JDBC)
- Python 3.8
O código Python abaixo está no meu entendimento autoexplicativo - apenas IP, PORT e SERVICE na string de conexão precisam ser alterados. Para observar os caracteres Unicode no shell/cmd, você precisa definir a variável de ambiente
PYTHONIOENCODING=UTF-8
Infelizmente, isso não funciona no Eclipse IDE com PyDEV, então usei try-except para obter o código em execução. Deu-me umas horas de dor de cabeça...
#
# Safe python file as UTF-8 - otherwise you get no UTF-8 output !!!!
#
# Unix:
# export PYTHONIOENCODING=UTF-8
#
# Windows:
# set PYTHONIOENCODING=UTF-8
#
# Eclipse/PyDev:
# create for run/debug environment variable
# PYTHONIOENCODING=UTF-8
#
# ODBC:
# Oracle Instantclient 12.2 + ODBC package
#
# DB:
# Oracle RDBMS 12.2 with Database Characterset AL32UTF8 to allow Unicode
#
# SQL Tool to Execute SQL (JDBC)
# Oracle SQL Developer
#
# SQL
# connect scott/tiger
# create table polish(col1 varchar2(50));
# insert into polish(col1) values('SQLD ł ń');
# commit;
#
#
import pyodbc
bl = " "
UTF8 = "UTF-8"
strict = "Strict"
s1 = "Test "+UTF8
print(s1)
s1 = chr(322) + bl + chr(324)
m = bytes(s1,UTF8)
print(m)
try:
print(m.decode(UTF8,strict))
except:
pass
print()
print("Test ODBC and " + UTF8)
print("Test ODBC and " + UTF8)
cs = "DRIVER={DRIVERNAME};UID={USERID};PWD={PASSWD};DBQ={IP_OR_HOSTNAME}:{PORT}/{SERVICE_OR_SID};"
csfill = cs.format(DRIVERNAME="Oracle in instantclient_12_2",
IP_OR_HOSTNAME="111.222.33.44",
PORT=12102,
SERVICE_OR_SID="DB1212UTF",
USERID="SCOTT",
PASSWD="tiger")
print(csfill)
cn = pyodbc.connect(csfill)
cursor = cn.cursor()
# Do the insert - can be done using normal parameters and Unicode strings...
cursor.execute("insert into Polish(COL1) values ( ? )", u"Python ł ń")
# perform commit if want to inspect in SQL Developer
# cursor.commit()
cursor = cn.cursor()
# We need to cast COL1 so that unicode is shipped as ' \xxxx'
# unfortunatly Unicode deos not work directly
# so we use ASCIISTR() to do that...
cursor.execute('SELECT ASCIISTR(COL1)"COL1" from Polish')
rows = cursor.fetchall()
for row in rows:
s =""
x = row.COL1
y = 0
j = len(x)-1
# Parse incoming column for Oracle-Style Unicode like ' \0142'
while y <= j:
if y + 5 <= j:
# detect if oracle unicode begins with blank and slash -> ' \'
sc = x[y]+x[y+1]
if sc == " \\":
# create unicode character
c = x[y+2]+x[y+3]+x[y+4]+x[y+5]
s += bl + chr(int(c,16))
# step forward to next character
y += 5
else:
# no unicode 4 characters before end !!
s += chr(ord(x[y]))
else:
# no unicode - regular ASCII
s += chr(ord(x[y]))
y += 1
m = bytes(s,UTF8)
print(m)
try:
print(m.decode(UTF8,strict))
except:
pass
cursor.close()
cn.close()
A aplicação em execução dá
Test UTF-8
b'\xc5\x82 \xc5\x84'
ł ń
Test ODBC and UTF-8
DRIVER=Oracle in instantclient_12_2;UID=SCOTT;PWD=tiger;DBQ=111.222.33.44:12102/DB1212UTF;
b'SQLD \xc5\x82 \xc5\x84'
SQLD ł ń
b'Python \xc5\x82 \xc5\x84'
Python ł ń