Obtener Metadatos de Oracle10g

September 4th, 2008

Dentro de una actividad del trabajo, tuve la necesidad de obtener los metadatos de una base de datos (es una tarea muy común: incluso se puede utilizar una interfaz gráfica como SQL Developer o Toad), sin embargo, en esta ocasión necesitaba automatizar el proceso dentro de un procedimiento almacenado dentro de la base de datos.

Para el caso de los procedimientos almacenados se puede utilizar dba_source, pero no funciona para las tablas, y para el resto de los objetos se pueden obtener con vistas del diccionario de datos, o con dbms_metadata.get_ddl.

Ahora bien, dbms_metadata.get_ddl obtiene el DDL de cualquier objeto, sin embargo, lo retorna con su información de almacenamiento (PCTFREE, Tablespace, Segments, etc.) por lo que podría no ser un buen acercamiento si nadamás interesa el metadato (asi como para migrarlo a otra base de datos).

DBMS_METADATA es un paquete muy completo que nos permite facilitar la tarea de obtener los metadatos de cualquier objeto, y tiene la ventaja de que podemos manipular ese metadato para facilitar nuestras tareas.

Primero, utilizamos el método open del paquete para indicarle que vamos a hacer una petición, esta retorna un ID o Handler que utilizaremos en el resto de la rutina:

v_meta_handler := dbms_metadata.open('TABLE');

v_meta_handler es una variable de tipo number que almacena el id de trabajo para el paquete, esto nos permite utilizar el paquete para obtener otros metadatos en otras funciones, incluso trabajando en paralelo; ya que los id’s son independientes.

Ahora, debemos indicarle al paquete “que queremos y como lo queremos” primero, filtramos los objetos que queremos:

dbms_metadata.set_filter(v_meta_handler, 'SCHEMA', 'SYSTEM');
dbms_metadata.set_filter(v_meta_handler, 'NAME', 'EXAMPLE');

Después le indicamos Como lo queremos mediante los métodos: add_transform, set_remap_param y set_transform_param:

v_transform1 := dbms_metadata.add_transform(v_meta_handler,'MODIFY');
dbms_metadata.set_remap_param(v_transform1,'REMAP_SCHEMA','SYSTEM',NULL);
v_transform2 := dbms_metadata.add_transform(v_meta_handler, 'DDL');
dbms_metadata.set_transform_param(v_transform2, 'SQLTERMINATOR', false);
dbms_metadata.set_transform_param(v_transform2,'SEGMENT_ATTRIBUTES',FALSE);

Para cada transformación se requiere especificar un ID de transformación, mas que nada se utiliza para no mezclar los tipos entre la misma operación, y entre operaciones. Primero le decimos que nos agregue una transformación de tipo “MODIFY”, ya que vamos a cambiar el DDL, después le decimos que “remapeamos” el esquema de ‘SYSTEM’ a NULL, esto para que no nos agregue el propietario del objeto (si queremos podemos cambiarlo por cualquier otro, dbms_metadata no valida que exista, solo lo cambia.

La segunda transformación le especifica que lo vamos a trabajar como DDL, anteriormente el paquete lo mantenia en una estructura interna de XML, por lo que se le puede hacer cualquier clase de cambios con un coste mínimo de renidimiento, pero debido a que nos interesa la instrucción, ahora le especificamos que la debe preparar como DDL.

Le especificamos que queremos el caracter de fin de instrucción SQL (”;” o “/” según sea el caso), y le especificamos que quite los atributos de segmento (almacenamiento, ubicación, fragmentación, etc.)

y ya por último, recuperamos la información:

 v_ddls := dbms_metadata.fetch_ddl(v_meta_handler);
  if (v_ddls is not null) then
    v_ddl := v_ddls(1);
    dbms_output.put_line(v_ddl.ddltext);
  end if;

v_ddls es una variable de tipo sys.ku$_ddls, la cual a su ves es una tabla del tipo sys.ku$_ddl, la cual es un tipo definido por el usuario con la estructura:

SQL> desc sys.ku$_ddl;
 Name                                      Null?    Type
 ----------------------------------------- -------- --------------------
 DDLTEXT                                            CLOB
 PARSEDITEMS                                        SYS.KU$_PARSED_ITEMS

El que nos interesa en este momento es DDLTEXT, sin embargo, podemos utilizar PARSEDITEMS para procesar la instrucción y obtener datos granulados de la instrucción DDL (asombroso, ¿no?), esto nos permite incluso alterar cualquier aspecto de la instrucción DDL sin necesidad de escribir programas muy complejos.

 

El código completo, junto con su ejecución es el siguiente:

SQL> declare
  2    v_meta_handler      number;
  3    v_transform1        number;
  4    v_transform2        number;
  5
  6    v_ddls              sys.ku$_ddls;
  7    v_ddl               sys.ku$_ddl;
  8  begin
  9    v_meta_handler := dbms_metadata.open('TABLE');
 10    dbms_metadata.set_filter(v_meta_handler, 'SCHEMA', 'SYSTEM');
 11    dbms_metadata.set_filter(v_meta_handler, 'NAME', 'EXAMPLE');
 12
 13
 14    v_transform1 := dbms_metadata.add_transform(v_meta_handler, 'MODIFY');
 15    dbms_metadata.set_remap_param(v_transform1,'REMAP_SCHEMA','SYSTEM',NULL);
 16
 17    v_transform2 := dbms_metadata.add_transform(v_meta_handler, 'DDL');
 18    dbms_metadata.set_transform_param(v_transform2, 'SQLTERMINATOR', false);
 19    dbms_metadata.set_transform_param(v_transform2,'SEGMENT_ATTRIBUTES',FALSE);
 20
 21    v_ddls := dbms_metadata.fetch_ddl(v_meta_handler);
 22    if (v_ddls is not null) then
 23      v_ddl := v_ddls(1);
 24      dbms_output.put_line(v_ddl.ddltext);
 25    end if;
 26    dbms_metadata.close(v_meta_handler);
 27  end;
 28  /
CREATE TABLE "EXAMPLE"
   (    "FLD1" NUMBER
   )

PL/SQL procedure successfully completed.

sin cosas raras ni mas!, así se puede obtener el DDL de cualquier objeto dentro de una base de datos de ORACLE, para mayor referencia, la página oficial de DBMS_METADATA para Oracle10g es: http://download.oracle.com/docs/cd/B14117_01/appdev.101/b10802/d_metada.htm#ARPLS026

Actualización

July 24th, 2008

Bueno… esto a lo mejor esta muy supérfluo a lo que normalmente escribo, pero lo considero importante (y mas aún para marcarme la meta de personalmente hacerlo), quiero actualizar mi blog!!!

voy a agregar los enláces a blogs muy interesantes, el de hugo y el de karl, que realmente me dejaron impactados con el contenido, de excelente calidad (el de orlando talvez… como es tan “superior” no creo que le haga falta de mi enláce xDD)

voy a poner el blog de los que se que tienen blog, no pongo nombres para no herir suceptibilidades.

voy a poner una nueva máscara para que se vea mas bonito

Voy a reclasificar los temas, ya que a cierto personaje de historieta no le parece como clasifico (e igual a lo mejor le falta una manita de gato)

y a ver que mas le pongo…

Cualquier sugerencia es bienvenida :)

Flota agitada

June 4th, 2008

Pues bien.. ahora que tengo algo de flota decentona, decidi ir a buscar blancos (mas que nada por que se me acaba el deuterio y necesito sacarlo de algún lado), pues bien, encontré a este fulano:

Recursos en memorias de idhun [X:XXX:X] (Jugador ‘alsan’)
a 06-04 18:48:17
Metal: 383.796 Cristal: 188.286
Deuterio: 53.586 Energía: 1.913

No es nada (y de hecho ese fue un espionaje posterior) pero decidi mandarlo a atacar :DDD, el combate fue una carnicería:

(no tengo el informe de batalla… pero les aseguro que fue mortal para el)

Como todo buen jugador, de esos que saben perder, admiten que necesitan mejorar y hasta piden algunos consejos, muy amablemente me envió un mensaje:

06-04 14:35:20 alsan [X:XXX:X] Sin asunto
hola hijo de la grandisima puta

Yo, como soy igual de amable, le di click en “reportar” (digo… para reportar la gran amabilidad de este sujeto para felicitarme por tan audáz ataque)… cual va siendo mi sorpresa que al ver su posición me encuentro con la horrible s de BAN!:

Thu Jun 5 2008 0:18:22 EiMinHa alsan Sun Jun 8 2008 0:18:22 Insulto grave (2º)

Hehehehehe, 4 días de farming! el GO del uni 6 es muy duro (ha baneado a miles de personas), pero almenos estoy seguro de que hace bien su trabajo (yeaaaaahhh!!!!)

Como utilizar OCILIB en Windows

May 16th, 2008

Pues en mi post anterior mencioné esta librería, pues ahora voy a mencionar como poder utilizarla en windows ,y es que debido a que en mi trabajo nos conectamos a muchas redes privadas… y configurar los clientes en linux es un cuete, sobretodo el cliente de checkpoint, que no existe… y las soluciones alternas parecen no llevar a algún lado.

Esta librería depende explícitamente de la OCI de ORACLE (esta viene incluida en la instalación normal de ORACLE), no se si viene en todas… pero yo instalé la enterprise (está en mi laptop y no le aplicaré parches, asi que no importa), los archivos que necesitamos explicitamente son:

%ORACLE_HOME%\OCI\Include\*
%ORACLE_HOME%\OCI\MSVC\oci.lib

Esas las vamos a copiar, respectivamente a nuestro ambiente de MinGW

%MINGW_32%\Include
%MINGW_32%\lib

Ya una vez hecho esto, compilamos con el siguiente par de instrucciones

gcc -c ocilib.c -o ocilib.o
gcc -shared -Wl,-soname,ocilib.dll -o ocilib.dll ocilib.o -loci

Eso nos generará nuestra dll con la que vamos a compilar, recuerden también copiar los respectivos archivos de cabecera a %MINGW_32%/Include

Código abierto… ¿sin soporte? porsupuesto que no

May 16th, 2008

Desde hace días he tenido que estar trabajando con una librería que abstrae las funciones del OCI (Oracle Client Interface) en funciones sencillas escritas en C (http://orclib.sourceforge.net/), el fundador y actual supervisor del proyecto, vincent Rogier, ha mantenido este proyecto y está en una fase de desarrollo y en constante evolución.

Desde el momento en el que solicité ayuda, me la proporcionó de una forma rápida y eficiente, e ncluso me dió algunos “snippets” de código para parchar mi versión de ocilib para lograr lo que necesitaba, icreible es, que mi problema no duró mas de 2 días, teniendo la solución inmediatamente (irónico es, que algunos servicios “profesionales” y que uno paga de help-desk no son tan eficientes, e incluso nisiquiera te llevan a una solución).

Un punto mas a favor de los proyectos de código abierto, su soporte superan a los soportes de las corporaciones que ofrecen paquetes en códigos privados, aqui no solo tuve la ayuda, sino además que en todo momento pude revisar el código, y saber exactamente que estaba haciendo que segmento de código.