Cómo Conectarse a Oracle desde Python en Ubuntu
Luego de luchar (y bastante) para acceder a una BD Oracle desde Python, me propuse escribir los pasos a realizar así quedan para la posteridad. Tengo entendido que el único driver que funciona bien para conectarse es el cx_Oracle, así que voy a tratar de explicar cómo se instala todo desde el comienzo, usando Ubuntu Hardy 8.04.
Actualización: este método aún sirve sobre Ubuntu Lucid 10.04 y cx_Oracle 5.03.
1. Instalación del Oracle InstantClient
Primero, hay que descargar el Oracle InstantClient para la plataforma Linux que se utilice (x86, x86_64, Power, Itanium, etc.) desde acá (es necesario registrarse, pero es gratuito). Los paquetes necesarios son «Instant Client Package – Basic Lite» y «Instant Client Package – SDK«. cx_Oracle debería funcionar con cualquiera de las versiones 9.x y 10.x, así que vamos a bajar la última versión de la serie 10.x (que en este momento es la 10.2.0.4).
Primero hay que descomprimir los 2 archivos .zip; por ejemplo:
marcelo@ubuntu-server:~$ unzip basiclite-10.2.0.4.0-linux-x86_64.zip Archive: basiclite-10.2.0.4.0-linux-x86_64.zip inflating: instantclient_10_2/BASIC_LITE_README [...] inflating: instantclient_10_2/libocijdbc10.so inflating: instantclient_10_2/ojdbc14.jar marcelo@ubuntu-server:~$ unzip sdk-10.2.0.4.0-linux-x86_64.zip Archive: sdk-10.2.0.4.0-linux-x86_64.zip creating: instantclient_10_2/sdk/ creating: instantclient_10_2/sdk/include/ inflating: instantclient_10_2/sdk/include/occi.h inflating: instantclient_10_2/sdk/include/occiCommon.h [...] inflating: instantclient_10_2/sdk/SDK_README extracting: instantclient_10_2/sdk/ottclasses.zip inflating: instantclient_10_2/sdk/ott marcelo@ubuntu-server:~$ |
Al descomprimir ambos archivos en el mismo directorio se generó el nuevo directorio «instantclient_10_2» con todo el contenido:
marcelo@ubuntu-server:~$ cd instantclient_10_2/ marcelo@ubuntu-server:~/instantclient_10_2$ ls -l total 33504 -rw-rw-r-- 1 marcelo marcelo 238 2008-03-12 04:37 BASIC_LITE_README -r--r--r-- 1 marcelo marcelo 1609607 2008-03-12 04:37 classes12.jar -rwxrwxr-x 1 marcelo marcelo 67542 2008-03-12 04:37 genezi -rwxrwxr-x 1 marcelo marcelo 21038613 2008-03-12 04:37 libclntsh.so.10.1 -r-xr-xr-x 1 marcelo marcelo 3796601 2008-03-12 04:37 libnnz10.so -rwxrwxr-x 1 marcelo marcelo 1664116 2008-03-12 04:37 libocci.so.10.1 -rwxrwxr-x 1 marcelo marcelo 4351321 2008-03-12 04:37 libociicus.so -r-xr-xr-x 1 marcelo marcelo 138033 2008-03-12 04:37 libocijdbc10.so -r--r--r-- 1 marcelo marcelo 1555682 2008-03-12 04:37 ojdbc14.jar drwxrwxr-x 4 marcelo marcelo 4096 2008-03-12 04:37 sdk marcelo@ubuntu-server:~/instantclient_10_2$ |
Creamos el directorio /opt/oracle, y después lo movemos al nuevo directorio renombrado como /opt/oracle/instantclient.
marcelo@ubuntu-server:~$ sudo mkdir -p /opt/oracle/ marcelo@ubuntu-server:~$ sudo mv instantclient_10_2 /opt/oracle/instantclient |
Ahora debemos decirle al linker de bibliotecas dinámicas del sistema (ld) la ubicación de un nuevo path donde podrá encontrar más bibliotecas software para el programa que lo requiera; en este caso ese «programa» será el módulo de python para acceder a Oracle, cx_Oracle. Es decir, que además de las bibliotecas disponibles en, por ejemplo, /usr/lib y /usr/local/lib, también pondremos a disposición de los programas del usuario las bibliotecas del directorio /opt/oracle/instantclient. Esto se hace con el programa ldconfig:
marcelo@ubuntu-server:~$ sudo -i [sudo] password for marcelo: root@ubuntu-server:~# echo "/opt/oracle/instantclient" > /etc/ld.so.conf.d/oracle.conf root@ubuntu-server:~# ldconfig root@ubuntu-server:~# ldconfig --print | grep /opt/oracle libocijdbc10.so (libc6,x86-64) => /opt/oracle/instantclient/libocijdbc10.so libociicus.so (libc6,x86-64) => /opt/oracle/instantclient/libociicus.so libocci.so.10.1 (libc6,x86-64) => /opt/oracle/instantclient/libocci.so.10.1 libnnz10.so (libc6,x86-64) => /opt/oracle/instantclient/libnnz10.so libclntsh.so.10.1 (libc6,x86-64) => /opt/oracle/instantclient/libclntsh.so.10.1 root@ubuntu-server:~# cd /opt/oracle/instantclient root@ubuntu-server:/opt/oracle/instantclient# ln -s libclntsh.so.10.1 libclntsh.so root@ubuntu-server:/opt/oracle/instantclient# ln -s libocci.so.10.1 libocci.so |
La idea es crear un archivo con extensión .conf en el directorio /etc/ld.so.conf.d/ [1], con un nombre relacionado con nuestro propósito, que sólo indica un nuevo directorio de bibliotecas de ubicación «no estándar».
Luego hay que refrescar la información de bibliotecas, con el comando «ldconfig». Después, «ldconfig –print» muestra todas las bibliotecas disponibles en el sistema para enlazar dinámicamente, pero como ahora sólo son de nuestro interés las del directorio /opt/oracle, se filtra la salida con un grep acorde.
También hacemos dos enlaces simbólicos a las bibliotecas principales del Instantclient, cuyo número de versión es «genérico», a diferencia de los archivos originales, cuya versión es 10.1. Al momento de compilar el cx_Oracle, éste buscará la versión genérica de estas librerías, no una versión específica (por ende, serán los archivos libclntsh.so y libocci.so). Todo esto debe hacerse como root, por eso el «sudo -i» inicial.
2. Instalación del cx_Oracle
(instrucciones extraídas en parte y basadas del Readme.txt del proyecto)
Una vez que se tiene el Instantclient instalado y configurado, vamos a proceder a instalar el módulo cx_Oracle. Lo «complicado» de la instalación del módulo (a diferencia de la gran mayoría que son 100% python) es que requiere correr un proceso de compilación contra las bibliotecas Instantclient que acabamos de instalar. Lo bueno es que a esta altura ya hicimos casi todo el trabajo. 🙂
Primero instalamos algunas dependencias:
marcelo@ubuntu-server:~$ sudo apt-get install python-dev python-setuptools build-essential Leyendo lista de paquetes... Hecho Creando árbol de dependencias Leyendo la información de estado... Hecho Se instalarán los siguientes paquetes extras: binutils dpkg-dev g++ g++-4.2 gcc gcc-4.2 libc6-dev libgomp1 libstdc++6-4.2-dev libtimedate-perl linux-libc-dev make patch python-pkg-resources python2.5-dev Paquetes sugeridos: binutils-doc debian-keyring g++-multilib g++-4.2-multilib gcc-4.2-doc libstdc++6-4.2-dbg autoconf automake1.9 bison flex gcc-doc gcc-multilib gdb libtool manpages-dev gcc-4.2-locales gcc-4.2-multilib libgcc1-dbg libgomp1-dbg libmudflap0-4.2-dbg libmudflap0-4.2-dev glibc-doc libstdc++6-4.2-doc make-doc diff-doc Se instalarán los siguientes paquetes NUEVOS: binutils build-essential dpkg-dev g++ g++-4.2 gcc gcc-4.2 libc6-dev libgomp1 libstdc++6-4.2-dev libtimedate-perl linux-libc-dev make patch python-dev python-pkg-resources python-setuptools python2.5-dev 0 actualizados, 18 se instalarán, 0 para eliminar y 0 no actualizados. Necesito descargar 12,8MB de archivos. After this operation, 52,9MB of additional disk space will be used. ¿Desea continuar [S/n]? [...] |
Cuando se compilan módulos de python que acceden a librerías nativas (generalmente en C), debe instalarse el paquete «python-dev», que contiene los headers de las estructuras, funciones y demás símbolos del lenguaje. Las setuptools creo que no hacen falta, pero siempre es útil tenerlo para instalar más módulos después. El metapaquete «build-essential» nos provee todo lo básico necesario para compilar programas en C/C++.
Luego descargamos y descomprimimos el código fuente del módulo, en formato .tar.gz (hay RPMs y paquetes para Windows, pero no DEBs). La última versión es la 4.3.1. La descompresión puede ser en un directorio cualquiera, como por ejemplo, el home de un usuario (no es necesario root):
marcelo@ubuntu-server:~$ tar xvzf cx_Oracle-4.3.1.tar.gz cx_Oracle-4.3.1/ cx_Oracle-4.3.1/test/ cx_Oracle-4.3.1/test/test_dbapi20.py cx_Oracle-4.3.1/test/LongVar.py cx_Oracle-4.3.1/test/LobVar.py cx_Oracle-4.3.1/test/DateTimeVar.py cx_Oracle-4.3.1/test/test.py cx_Oracle-4.3.1/test/NumberVar.py [...] marcelo@ubuntu-server:~$ cd cx_Oracle-4.3.1/ marcelo@ubuntu-server:~/cx_Oracle-4.3.1$ |
Luego, para poder compilar/construir primero e instalar después el módulo, hay que establecer la variable de entorno ORACLE_HOME:
marcelo@ubuntu-server:~/cx_Oracle-4.3.1$ export ORACLE_HOME=/opt/oracle/instantclient/ |
Ahora, a construir el módulo. Puede verse que no hace falta ser root:
marcelo@ubuntu-server:~/cx_Oracle-4.3.1$ python setup.py build running build running build_ext building 'cx_Oracle' extension gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.5/cx_Oracle.o -L/opt/oracle/instantclient/lib -L/opt/oracle/instantclient/ -lclntsh -o build/lib.linux-x86_64-2.5/cx_Oracle.so marcelo@ubuntu-server:~/cx_Oracle-4.3.1$ |
Listo, ya podemos instalar y probar el nuevo módulo:
marcelo@ubuntu-server:~/cx_Oracle-4.3.1$ sudo python setup.py install running install running build running build_ext running install_lib copying build/lib.linux-x86_64-2.5/cx_Oracle.so -> /usr/lib/python2.5/site-packages running install_egg_info Writing /usr/lib/python2.5/site-packages/cx_Oracle-4.3.1.egg-info marcelo@ubuntu-server:~/cx_Oracle-4.3.1$ ipython Python 2.5.2 (r252:60911, Jul 31 2008, 17:31:22) Type "copyright", "credits" or "license" for more information. IPython 0.8.1 -- An enhanced Interactive Python. ? -> Introduction to IPython's features. %magic -> Information about IPython's 'magic' % functions. help -> Python's own help system. object? -> Details about 'object'. ?object also works, ?? prints more. In [1]: import cx_Oracle In [2]: conn_str='scott/tiger@192.168.1.90:1521/DESARROLLO' In [3]: db_conn = cx_Oracle.connect(conn_str) In [4]: cursor = db_conn.cursor() In [5]: cursor.execute('SELECT username, user_id, created FROM dba_users') Out[5]: [, , ] In [6]: registros = cursor.fetchall() In [7]: for r in registros: ...: print str(r) ...: ...: ('MGMT_VIEW', 46, datetime.datetime(2008, 10, 15, 13, 4, 47)) ('SYS', 0, datetime.datetime(2008, 10, 15, 12, 43, 8)) ('SYSTEM', 5, datetime.datetime(2008, 10, 15, 12, 43, 8)) ('DBSNMP', 24, datetime.datetime(2008, 10, 15, 12, 51, 3)) ('SYSMAN', 44, datetime.datetime(2008, 10, 15, 13, 3, 24)) ('SCOTT', 49, datetime.datetime(2008, 10, 21, 17, 30, 43)) ('PYTK08', 47, datetime.datetime(2008, 10, 15, 13, 54, 37)) ('OUTLN', 11, datetime.datetime(2008, 10, 15, 12, 43, 13)) ('MDSYS', 43, datetime.datetime(2008, 10, 15, 12, 57, 21)) ('ORDSYS', 40, datetime.datetime(2008, 10, 15, 12, 57, 21)) ('ANONYMOUS', 36, datetime.datetime(2008, 10, 15, 12, 55, 58)) ('EXFSYS', 34, datetime.datetime(2008, 10, 15, 12, 55, 41)) ('WMSYS', 25, datetime.datetime(2008, 10, 15, 12, 51, 55)) ('XDB', 35, datetime.datetime(2008, 10, 15, 12, 55, 58)) ('ORDPLUGINS', 41, datetime.datetime(2008, 10, 15, 12, 57, 21)) ('SI_INFORMTN_SCHEMA', 42, datetime.datetime(2008, 10, 15, 12, 57, 21)) ('DIP', 19, datetime.datetime(2008, 10, 15, 12, 46)) ('TSMSYS', 21, datetime.datetime(2008, 10, 15, 12, 49, 19)) In [8]: |
Listo! Ya tenemos acceso a Oracle desde mi lenguaje de programación preferido, Python.
Espero que les sirva.
Saludos!
Marcelo
[1] Esto es así en Ubuntu Hardy 8.04. En versiones más antiguas de Ubuntu, como Dapper 6.06, este directorio no existe y en su lugar se debe agregar una línea con el mismo contenido pero en el archivo /etc/ld.so.conf (creándolo en caso de no existir).
Gracias por el manual Marcelo. Pero me quedo atascando en el paso de ldconfig. Este noa ctualiza las librerias. Por tanto no aparece las de oracle por ningun lado.
Estoy usando ubuntu 10
Uhm… Ni idea qué puede pasar, en Ubuntu 10.04 hace poquito un compañero de trabajo siguió estos pasos y no hubo ningún problema. Revisá permisos, si los archivos están donde tienen que estar, los archivos en /etc/ld.so.conf.d/, etc.
El procedimiento de ldconfig es muy común para cargar bibliotecas, en todo caso podés probar copiar los .so en algún lugar común como «/usr/lib/oracle/» o buscar cómo funciona ldconfig en Google…
Saludos
Gracias, sirve 100%
Este tuto esta excelente, le agrego nomas que si al querer conectarse se obtiene el error:
ORA-21561: OID generation failed
es porque no tenes asociado en tu /etc/hosts a la ip 127.0.0.1 el resultado del comando ‘hostname’. Ej:
$ hostname
foobar.site
$ cat /etc/hosts
127.0.0.1 localhost
Lo correcto seria:
$ hostname
foobar.site
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 foobar.site
Con esto cx_Oracle deberia dejar de dar el mencionado error y en el mejor de los casos, conectarnos a la DB.
Dejo link de referencia:
http://sourceforge.net/p/tora/discussion/52737/thread/f68b89ad
Saludos!
buenos dias, la linea:
sudo python setup.py install
me bota el error:
Traceback (most recent call last):
File «setup.py», line 36, in
oracleHome = os.environ[«ORACLE_HOME»]
File «/usr/lib/python2.7/UserDict.py», line 23, in __getitem__
raise KeyError(key)
KeyError: ‘ORACLE_HOME’
que puede ser???
Hola Juan,
Sí, esto me pasó en versiones posteriores, pero hace tanto que no me acuerdo bien cómo lo solucioné. Tratá de cambiar a usuario root para hacerlo («sudo su -«) y exportar la variable ORACLE_HOME directamente como root:
# export ORACLE_HOME=/opt/oracle/instantclient/
Y probá de nuevo a ver si el script encuentra la variable de entorno. Caso contrario habrá que editar el setup.py, ir a la línea 36 (que es donde falla, al menos) y ver de qué manera setear la variable a mano.
Saludos
Estimado gracias por la respuesta,
Efectivamente le cambie en el archivo y le puse directamente el ORACLE_HOME y ejecuto hasta a instalacion, pero al momento de la prueba no me deja importar la libreria:
In [4]: import cx_Oracle
—————————————————————————
ImportError Traceback (most recent call last)
in ()
—-> 1 import cx_Oracle
ImportError: libaio.so.1: cannot open shared object file: No such file or directory
ese archivo no lo encuentro en el directorio….
que podria darse o es concecuencia del oracle_home… no creo…
gracias anticipadas
Marcelo, buenas tardes acabo de lograr la conexion faltaba:
sudo apt-get install libaio1
con esto completé la instalacion hasta el ejercicio,
Saludos