sql >> Base de Datos >  >> RDS >> Oracle

¿Cómo conectarse a la base de datos usando QOCI o QODBC con la codificación correcta?

He creado una solución usando

  • Base de datos Oracle 12c con juego de caracteres de base de datos AL32UTF8 (¡obligatorio para almacenar Unicode!)
  • Esquema SCOTT
  • Oracle Instant client 12.2 con paquete ODBC (se puede descargar de forma gratuita desde Oracle)
  • Oracle SQL Developer (Herramienta capaz de ingresar caracteres Unicode y conectarse mediante Java/JDBC)
  • Python 3.8

El código de Python a continuación se explica por sí mismo:solo es necesario cambiar la IP, el PUERTO y el SERVICIO en la cadena de conexión. Para ver los caracteres Unicode en shell/cmd, debe configurar la variable de entorno

PYTHONIOENCODING=UTF-8

Desafortunadamente, esto no funciona en Eclipse IDE con PyDEV, así que usé try-except para ejecutar el código. Me dio un par de horas de dolor de cabeza...

#  
# 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()   

La aplicación en ejecución da

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 ł ń