Skip navigation

PL/SQL Argentina

September 2017 Previous month Next month
Es común encontrar en nuestras aplicaciones, lugares donde accedemos a tablas o vistas diccionario de datos de Oracle para obtener cierta información, por ejemplo:
SELECT t.table_name
INTO vTabla
FROM user_tables t
WHERE t.table_name like ‘T_%’

El tamaño máximo de los indicadores era, hasta Oracle 12c R2, de 30 caracteres, por lo que es frecuente encontrar que se definía a la variable “vTabla” de la siguiente forma:

DECLARE
     vTabla    VARCHAR2(30);

 

Pero, como ya vimos en el artículo anterior del blog, "Oracle 12c R2 - Identificadores de 128 Bytes", la Release 2 de Oracle 12c nos permite definir indicadores de hasta 128 caracteres de largo, por lo que es probable que nuestras aplicaciones que definían variables para almacenar indicadores con un largo fijo de 30 caracteres muy pronto comiencen a fallar con el siguiente error:

ORA-06502: PL/SQL: numeric or value error: character string buffer too small
Afortunadamente, el cambio  en el tamaño de los indicadores viene acompañado en Oracle 12c R2 de la posibilidad de declarar el largo de variables usando constantes. Por ejemplo, podemos definir un paquete de constantes y especificar en el mismo los valores que deseamos utilizar:
CREATE OR REPLACE PACKAGE pkg_constantes
AS
  --
  cn_largo_identificadores constant pls_integer := 128;
  cn_largo_codigos constant pls_integer := 20;
  cn_largo_cuit constant pls_integer := 11;
  --
END pkg_constantes;
/

Y luego utilizar los mismos al momento de definir variables:
DECLARE
  vNombreTabla VARCHAR2(pkg_constantes.cn_largo_identificadores );
  vCUIT NUMBER(pkg_constantes.cn_largo_cuit);
  vCodigoCliente VARCHAR2(pkg_constantes.cn_largo_codigos);

Para simplificar nuestra tarea, la versión 12c R2 ya provee una constante declarada en el paquete “DBMS_STANDARD” llamada “ORA_MAX_NAME_LEN” la cual representa un valor de 128, por lo que nuestro primer ejemplo puede ser reformulado de la siguiente forma:

DECLARE vTabla  VARCHAR2(ORA_MAX_NAME_LEN);

Ejemplo y documentación adicional

Seguramente, mas de una vez cada desarrollador o administrador de Oracle sufrió un dolor de cabeza al tener que crear un objeto y encontrarse con la limitación de treinta caracteres para los nombres de objetos (identificadores).

 

Por ejemplo, si queríamos correr el siguiente script:

 

CREATE TABLE t_EstadoComprobante
( ID_EstadoComprobante      NUMBER(4)       NOT NULL,
  EstadoComprobante         VARCHAR(50)     NOT NULL );
--
ALTER TABLE t_EstadoComprobante ADD CONSTRAINT PK_EstadoComprobante
    PRIMARY KEY (ID_EstadoComprobante);
--
CREATE TABLE t_Comprobante
( ID_Comprobante            NUMBER(4)       NOT NULL,
  Numero_Comprobante        NUMBER(8)       NOT NULL,
  Fecha_Comprobante         DATE            NOT NULL,
  Monto_Comprobante         NUMBER(12,2)    NOT NULL,
  ID_EstadoComprobante      NUMBER(4)       NOT NULL );
--
ALTER TABLE t_Comprobante ADD CONSTRAINT PK_Comprobante
    PRIMARY KEY (ID_Comprobante);
--
ALTER TABLE t_Comprobante ADD CONSTRAINT FK_Comprobante_EstadoComprobante
    FOREIGN KEY (ID_EstadoComprobante) REFERENCES t_EstadoComprobante (ID_EstadoComprobante);
--

 

Nos encontrábamos con el siguiente mensaje de error.

 

ORA-00972: identifier is too long
00972. 00000 -  "identifier is too long"
*Cause:    An identifier with more than 30 characters was specified.
*Action:   Specify at most 30 characters.

 

La limitación de 30 caracteres obligaba a utilizar abreviaturas para nombrar a identificadores, haciendo poco legibles (y hasta inentendibles) ciertos nombres.

 

Identificadores Largos (hasta 128 bytes) en Oracle 12c R2

La nueva versión de Oracle soporta identificadores de hasta 128 bytes, por lo que de ejecutar el script anterior en una base de datos 12c R2, obtendremos el siguiente resultado:

 

Table created.
Table altered.
Table created.
Table altered.
Table altered.

Si consultamos la estructura de las tablas del diccionario de datos, podemos ver que la mayoria de las columnas de las vistas del diccionario de datos que contienen identificadores ahora tienen un tamaño de 128 bytes:

 

SQL> desc all_tables
Name                                      Null?    Type
----------------------------------------- -------- ----------------------------
OWNER                                     NOT NULL VARCHAR2(128)
TABLE_NAME                                NOT NULL VARCHAR2(128)
TABLESPACE_NAME                                    VARCHAR2(30)
CLUSTER_NAME                                       VARCHAR2(128)
...
...

 

Restricciones y Consideraciones

Los siguientes objetos mantienen sus identificadores con el largo como en versiones anteriores.

  • 8 Bytes
    • Nombre de Base de Datos
  • 30 Bytes
    • Tablespace
    • Disk Group
    • PDBs
    • Rollback Segment

 

Otro aspecto a tener en cuenta es que el nuevo tamaño se mide en Bytes, por lo que si nuestra base de datos tiene un set de caracteres UTF8, cada caracter puede ocupar entre 1 y 3 bytes, por lo que el tamaño máximo en caracteres del identificador puede ser menor, como vemos a continuación:

 

create table tablááááááááááááááááááááááááááááááááááááááááááááááááááááááááááááááá
( Son_67_Caracteres_pero_ocupan_130_bytes int );

ORA-00972: identifier is too long

¿Qué es "PRAGMA DEPRECATE"?

La opción de compilador "PRAGMA DEPRECATE" permite marcar a un elemento PL/SQL como obsoleto. El compilador emite advertencias para usos del pragma DEPRECATE o el de elementos obsoletos.

 

Las advertencias le indican a los usuarios que utilizan un elemento obsoleto que es necesario cambiar el código para tener en cuenta la depreciación.

 

¿Qué objetos se pueden marcar como obsoletos con "PRAGMA DEPRECATE"?

 

Se puede marcar como obsoleto objetos de los siguientes tipos:

 

  • Subprograms
  • Packages
  • Variables
  • Constants
  • Types
  • Subtypes
  • Exceptions
  • Cursors

 

¿Cómo se utiliza?

 

Habilitar las advertencias de compilador

Como primer medida, tenemos que habilitar las advertencias de compilador para poder utilizar este nuevo Pragma. Se puede hacer para las advertencias relacionadas con "PRAGMA DEPRECATE" o bien se puede habilitar para todas las advertencias de compilación.

 

ALTER SESSION SET PLSQL_WARNINGS='ENABLE:(6019,6020,6021,6022)';
ALTER SESSION SET PLSQL_WARNINGS='ENABLE:ALL';

 

Compilar una unidad de programación utilizando ""PRAGMA DEPRECATE"

En el siguiente ejemplo, compilamos un paquete e indicamos que el mismo se encuentra obsoleto al incluir la línea "PRAGMA DEPRECATE" seguida del nombre del paquete.

 

CREATE OR REPLACE PACKAGE pkg_Deprecado AUTHID DEFINER 
AS
  PRAGMA DEPRECATE (pkg_Deprecado);
  --
  PROCEDURE Procedimiento1;
  --
  FUNCTION Funcion1 RETURN NUMBER;
END pkg_Deprecado;

SP2-0808: Package created with compilation warnings

 

Dependiendo de la IDE que utilicemos para desarrollar, la advertencia puede mostrarse en forma automática o tendremos que consultar que tipo de advertencia se ha generado:

 

SQL> SHOW ERRORS 
Errors for PACKAGE PKG_DEPRECADO:

LINE/COL ERROR
-------- -------------------------------------------------------
3/4      PLW-06019: entity PKG_DEPRECADO is deprecated

 

Lo mismo si probamos de marcar como obsoleto sólo a un procedimiento de un paquete:

 

CREATE OR REPLACE PACKAGE pkg_Codigo AUTHID DEFINER
AS
  PROCEDURE Procedimiento1;
  PRAGMA DEPRECATE (Procedimiento1, 'pkg_Codigo.Procedimiento1 deprecado. Utilice pkg_Codigo.Procedimiento2');
  --
  PROCEDURE Procedimiento2;
END;

SP2-0808: Package created with compilation warnings

 

El mensaje de error ahora nos indica que la entidad que se encuentra marcada como obsoleta es el procedimiento "PROCEDIMIENTO1" y no el paquete completo.

 

SQL> SHOW ERRORS
Errors for PACKAGE PKG_DEPRECADO:

LINE/COL ERROR
-------- -------------------------------------------------------
4/3      PLW-06019: entity PROCEDIMIENTO1 is deprecated

 

¿Qué significa cada mensaje de Advertencia?

 

A continuación tenemos la definición oficial de cada uno de los cuatro mensajes de advertencia o error relacionados con "PRAGMA DEPRECATE"

 

Nro. de Advertencia

Significado de la Advertencia

6019

La entidad ha sido marcada como obsoleta y puede ser removida en una versión futura. No utilice esta entidad.

6020

La entidad referenciada ha sido marcada como obsoleta y puede ser removida en una versión futura. No utilice esa entidad. Siga las instrucciones especificadas en la advertencia si están disponibles

6021

Pragma mal ubicado. El pragma DEPRECATE debe seguir en forma inmediata a la declaración de la entidad que esta siendo marcada como obsoleta.Ubique al pragma inmediatamente debajo de la declaración de la entidad que esta siendo marcada como obsoleta

6022

Esta entidad no puede ser marcada como obsoleta. Esta funcionalidad sólo aplica a entidades que se declaran en un Paquete, a especificaciones de tipos o a Procedimientos y Funciones. Elimine el pragma.

 

Advertencia 6019

La advertencia (o error) 6019, como vimos al compilar los dos paquetes anteriores, ocurrirá cada vez que compilemos un objeto que se ecuentra "marcado" como obsoleto con la instrucción "PRAGMA DEPRECATE".

 

Advertencia 6020

La advertencia (o error) 6020 ocurrirá cada vez que compilemos un objeto que referencia a otro que se encuentra "marcado" como obsoleto con la instrucción "PRAGMA DEPRECATE".

 

Siguiendo con el ejemplo anterior, si intentamos compilar un procedimiento que referencia al procedimiento "Procedimiento1" del paquete "pkg_Codigo", obtendremos la advertencia 6020:

 

CREATE OR REPLACE PROCEDURE Usar_Procedimiento_Deprecado
IS
BEGIN
    pkg_codigo.procedimiento1;
END;
/

SP2-0804: Procedure created with compilation warnings

SQL> SHOW ERRORS
Errors for PROCEDURE USAR_PROCEDIMIENTO_DEPRECADO:

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/4      PLW-06020: reference to a deprecated entity: PROCEDIMIENTO1
         declared in unit PKG_CODIGO[3,13].  pkg_Codigo.Procedimiento1
         deprecado. Utilice pkg_Codigo.Procedimiento2

 

Este escenario es el mas útil, ya que una vez que un objeto sea marcado como obsoleto, cualquier usuario que compile cualquier unidad de programación que haga referencia al mismo recibirá la advertencia, pudiendo en ese caso modificar su código para utilizar el código vigente en vez del objeto obsoleto.


Advertencia 6021

La advertencia (o error) 6021 ocurrirá si tratamos de compilar un objeto con una sentencia "PRAGMA DEPRECATE" ubicada en un lugar incorrecto, como podemos ver en el siguiente ejemplo:

 

CREATE OR REPLACE PACKAGE MiPaquete AUTHID DEFINER
AS
--
  PRAGMA DEPRECATE(CalculaTotal);
  --
  CURSOR c_cursor IS SELECT dummy FROM dual;
  --
  PROCEDURE CalculaTotal;
  --
END MiPaquete;
/

SP2-0808: Package created with compilation warnings

SQL> SHOW ERRORS
Errors for PACKAGE MIPAQUETE:

LINE/COL ERROR
-------- -----------------------------------------------------------------
3/10     PLW-06021: PRAGMA DEPRECATE on CALCULATOTAL is misplaced


Advertencia 6022

La advertencia (o error) 6022 indica que estamos tratando de marcar como obsoleto un objeto que no puede ser marcado como obsoleta. Esto puede ocurrir si marcamos como obsoleto un procedimiento o función interna (declarada dentro de otro procedimiento o función), como podemos ver en el siguiente ejemplo:

 

CREATE OR REPLACE PROCEDURE Error6022
IS
  PROCEDURE Error6022_Interno
  IS
    PRAGMA DEPRECATE (Error6022_Interno, 'Error6022_Interno es Obsoleto');
  BEGIN
    DBMS_OUTPUT.PUT_LINE('Probando Error6022_Interno');
  END;
BEGIN
  --
  DBMS_OUTPUT.PUT_LINE('Probando Error6022');
  --
  Error6022_Interno;
  --
END;

Warning: PROCEDURE ERROR6022
Line: 5 PLW-06022: cannot use PRAGMA DEPRECATE on this entity

 

Documentación y ejemplos en Oracle Live SQL

 

¿Que es PL/Scope?

PL/Scope es una herramienta del compilador introducida en Oracle 11g que recopila datos sobre identificadores en el código fuente PL/SQL en tiempo de compilación de unidades de programa. La información recopilada queda disponible en vistas estáticas del diccionario de  datos. Los datos recogidos incluyen información sobre tipos de identificadores, sus usos (declaración, definición, referencia, llamada, asignación) y la ubicación de cada uso en el código fuente de nuestros programas.

 

¿Como se lo habilita?

El parámetro "PLSCOPE_SETTINGS" define el comportamiento de esta herramienta al momento de compilar código PL/SQL. Por defecto, su valor es "IDENTIFIERS:NONE".

 

Una de las nuevas funcionalidades en Oracle 12.2 es la posibilidad de aceptar otras opciones aparte para indicar el tipo de identificador.

 

Sintaxis (en negrita las nuevas opciones de 12.2)

IDENTIFIERS : { ALL | NONE | PUBLIC | SQL | PLSQL }
STATEMENTS  : { ALL | NONE }

Ejemplo

Para habilitar el uso de PL/Scope al momento de compilar, sólo es necesario modificar el parámetro "PLSCOPE_SETTINGS" y crear o modificar una unidad de programación almacenada en la base de datos (procedimiento, función o paquete)

 

 CREATE TABLE t_datos (ID NUMBER(10), Dato VARCHAR(100), Nada VARCHAR(100));
--
ALTER SESSION SET PLSCOPE_SETTINGS='IDENTIFIERS:ALL';
--
CREATE OR REPLACE PROCEDURE PRUEBA_PLSCOPE(p_numerico IN NUMBER)
AS
--
v_numero NUMBER;
v_texto VARCHAR2(30000);
--
BEGIN
   --
   SELECT dummy
   INTO v_texto
   FROM dual;
   --
   SELECT COUNT(*) + p_numerico
   INTO v_numero
   FROM dual;
   --
   INSERT INTO t_datos (ID, Dato)
   VALUES (v_numero, v_texto);
   --
END;
/
DROP TABLE t_datos;

 

¿Cómo se utiliza la información generada por PL/Scope?

Una vez que compilamos una unidad de programación teniendo habilitado PL/Scope, es posible consultar la información generada utilizando las vista estáticas "ALL_IDENTIFIERS" y "ALL_STATEMENTS" ( o sus versiones user_* o dba_*).

 

  SELECT ai.usage_id, ai.usage, ai.type, ai.name, ai.line, ai.col
  FROM ALL_IDENTIFIERS ai
  WHERE ai.object_name = 'PRUEBA_PLSCOPE'
  ORDER BY ai.usage_id;

 

 

  SELECT a_s.usage_id, a_s.type, a_s.line, a_s.col, a_s.text
  FROM ALL_STATEMENTS a_s
  WHERE a_s.object_name = 'PRUEBA_PLSCOPE'
  ORDER BY a_s.usage_id;

 

 

¿Que nuevos tipos de identificadores y sentencias soporta PL/Scope en Oracle 12.2?

Oracle 12c Release 2 incluye los siguientes nuevos tipo de identificadores, antes no tenidos en cuenta por PL/Scope

 

Identificadores

  • ALIAS
  • COLUMN
  • MATERIALIZED VIEW
  • OPERATOR
  • TABLE

Sentencias

  • SELECT
  • UPDATE
  • INSERT
  • DELETE
  • MERGE
  • EXECUTE IMMEDIATE
  • SET TRANSACTION
  • LOCK TABLE
  • COMMIT
  • SAVEPOINT
  • ROLLBACK
  • OPEN
  • CLOSE
  • FETCH

 

¿Dónde se almacena la información generada por PL/Scope?

 

La información que PL/Scope recopila al momento de compilar una unidad de programación, es almacenada en el tablespace SYSAUX.

 

SELECT SPACE_USAGE_KBYTES
FROM V$SYSAUX_OCCUPANTS
WHERE OCCUPANT_NAME='PL/SCOPE';

 

SPACE_USAGE_KBYTES
------------------
              1088

 

Referencias e Información Adicional