Oracle
 sql >> Database >  >> RDS >> Oracle

Come connettersi al database utilizzando QOCI o QODBC con la codifica corretta?

Ho creato una soluzione utilizzando

  • Oracle Database 12c con Database Characterset AL32UTF8 (obbligatorio per memorizzare Unicode!!)
  • Schema SCOTT
  • Client Oracle Instant 12.2 con pacchetto ODBC (scaricabile gratuitamente da Oracle)
  • Oracle SQL Developer (strumento in grado di inserire caratteri Unicode e connettersi tramite Java/JDBC)
  • Python 3.8

Il codice Python di seguito si spiega da sé:solo IP, PORT e SERVICE nella stringa di connessione devono essere modificati. Per guardare i caratteri Unicode su shell/cmd, devi impostare la variabile d'ambiente

PYTHONIOENCODING=UTF-8

Sfortunatamente questo non funziona su Eclipse IDE con PyDEV, quindi ho usato try-only per eseguire il codice. Mi ha dato qualche ora di mal di testa...

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

L'applicazione in esecuzione 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 ł ń