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/[email protected]: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).


Comentarios

8 respuestas a «Cómo Conectarse a Oracle desde Python en Ubuntu»

  1. Avatar de temeter

    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

  2. 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

  3. Gracias, sirve 100%

  4. 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!

  5. 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???

  6. 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

  7. 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

  8. Marcelo, buenas tardes acabo de lograr la conexion faltaba:

    sudo apt-get install libaio1

    con esto completé la instalacion hasta el ejercicio,

    Saludos

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *