Optimización SQL en Oracle

PL/SQL y ejecuciones en host.

2005-07-20 · Blog

Por un motivo de seguridad, desde PL/SQL no es posible ejecutar llamadas al host. En principio, ningún módulo programado en PL/SQL debería ejecutar nada en sistema operativo. No obstante, seguro que cualquiera es capaz de recordar alguna situación concreta en la que poder invocar un «copy» o quizás ejecutar algún fichero .exe hubiera sido de gran ayuda.

Existe una forma de dar un rodeo a este escenario.

Oracle permite la llamada a procedimientos externos mediante un servicio extproc que debe configurarse en el fichero de alias de servicios «tnsnames.ora» para el cliente, y en el de configuración del listener «listener.ora» en el lado del servidor.

Los ficheros tendrán este aspecto.

Nota: puede haber cambios por la versión del servidor. El ejemplo se implementó sobre Oracle 8.1.7.

Fichero LISTENER.ORA
LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
      )
    )
  )
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC = (SID_NAME = extproc_agent)
      (ORACLE_HOME = E:oracleora92)
      (PROGRAM = extproc)
      (ENVS = «EXTPROC_DLLS=ANY»)

    )
  )

Fichero TNSNAMES.ORA
EXTPROC_CONNECTION_DATA =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = IPC)(Key = EXTPROC)))
    (CONNECT_DATA =
      (SID = extproc_agent)
    )
  )

Con esta parametrización del listener, y la definición de un servicio para llamadas a ‘extproc’, Oracle es capaz de invocar desde PL/SQL librerías externas programadas en C o PASCAL.

Pasos:

      1.- Descarga de un compilador de C++. Este ejemplo utiliza C++Compiler de Borland.
      2.- Creación de un programa en C que ejecuta en S.O. un comando dado.
      3.- Compilación del programa e implementación de las librerías.
      4.- Desde Oracle, creación del objeto LIBRARY (biblioteca).
      5.- Creación de un procedimiento PL/SQL que invoque a una función de esa biblioteca.

Creación del programa shell.c
—————————–
   #include <windows.h>    
   #include <stdio.h>    
   #include <stdlib.h>      

   void __declspec(dllexport) sh(char *);    
   void sh(char *cmd)    
   {    
       system(cmd);    
   }

Compilación del código C y creación de las librerías  .lib y .dll
—————————————————————–
  bcc32 -WD shell.c    
  implib shell.lib shell.dll

Creación del objeto LIBRARY, en la consola de SQL.
————————————————–
SQL> create library shell_lib is ‘C:BorlandBCC55shell.dll’;
  2  /

Biblioteca creada.

De modo que ya es posible crear un procedimiento PL/SQL que referencie externamente a esa librería. Ésta se encargará de ejecutar en host el parámetro que le incluyamos. Por ejemplo, un «copy».
————————————————————————————————–
SQL> create or replace procedure shell (
  2         cmd IN varchar2)
  3  as external
  4       library shell_lib
  5       name «_sh»
  6       language C
  7       parameters (cmd string);

  8  /

Procedimiento creado.

SQL>

El testeo podrá hacerse con un simple ‘exec’ desde SQL*Plus, ya que equivale a «BEGIN shell(‘parametro’); END;»
—————————————————————————————————————
SQL> exec shell(‘copy c:test*.* c:destino’);

Procedimiento PL/SQL terminado correctamente.

Funciona.

← Volver al blog