tag:blogger.com,1999:blog-6230959840389481677.post-74853809322279863782008-03-24T14:51:00.000-07:002008-03-27T11:00:34.591-07:00Compilación condicional en 9iLa compilación condicional permite indicarle al compilador los fragmentos de código que debe compilar en nuestro código PL/SQL, según las condiciones que el programador indique utilizando directivas especiales.<br />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.<br /><br /><strong>En Oracle 10g y superiores</strong><br />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.<br /><br /><strong>En Oracle 9i</strong><br />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 <span style="font-family:courier new;color:#3333ff;">_plsql_conditional_compilation=TRUE</span>. 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.<br /><br /><strong>En Oracle 8i e inferiores</strong><br />No es soportada.<br /><br />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.<br /><br /><strong>Un ejemplo de compilación condicional</strong><br />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.<br />La compilación condicional va a entrar en juego con la siguiente lógica:<br />-Si la base es 9i, ejecuta SQL con invocaciones a SUBSTR para verificar el patrón<br />-Si la base es 10g, ejecuta SQL con expresiones regulares ya que es más performante<br /><br />Primero compilamos la especificación de nuestro paquete, que no tiene nada de especial:<br /><br /><pre><span style="color:#009900;">CREATE OR REPLACE PACKAGE pack_cuentas<br />IS<br /> PROCEDURE list_cuentas (p_max IN VARCHAR2);<br />END pack_cuentas;<br />/</span></pre>Luego compilamos el body, donde está la diferencia:<pre><span style="color:#009900;">CREATE OR REPLACE PACKAGE BODY pack_cuentas<br />IS<br /> PROCEDURE spool_cuentas (p_max IN VARCHAR2)<br /> IS<br /> BEGIN<br /> <span style="color:#3333ff;">$IF DBMS_DB_VERSION.VER_LE_9<br /> $THEN</span><br /> DECLARE<br /> v_pattern VARCHAR2(20) := '00[0-'&#124;&#124;p_max&#124;&#124;']-[0-9]+A';<br /> BEGIN<br /> FOR cue IN (SELECT cod_cuenta FROM cuentas<br /> WHERE activo='Y' AND REGEXP_LIKE (cod_cuenta,v_pattern))<br /> LOOP<br /> dbms_output.put_line(cue.cod_cuenta);<br /> END LOOP;<br /> END;<br /> <span style="color:#3333ff;">$ELSE</span><br /> FOR cue IN (SELECT cod_cuenta FROM cuentas<br /> WHERE activo='Y' AND SUBSTR(cod_cuenta,1,2)='00'<br /> AND SUBSTR(cod_cuenta,3,1) IN ('0','1','2','3')<br /> AND SUBSTR(cod_cuenta,LENGTH(cod_cuenta),-1)='A')<br /> LOOP<br /> dbms_output.put_line(cue.cod_cuenta);<br /> END LOOP;<br /> <span style="color:#3333ff;">$END</span><br /> END spool_cuentas;<br />END pack_cuentas;<br />/</span><br /></pre>Las 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.<br />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 <em>ver_le_9</em> que implica 'menor o igual a 9i', pero también tenemos para indicar menor o igual a un release como por ejemplo <em>ver_le_9_2</em>.<pre><span style="color:#009900;">CREATE OR REPLACE package dbms_db_version is<br /> version constant pls_integer := 10; -- RDBMS version number<br /> release constant pls_integer := 2; -- RDBMS release number<br /> ver_le_9_1 constant boolean := FALSE;<br /> ver_le_9_2 constant boolean := FALSE;<br /> ver_le_9 constant boolean := FALSE;<br /> ver_le_10_1 constant boolean := FALSE;<br /> ver_le_10_2 constant boolean := TRUE;<br /> ver_le_10 constant boolean := TRUE;<br />end dbms_db_version;<br />/</span></pre>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.lferhttp://www.blogger.com/profile/00618392085702183279noreply@blogger.com