PL SQL dinámico

Consiste en la ejecución de sentencias SQL o bloques PL/SQL a partir de una cadena de texto montadas de manera dinámica.

El uso de execute immediate es muy cómodo para la construcción de sql dinámicos el problema es el parseo de estas sentencias. Las bind variables, evita parseos inecesarios. Para evitar SQL Injection en PL/SQL dinámico es importante utilizar bind variables en vez de concatenación de cadenas.

VENTAJAS:

  • Creación de sentencias en tiempo de ejecución
  • Interactivo con el usuario
  • Acceder a objetos no existentes en tiempo de compilación
  • Gestión de permisos de usuarios de forma dinámica
  • Permite ejecutar instrucciones DDL (create, alter, drop, grant, …)

DESVENTAJAS:

  • No siempre se forman las consultas más optimas
  • Problemas de seguridad por ataques de inyección SQL

SINTAXIS:
EXECUTE IMMEDIATE es el sustituto del paquete DBMS_SQL

EXEC SQL EXECUTE IMMEDIATE cadena_txt 
          [INTO {variable, ...|registro}]
          [USING {IN|OUT|INOUT} argumento ...]
          [{RETURNING|RETURN} INTO argumento, ...]

cadena_txt: instrucción SQL o bloque PL/SQL
variable: variable donde se guarda el valor de la columna seleccionada
registro: variable estructurada, en la que se obtiene una fila

EJEMPLOS:

Ejemplo de update utilizando bind variables:

DECLARE
   reg_actualizados NUMBER;
   sql_str VARCHAR2(100);
   nombre VARCHAR2(20) := 'Pepe';
   codigo NUMBER(5) := 5;

BEGIN
   sql_str := 'UPDATE DATOS SET NOMBRE = :nombre '
           ||' WHERE CODIGO = :codigo';
   EXECUTE IMMEDIATE sql_str USING nombre, codigo;
   reg_actualizados := SQL%ROWCOUNT;
   dbms_output.put_line('Se han actualizado '||TO_CHAR(reg_actualizados)||' registros');
END;

Ejemplo utilización en cursores utilizando bind variables:

DECLARE
   TYPE cur_typ IS REF CURSOR;
   c_cursor    CUR_TYP;
   fila nombres%ROWTYPE;
   v_query     VARCHAR2(255);
   co_nombre   VARCHAR2(3) := 'JDF';

BEGIN
   v_query := 'SELECT * FROM nombres WHERE co_nombre = :cnombre';
   OPEN c_cursor FOR v_query USING co_nombre;
   LOOP
     FETCH c_cursor INTO fila;
     EXIT WHEN c_cursor%NOTFOUND;
     dbms_output.put_line(fila.DESCRIPCION);
   END LOOP;
   CLOSE c_cursor;
END;

Comments are closed.