=====Python 2.7 / 3.4 und die Oracle Datenbank===== Mit der cx_Oracle (http://cx-oracle.sourceforge.net/) Library lässt sich einfach die Oracle Datenbank in Python einbinden. == Voraussetzung === Eine Oracle OCI Client Umgebung in der richtigen Bit Version und Oracle Version ist installiert! Minimal ist dazu der "Oracle Instant Client" notwendig, siehe => http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html In vielen Beispielen im Netz werden keine Bind Variablen verwendet, davon ist dringend abzuraten! D.h. die SQL Statements werden als String Objekte "zusammen gebaut" und dann ausgeführt! Das ist eine der Hauptursachen für die ganzen SQL Injektion Problem in vielen Anwendungen! Mehr dazu siehe hier: [[http://blog.red-database-security.com/2009/01/17/tutorial-oracle-sql-injection-in-webapps-part-i/|Alexander Kornbrust -Tutorial: Oracle SQL Injection in Webapps – Part I]] ==== Installation Windows 10 ==== Für Windows kann die Software mit einem Installer installiert werden. === Software download für Python 2.7 und 3.4 32bit für eine 11g Client 32bit Umgebung=== Die neueste Python Library für die Oracle Datenbank von https://pypi.python.org/pypi/cx_Oracle landen * cx_Oracle-5.2-11g.win32-py2.7-2.exe (md5) (md5 => 94a2b3dd0922f07d613ed1b67a14b48c) * cx_Oracle-5.2-11g.win32-py3.4.exe (md5) (md5 => 63137306c4fd292438a693dbce0a801d) Auf die Bit Version achten! In meine Fall 32bit und 11g! === Datei prüfen und installieren=== Über die Powershell MD5 checken: cd C:\Users\gpipperr\Downloads [Reflection.Assembly]::LoadWithPartialName("System.Web") [System.Web.Security.FormsAuthentication]::HashPasswordForStoringInConfigFile("cx_Oracle-5.2-11g.win32-py2.7-2.exe","MD5") 67413C94BA8BCFD462315787CDCFE7BA Toll, dies ist mal ein ganz anderer Hash als auf der Webseite angegeben ... Installer starten, und Library im jeweilgen Python Home installieren ==Installation mit pip== Leider funktioniert mit installierten C++ Compiler (Fehler "error: Microsoft Visual C++ 10.0 is required (Unable to find vcvarsall.bat)." ) .\python.exe -m pip install cx_Oracle ---- ==== Installation Cygwin Windows 7 ==== Voraussetzung: * Oracle Client auf dem System installiert * gcc unter cywin === Download der Sourcen === Wieder über => https://pypi.python.org/pypi/cx_Oracle * cx_Oracle-5.1.3.tar.gz (md5) => 32491c97d099d6ed04fd686697e3a6ea Nach cygwin /tmp kopieren + MD5 Testen und entpacken: md5sum cx_Oracle-5.1.3.tar.gz cd6ff16559cbc9c20087ec812c7092ab *cx_Oracle-5.1.3.tar.gz tar xfvz cx_Oracle-5.1.3.tar.gz cd ./cx_Oracle-5.1.3 ===Übersetzen und installieren === # in das ausgepackte Verzeichnis wechseln cd /tmp/cx_Oracle-5.1.3 python setup.py build #Fehler gcc: Fehler: nicht erkannte Kommandozeilenoption »-mno-cygwin« error: command 'gcc' failed with exit status vi setup.py .. #nach mno-cygwin suchen und auskomentieren .... elif sys.platform == "cygwin": #extraCompileArgs.append("-mno-cygwin") .. # erneut aufrufen => python setup.py build cx_Oracle.c:10:17: schwerwiegender Fehler: oci.h: No such file or directory #include ^ # Oracle Home setzen aufgerufen export ORACLE_HOME=/cygdrive/d/oracle/product/11.2.0.3/dbhome_1 python setup.py build python setup.py install #Warnings ignorieren #ok! #teste mit Script weiter unten ---- ====Test 1 - die EMP Tabelle abfragen==== Die EMP Tabelle abfragen: import cx_Oracle # get client library version print "Oracle Client Library Version :: ", cx_Oracle.clientversion() #get the connection to the database connection = cx_Oracle.connect('scott/tiger@10.10.10.1/GPI') # Version der DB ausgeben print "Oracle Database Version ::", connection.version #Cursor auf die DB öffenen cursor = connection.cursor() #Cursor ausführen cursor.execute('select * from emp order by empno') # Ergebnis ausgeben: # simple #for result in cursor: # print result # extended fetch # for EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO in cursor.fetchall(): print "Values from DB:", EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO #Verbindung wieder schließen cursor.close() connection.close() **Problem: ORA-12557: TNS:protocol adapter not loadable** In einer Umgebung mit mehren Oracle Homes darauf achten das in der Umgebung keine Pfade gesetzt sind, die auf das andere Home als das gewünschte zeigen! ==== Test 2 - Mit Bind Variablen die EMP Tabelle abfragen==== import cx_Oracle connection = cx_Oracle.connect('scott/tiger@10.10.10.1/GPI') # Cursor auf die DB oeffenen cursor = connection.cursor() # Cursor ausfuehren cursor.prepare('select * from emp where deptno=:1') # execute the statement on the statment above # NONE Parameter deptno = ("10", "20") for i in deptno: cursor.execute(None, {'1': i}) result = cursor.fetchall() print result #Verbindung wieder schliessen cursor.close() connection.close() ==== Test 3 - Daten in Tabelle EMP einfügen ==== import cx_Oracle import sys # get client library version print "Oracle Client Library Version :: ", cx_Oracle.clientversion() connection = cx_Oracle.connect('scott/tiger@10.10.10.1/GPI') # Version der DB ausgeben print "Oracle Database Version ::", connection.version # Cursor auf die DB oeffenen cursor = connection.cursor() # Oracle dept table has this columns # DEPTNO # DNAME # LOC dept_rows = [(90, "London", "Headquarter" ), (92, "Muenich", "Support" )] # how many rows to insert cursor.bindarraysize = len(dept_rows) # datatype - lenght of the inserted data cursor.setinputsizes(int, 14, 13) try: # insert the whole record cursor.executemany("insert into dept (DEPTNO, DNAME4,LOC) values (:1, :2,:3)", dept_rows) except cx_Oracle.DatabaseError as e: connection.rollback() print "Oracle Database Error:", e except: print "Unexpected error:", sys.exc_info()[0] raise connection.commit() # Verbindung wieder schliessen cursor.close() connection.close() ==== Test 4 - PL/SQL einbinden ==== Für das Einbinden von PL/SQL müssen die zurück gegeben Werte "gefangen" werden können. Procedure in PL/SQL anleegen: create or replace procedure myDate(p_date in out date,p_offset number) as begin p_date:=sysdate+p_offset; end; / In Python aufrufen, auf die [] bei callproc achten: import cx_Oracle connection = cx_Oracle.connect('scott/tiger@10.10.10.1/GPI') cursor = connection.cursor() return_value = cursor.var(cx_Oracle.Date) cursor.callproc('myDate', [return_value,2]) print return_value.getvalue() # return_value = cursor.var(cx_Oracle.STRING) cursor.execute(" BEGIN select sysdate into :1 from dual; END; ", [return_value]) print return_value.getvalue() #close cursor.close() connection.close() ==== Test 5 - DDL ==== import cx_Oracle import sys # get client library version print "Oracle Client Library Version :: ", cx_Oracle.clientversion() connection = cx_Oracle.connect('scott/tiger@10.10.10.1/GPI') # Version der DB ausgeben print "Oracle Database Version ::", connection.version # Cursor auf die DB oeffenen cursor = connection.cursor() ddl_sql = "create table t7 ( id number(11) not null , texte varchar2(2000))" try: cursor.execute(ddl_sql) except cx_Oracle.DatabaseError as e: print "Oracle Database Error:", e except: print "Unexpected error:", sys.exc_info()[0] raise cursor.close() # Verbindung wieder schliessen connection.close() ==== Test 6 - Daten visualisieren mit matplotlib ==== ==matplotlib unter Windows== see => http://matplotlib.org Vorbereitung => http://aka.ms/vcpython27 herunterladen und installieren (Microsoft Visual C++ Compiler for Python 2.7 ) python -m pip install matplotlib == Code Beispiel == # -*- coding: iso-8859-1 -*- import cx_Oracle import matplotlib.pyplot as plt import numpy as np # get client library version print "Oracle Client Library Version :: ", cx_Oracle.clientversion() connection = cx_Oracle.connect('scott/tiger@10.10.10.1/GPI') # Version der DB ausgeben print "Oracle Database Version ::", connection.version #Cursor auf die DB öffenen cursor = connection.cursor() #Cursor ausführen cursor.execute('select ename,sal from emp order by empno') #exctract the values to plot plot_values=[] plot_names=[] for ename,sal in cursor.fetchall(): plot_values.append(sal) plot_names.append(ename) ################ Line Plot ########## print plot_values plt.plot(plot_values,'bs') plt.show() ################ Bar diagramm ####### y_pos = np.arange(len(plot_names)) print y_pos error = np.random.rand(len(plot_names)) print error plt.barh(y_pos, plot_values, xerr=0, align='center', alpha=0.8) plt.yticks(y_pos, plot_names) plt.xlabel('Sallery') plt.title('Enough for all?') plt.show() #Verbindung wieder schliessen cursor.close() connection.close() ===== Database Resident Connection Pooling (DRCP) ===== siehe => [[dba:oracle_connection_pooling|Database Resident Connection Pooling (DRCP)]] ==== Quellen ==== cx-oracle Dokumentation: * http://cx-oracle.readthedocs.org/en/latest/index.html Oracle: * http://www.oracle.com/technetwork/articles/dsl/python-091105.html * http://www.oracle.com/technetwork/articles/prez-stored-proc-084100.html Weitere Seite über das Thema * http://dbaportal.eu/sidekicks/sidekick-cx_oracle-code-paterns/