Ahora, si bien la compilación condicional fue presentada con Oracle 10g R2, es también posible contar con esta característica en 9i y 10g R1, gracias a la aplicación de patches sobre la base de datos.
En Oracle 10g y superiores
En Oracle 10g ya viene incorporada a partir de la versión 10.1.0.4 y activada por defecto, por lo tanto no debemos hacer nada para comenzar a utilizarla.
En Oracle 9i
Para contar con ella en 9i debemos primero tener instalado el patch 9.2.0.6 o superiores. Luego debemos setear el parámetro indocumentado _plsql_conditional_compilation=TRUE. Este parámetro es del sistema y no es dinámico, por lo que el DBA deberá incluirlo en el archivo de parámetros y reiniciar la instancia.
En Oracle 8i e inferiores
No es soportada.
Una aplicación de la compilación condicional bastante práctica y recomendable es la de hacer que nuestro código PL/SQL compile en cualquier versión, utilizando los features propios de cada release cuando es posible, todo en el mismo código. Esta buena práctica tiene dos objetivos: el primero es hacer que nuestro paquete sea reutilizable (por ejemplo un paquete de funciones de uso general), y el segundo que nuestro código no genere un impacto al momento de migrar de versión.
Un ejemplo de compilación condicional
En este ejemplo, vamos a realizar un procedimiento para hacer un spool de determinadas cuentas que cumplen con un patrón en su código.
La compilación condicional va a entrar en juego con la siguiente lógica:
-Si la base es 9i, ejecuta SQL con invocaciones a SUBSTR para verificar el patrón
-Si la base es 10g, ejecuta SQL con expresiones regulares ya que es más performante
Primero compilamos la especificación de nuestro paquete, que no tiene nada de especial:
CREATE OR REPLACE PACKAGE pack_cuentas
IS
PROCEDURE list_cuentas (p_max IN VARCHAR2);
END pack_cuentas;
/
Luego compilamos el body, donde está la diferencia:CREATE OR REPLACE PACKAGE BODY pack_cuentasLas directivas especiales $IF $THEN $END hacen el truco. Observar que este mismo código se compila en Oracle 9i, donde la función REGEXP_LIKE retornaría un error de compilación, sin embargo el fragmento de código que no corresponde a la versión ni siquiera es analizado por el compilador.
IS
PROCEDURE spool_cuentas (p_max IN VARCHAR2)
IS
BEGIN
$IF DBMS_DB_VERSION.VER_LE_9
$THEN
FOR cue IN (SELECT cod_cuenta FROM cuentas
WHERE activo='Y' AND SUBSTR(cod_cuenta,1,2)='00'
AND SUBSTR(cod_cuenta,3,1) IN ('0','1','2','3')
AND SUBSTR(cod_cuenta,LENGTH(cod_cuenta),-1)='A')
LOOP
dbms_output.put_line(cue.cod_cuenta);
END LOOP;
$ELSE
DECLARE
v_pattern VARCHAR2(20) := '00[0-'||p_max||']-[0-9]+A';
BEGIN
FOR cue IN (SELECT cod_cuenta FROM cuentas
WHERE activo='Y' AND REGEXP_LIKE (cod_cuenta,v_pattern))
LOOP
dbms_output.put_line(cue.cod_cuenta);
END LOOP;
END;
$END
END spool_cuentas;
END pack_cuentas;
/
Para poder diferenciar entre las versiones 9i, 9iR1, 9iR2, 10g, 10gR1 y 10gR2 contamos con el paquete DBMS_DB_VERSION, el cual incluye constantes para cada versión, como la que usé en el ejemplo. En el ejemplo usamos la constante ver_le_9 que implica 'menor o igual a 9i', pero también tenemos para indicar menor o igual a un release como por ejemplo ver_le_9_2.
CREATE OR REPLACE package dbms_db_version is
version constant pls_integer := 10; -- RDBMS version number
release constant pls_integer := 2; -- RDBMS release number
ver_le_9_1 constant boolean := FALSE;
ver_le_9_2 constant boolean := FALSE;
ver_le_9 constant boolean := FALSE;
ver_le_10_1 constant boolean := FALSE;
ver_le_10_2 constant boolean := TRUE;
ver_le_10 constant boolean := TRUE;
end dbms_db_version;
/
Ahora podremos arreglar nuestro viejo código para que sea más eficiente en las versiones siguientes y que no tengamos que hacer cambios al momento de migrar, en definitiva adelantarnos y minimizar el retrabajo en el futuro.
4 comentarios:
Hola,
estoy empezando a trabajar con oracle 9.2 y tengo que cambiar una sentencia que esta en mysql con expresiones
regulares a oracle. La sentencia que tengo que pasar a oracle es la siguiente:
SELECT * FROM prueba WHERE (content REGEXP ?) AND (codigo = ?) AND (nombre = ?) GROUP BY mes
¿Alguien sabe como puedo pasar a oracle esta sentecia?
Muchas gracias.
Laura.
Laura,
Publiqué una nueva entrada en tu honor. Espero que te sea útil la solución.
http://oraclenotepad.blogspot.com/2010/03/expresiones-regulares-en-sql-con-9i.html
Saludos
En el ejemplo la declaración de v_pattern está en el bloque de la versión 9 ($THEN), cuando debería estar en el bloque perteneciente a la versión > 9 ($ELSE). Es alli dónde se emplea la expresión regular.
Saludos.
Corregido. Gracias Roberto!
Saludos
Publicar un comentario