Fecha de publicación del tutorial: 2007-04-25

Tutorial visitado 11.834 veces Descargar en PDF
Rutinas C desde Oracle

Accediendo a rutinas C y C++ desde Oracle

Creación: 09-04-2007

1. Introducción

En este tutorial os quiero mostrar como llamar a rutinas desarrolladas en c o cpp desde un procedimiento almacenado de ORACLE.



2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: HP COMPAQ Presario V6000 (Centrino Duo 1.66GHz, 2048 MB RAM, 100 GB HD)

  • Sistema Operativo: Windows XP Home Edition

  • Oracle 9.2

  • MinGW 5 para windows.

  • Eclipse como editor de ficheros



3. Creando el .c y el .cpp

Para comenzar vamos a crear dos pequeños ficheros, uno escrito en c, y otro escrito en cpp. Crearemos una función que escribirá en un fichero una pequeña frase. A continuación os muestro el código de nuestros archivos:

helloWord.c

#include <stdlib.h>

#include <stdio.h>

#include <windows.h>


#define EXPORT _declspec(dllexport)


EXPORT void HelloWord(char* cadena, int* numero);


EXPORT void HelloWord(char* cadena, int* numero)

{

FILE * f = fopen("c:\\HelloWordC.log", "aw");

fprintf(f, "Hola desde la libreria HelloWordC.dll:\n");

fprintf(f, "Datos antes de modificarse \nCadena: %s \nNumero: %d\n", cadena, *numero);

strcpy(cadena,"Modificada por helloWordC.dll");

*numero = 10;

fprintf(f, "Despues\nCadena: %s \nNumero: %d\n", cadena, *numero);

fflush(f);

fclose(f);

}



Al llamar a la función HelloWord, se creará un fichero, si no existe ya, con el nombre HelloWordC.log en c:\ y se le añadirá la frase "Hola desde la librería HelloWordC.dll". Se imprimirán los parámetros antes y despúes de ser modificados, para ver que realmente los datos son obtenidos y modificados correctamente.

helloWord.cpp

#include <stdlib.h>

#include <stdio.h>

#include <windows.h>


#define EXPORT extern "C" _declspec(dllexport)


EXPORT void HelloWord(char* cadena, int* numero);


EXPORT void HelloWord(char* cadena, int* numero)

{

FILE * f = fopen("c:\\HelloWordCpp.log", "aw");

fprintf(f, "Hola desde la libreria HelloWordCpp.dll:\n");

fprintf(f, "Datos antes de modificarse \nCadena: %s \nNumero: %d\n", cadena, *numero);

strcpy(cadena,"Modificada por helloWordCpp.dll");

*numero = 20;

fprintf(f, "Despues\nCadena: %s \nNumero: %d\n", cadena, *numero);

fflush(f);

fclose(f);

}



La única diferencia entre las dos implementaciónes está en la definición de EXPORT. En cpp se antepone extern "C" a _declspec(dllexport) .



4. Creando las librerías

Vamos a crear un fichero makefile para facilitarnos la compilación de los ficheros y la creación de la librería. El contenido es el siguiente:

JDK_HOME=$(JAVA_HOME)


WIN32_CPP=g++

WIN32_C=gcc


CPPFILE=helloWord.cpp

CFILE=helloWord.c


CPPLIBNAMEWIN32=helloWordCpp.dll

CLIBNAMEWIN32=helloWordC.dll

CFLAGSWIN32=-DLOG -I$(JDK_HOME)\include -I$(JDK_HOME)\include\win32 -shared -Wl,--kill-at -Wall


all:

@echo "Uso: make {win32 | help}"


win32: $(FILE) $(JNIFILE)

$(WIN32_CPP) $(CFLAGSWIN32) -o $(CPPLIBNAMEWIN32) $(CPPFILE)

$(WIN32_C) $(CFLAGSWIN32) -o $(CLIBNAMEWIN32) $(CFILE)

help:

@echo "Uso: make win32"


Se crearán dos librerías. Una llamada helloWordCpp.dll generada a partir del fuente helloWord.cpp y otra llamada helloWordC.dll, generada a partir del fuente helloWord.c

Estas dos librerías son las que invocaremos desde Oracle.



5. Configurando Oracle para poder acceder a librerías externas

Debemos editar el listener de oracle (archivo listener.ora), situado en %oracle_dir%\ora92\network\admin\listener.ora, y añadir a cada entrada de SID_DESC la opción (ENVS = "EXTPROC_DLLS=ANY"). A continuación os muestro un ejemplo:



[...]

SID_LIST_LISTENER =

(SID_LIST =

(SID_DESC =

(SID_NAME = PLSExtProc)

(ORACLE_HOME = C:\oracle\ora92)

(PROGRAM = extproc)

(ENVS = "EXTPROC_DLLS=ANY")

)

(SID_DESC =

(GLOBAL_DBNAME = WOODY)

(ORACLE_HOME = C:\oracle\ora92)

(SID_NAME = WOODY)

(ENVS = "EXTPROC_DLLS=ANY")

)

)

[...]

Una vez editado el fichero, debemos reiniciar el servicio del listener de Oracle.



6. Llamada a las librerías

Lo primero que debemos hacer es crear un objeto LIBRARY asociado a la librería a la que queremos acceder. Lanzamos en la consola de Oracle:

CREATE OR REPLACE LIBRARY helloWordC AS 'C:\helloWordC.dll'; /

CREATE OR REPLACE LIBRARY helloWordCpp AS 'C:\helloWordCpp.dll'; /

Como vemos, las librerías se encuentran en C:\. Oracle no comprueba que la librería es correcta (el path, el código, etc.) hasta el momento de la ejecución, por lo tanto no sabríamos si lo hemos hecho bien hasta que no lanzaramos la prueba.

Ahora vamos a asociar dos procedimientos almacenados con las dos funciones HelloWord de las librerías. Lanzamos en la consola de Oracle:

CREATE OR REPLACE PROCEDURE helloC(cadena IN OUT VARCHAR, numero IN OUT PLS_INTEGER) AS LANGUAGE C LIBRARY helloWordC name "HelloWord"; /

CREATE OR REPLACE PROCEDURE helloCpp(cadena IN OUT VARCHAR, numero IN OUT PLS_INTEGER) AS LANGUAGE C LIBRARY helloWordCpp name "HelloWord"; /

Hemos asociado un procedimiento helloC al procedimiento HelloWord() de la librería de C, y un procedimiento helloCpp asociado al HelloWord() de la librería de Cpp. Para mapear los parámetros podemos consultar el capítulo 2 del manual de oracle (http://www.unix.org.ua/orelly/oracle/prog2/ch21_04.htm). Nos indica que VARCHAR mapea a un tipo char* de C, y PLS_INTEGER mapea a un tipo de dato int* de C.

Vamos a crear otro procedimiento llamado test para poder probar nuestras librerías:

CREATE OR REPLACE PROCEDURE test

AS

cadena VARCHAR(50);

numero PLS_INTEGER;

begin

cadena := 'Hola mundo';

numero := 0;

dbms_output.put_line('Valores iniciales');

dbms_output.put_line('Cadena:' || cadena);

dbms_output.put_line('Numero:' || to_char(numero));

helloC(cadena, numero);

dbms_output.put_line('Valores modificados con helloWordC.dll');

dbms_output.put_line('Cadena:' || cadena);

dbms_output.put_line('Numero:' || to_char(numero));

helloCpp(cadena, numero);

dbms_output.put_line('Valores modificados con helloWordCpp.dll');

dbms_output.put_line('Cadena:' || cadena);

dbms_output.put_line('Numero:' || to_char(numero));

end; /

Se imprimen los valores iniciales de las variables y se realiza las llamadas a las funciones, imprimiéndose los parámetros para comprobar que se modifican correctamente.

Ahora lanzamos nuestro test. Primero hay que activar el serveroutput de oracle para que se impriman las variables:

set serveroutput on;

Lanzamos el test:

exec test;

Comprobamos que los cambios se realizan correctamente, viendo el resultado por pantalla en la consola de Oracle. Comprobamos también que se generan los dos archivos de texto en C:\ con el contenido descrito anteriormente.



7. El código fuente

Aquí adjunto el fuente y las dll de windows.



8. Sobre el autor

José Carlos López Díaz, Ingeniero en Informática

mailto:jclopez@autentia.com

Autentia Real Business Solutions S.L - "Soporte a Desarrollo"

A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL: