diumenge, 2 / setembre / 2007

Una aproximació als objectes

Un dels reptes que presenta un traspàs de coneixement sempre és fer-ho en condicions òptimes amb el termini fixat. És possible, que un dels requeriments sigui haver de reflectir aquelles millores o evolucions del programari que enguany es desenvolupa o manté. En el nostre escenari, es situa en un entorn de pre-producció d'un magatzem de dades que s'està transformant per implantar en l'entorn de producció una solució ETL feta a mida.

El gestor del magatzem corre en una aplicació client-servidor J2EE (Tomcat), que interactua amb Web amb l'suauri i amb JDBC contra una Base de dades Oracle9i. La normalització imposada per l'aplicatiu és XML, i la base de dades està modelada relacionalment. Una capa molt senzilla de PL gestiona les càrregues ETL, en el seu nivell més baix. Un requeriment de la posada en marxa de l'aplicació, era eliminar les configuracions a nivell de base de dades -plataforma independent- i evitar el seu emmagatzematge en la BD.

En entrar en producció la nova solució, totes les metadades estaran gestionades per ella, eliminant la capa actual de la base de dades que s'encarrega de fer-ho. És per tant moment de canvis, on conviuran dos sistemes, el d'implantació i l'heredat. Per afrontar aquest procés amb la màxima garantia d'èxit, i en un termini raonable, necessitarem introduir un protocol per desenvolupar el nou model de base de dades, fent una passa més enllà. Aquest article, tracta doncs, com implantar un model objecte-relacional, on els objectes correspondran amb el nou, i el relacional amb l'heretat.

Si prenem per exemple l'objecte de negoci ALUMNE, aquest estaria constituït per un grup nodrit d'Objectes, dels que en considerem dos: Persona i Residencia; d'Atributs com la universitat, el curs acadèmic, el seu document identitari; i diverses funcionalitats, com el seu constructor i el seu instanciador, etc.

Amb les nostres taules relacionals actuals i els procediments ETL que les carreguen crearem les primeres classes del nostre model objecte-relacional. A cada classe li correspondrà un paquet (PACKAGE) PL, i d'aquesta manera inciarem el desenvolupament del nou model. Fent-ho d'aquesta manera, els nous processos ETL i els vells conviuran en una única estructura lògica. La facilitat de la sobrecàrrega de procediments en un paquet permetrà mantenir els dos models amb el mateix nom, si més no, proporcionant un avantatge pel que fa a l'impacte de les modificacions introduides.

Com hem comentat abans en la definició de l'objecte de negoci Alumnne hi intervenien atributs, com la universitat i el centre al que pertany, el curs acadèmic al que corresponen les dades i el seu document d'identitat validat. I també altres objectes, que en el nostre cas són:
....- Identitat, que emmagatzema les seves dades personals.
....- Residència, que emmagatzema les seves dades residencials.
....- Expedient, que emmagatzema dades acadèmiques.

La seva definició podria ser com la que es mostra en el llistat número 1.

1. Definició de l'objecte de negoci Alumne.


....CREATE TYPE Alumne AS OBJECT(univ VARCHAR2(50),cursacad VARCHAR2(50),dniValidat VARCHAR2(50), Identitat Persona,Residencia Residencial,Expedient Academica );
/


Però jeràrquicament l'objecte Alumne depèn de les classes Persona -objecte Identitat-, Residencial -Residència- i Academica -Expedient-, per tant, les haurem de crear abans, per poder-les instanciar. Per crear llavors l'objecte Alumne, hauríem d'incloure les sentències de creació de tots aquells objectes dels que depèn. Per tant, a nivell d'esquema de base de dades ja tindríem quatre objectes, tal i com es mostra en el llistat número 2

2. Definició sencera de l'objecte Alumne.


..CREATE TYPE Persona AS OBJECT (dni VARCHAR2(50),nomsencer VARCHAR2(250),
..sexe VARCHAR2(50),datanaixement NUMBER,nacionalitat VARCHAR2(50));
/

..CREATE TYPE Residencial AS OBJECT (dataresidencia DATE,poblacio VARCHAR2(50),
....municipi VARCHAR2(50),provincia VARCHAR2(50),codipostal VARCHAR2(50),
....poblacio VARCHAR2(50), estat VARCHAR2(50));
/
..CREATE TYPE Academica AS OBJECT(origen VARCHAR2(50),cursacad INTEGER,
..identificador VARCHAR2(50),valor VARCHAR2(50));
/
..CREATE TYPE Alumne AS OBJECT(univ VARCHAR2(50),cursacad VARCHAR2(50),
..dniValidat VARCHAR2(50), ..Identitat Persona,Residencia Residencial,
..Expedient Academica );
/


Si volem emmagatzemar les dades que processa l'objecte haurem de definir una estructura en la base de dades per que ho faci. Ho farem de tal manera que les funcions membres bàsiques que hem de disposar són la sentència de creació, la sentències d'actualització, esborrat i inserció de registres, i la de la seva eliminació. Aquesta estructura serà parella en tots els objectes dels que volguem emmagatzemar dades en la BD.

3. Definició d'útils auxiliars necessaris per als subprogrames de qualsevol objecte.


..CREATE TYPE Columnes is TABLE OF VARCHAR2(4000);
../
..CREATE TYPE StoreDWH is TABLE OF VARCHAR2(80);
../

..CREATE PACKAGE Utl_Objecte AS
..-- Estructures
....PROCEDURE elimina_taula(nom_taula, camps Columnes);
....PROCEDURE crea_taula(nom_taula VARCHAR2,camps Columnes,clausula_storage StoreDWH);
..-- Dades
....PROCEDURE actualitza_taula(nom_taula VARCHAR2,camps Columnes, valors Columnes);
....PROCEDURE esborra_taula(nom_taula VARCHAR2,camps Columnes, valors Columnes);
....PROCEDURE insereix_taula(nom_taula VARCHAR2,camps Columnes, valors Columnes);
..-- Enregistrament
....PROCEDURE fes_log(Proces Varchar2, Procedure Varchar2,Missatges Varchar2);

..END Utl_Objecte;
../
......CREATE PACKAGE BODY Utl_Objecte AS
....PROCEDURE elimina_taula (
......nom_taula VARCHAR2,camps Columnes
....) IS
......vProces Varchar2(30):='';
......vProcedure Varchar2(30):= 'ELIMINA_TAULA';
......vMissatge Varchar2(4000);
......vRol Varchar2(50);
......ErrorProc Exception;
......vSQL Varchar2(32767);
......vCompta Integer;
....BEGIN
......vRol:=pkg_Conf.c_Estat;
......vMissatge :=vRol||'#'||'Iniciant execució';
......FES_LOG(vProces,vProcedure,vMissatge);
......vRol:=pkg_Conf.c_Info;
......EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects where name='''||
........nom_taula' INTO vCompta;
......If vCompta =0 Then
........vMissatge := vRol||'#'||'La taula '||nom_taula||' NO existeix o NO és accessible.';
........FES_LOG(vProces,vProcedure,vMissatge);
........Raise ErrorProc;
........End If;
........EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_tab_columns where table_name=''''||
........nom_taula||' and column_name in ('||TRACTA_COL_WHERE(camps)||')' INTO vCompta;
........If vCompta <> OBTE_NUM_COL(camps) Then
..........vMissatge := vRol||'#'||'La taula '||nom_taula||' existeix, però no té la mateixa estructura.';
..........FES_LOG(vProces,vProcedure,vMissatge);
..........Raise ErrorProc;
.........End If;
vSQL := 'DROP TABLE '||nom_taula:
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects where name='''||
nom_taula' INTO vCompta;
If vCompta > 0 Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' no s'ha eliminat.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
End If;
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||'Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END elimina_taula;

PROCEDURE crea_taula(
nom_taula VARCHAR2,camps Columnes,clausula_storage StoreDWH
) IS
vProces Varchar2(30):='';
vProcedure Varchar2(30):= 'CREA_TAULA';
vMissatge Varchar2(4000);
vRol Varchar2(50);
ErrorProc Exception;
vSQL Varchar2(32767);
vCompta Integer;
BEGIN
vRol:=pkg_Conf.c_Estat;
vMissatge :=vRol||'#'||'Iniciant execució';
FES_LOG(vProces,vProcedure,vMissatge);
vRol:=pkg_Conf.c_Info;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects where name='''||
nom_taula' INTO vCompta;
If vCompta =0 Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' NO existeix o NO és accessible.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
vSQL := 'CREATE TABLE '||nom_taula||' ('||TRACTA_CREATE(camps)||' '||clausula_storage:
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects where name='''||
nom_taula' INTO vCompta;
If vCompta > 0 Then
vMissatge:= vRol||'#'||'La taula '||nom_taula||' NO s'ha creat, o NO és accessible.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
End If;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_tab_columns where table_name=''''||
nom_taula||' and column_name in ('||TRACTA_COL_WHERE(camps)||')' INTO vCompta;
If vCompta <> OBTE_NUM_COL(camps) Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' existeix, però no té la mateixa estructura.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||'Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END crea_taula;

PROCEDURE esborra_taula (
nom_taula VARCHAR2,camps Columnes,valors Columnes
) IS
vProces Varchar2(30):='';
vProcedure Varchar2(30):= 'ESBORRA_TAULA';
vMissatge Varchar2(4000);
vRol Varchar2(50);
ErrorProc Exception;
vSQL Varchar2(32767);
vCompta Integer;
BEGIN
vRol:=pkg_Conf.c_Estat;
vMissatge:= vRol||'#'||'Iniciant execució';
FES_LOG(vProces,vProcedure,vMissatge);
vRol:=pkg_Conf.c_Info;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects where name='''||
nom_taula' INTO vCompta;
If vCompta = 0 Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' NO existeix, o NO és accessible.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_tab_columns where table_name=''''||
nom_taula||' and column_name in ('||TRACTA_COL_WHERE(camps)||')' INTO vCompta;
If vCompta <> OBTE_NUM_COL(camps) Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' existeix, però no té la mateixa estructura.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
vSQL := 'DELETE FROM '||nom_taula|| (||TRACTA_DELETE(camps,valors)||')';
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
COMMIT;
vMissatge:= vRol||'#'||' Executat: '||vSQL;1
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||': Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END esborra_taula;

PROCEDURE actualitza_taula (
nom_taula VARCHAR2,camps Columnes, Valors Columnes
) IS
vProces Varchar2(30):='';
vProcedure Varchar2(30):= 'ACTUALITZA_TAULA';
vMissatge Varchar2(4000);
vRol Varchar2(50);
ErrorProc Exception;
vSQL Varchar2(32767);
vCompta Integer;
BEGIN
vRol:=pkg_Conf.c_Estat;
vMissatge:= vRol||'#'||'Iniciant execució';
FES_LOG(vProces,vProcedure,vMissatge);
vRol:=pkg_Conf.c_Info;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects where name='''||
nom_taula' INTO vCompta;
If vCompta = 0 Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' NO existeix, o NO és accessible.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_tab_columns where table_name=''''||
nom_taula||' and column_name in ('||TRACTA_COL_WHERE(camps)||')' INTO vCompta;
If vCompta <> OBTE_NUM_COL(camps) Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' existeix, però no té la mateixa estructura.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
vSQL := 'UPDATE '||nom_taula|| (||TRACTA_UPDATE(camps,valors);
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
COMMIT;
vMissatge:= vRol||'#'||' Executat: '||vSQL;1
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||': Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END actualitza_taula;

PROCEDURE insereix_taula (
nom_taula VARCHAR2,camps Columnes, valors Columnes
) IS
vProces Varchar2(30):='';
vProcedure Varchar2(30):= 'INSEREIX_TAULA';
vMissatge Varchar2(4000);
vRol Varchar2(50);
ErrorProc Exception;
vSQL Varchar2(32767);
vCompta Integer;
BEGIN
vRol:=pkg_Conf.c_Estat;
vMissatge:= vRol||'#'||'Iniciant execució';
FES_LOG(vProces,vProcedure,vMissatge);
vRol:=pkg_Conf.c_Info;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects where name='''||
nom_taula' INTO vCompta;
If vCompta = 0 Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' NO existeix, o NO és accessible.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_tab_columns where table_name=''''||
nom_taula||' and column_name in ('||TRACTA_WHERE(camps)||')' INTO vCompta;
If vCompta <> OBTE_NUM_COL(camps) Then
vMissatge := vRol||'#'||'La taula '||nom_taula||' existeix, però no té la mateixa estructura.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
vSQL := 'INSERT INTO '||nom_taula|| (||TRACTA_COL_WHERE(camps)||')'||
TRACTA_INSERT(valors);
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
COMMIT;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||': Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END insereix_taula;

PROCEDURE fes_log (
Proces VARCHAR2, Procedure VARCHAR2,Missatges VARCHAR2
) IS PRAGMA AUTONOMOUS TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'Insert into '||pkg_Conf.c_Log_Proc||' VALUES(''''||
to_char(Sysdate,'yyyymmddhh24missff')||''',''''||Proces||''',''''||Procedure||''','''||Missatge||''')';
COMMIT;
EXCEPTION
When Others Then
Raise;
END fes_log;

END Utl_Objecte;
/

Anem a pams, i analitzem aquest últim llistat, el número 3, per entendre què és el que estem fent. En primer lloc definim dos tipus nous, l'un per a crear les columnes -el tipus Columnes- de la taula, i llurs valors que poden prendre, ja siguin constants, o consultes SQL dinàmiques , i l'altre - el tipus SotorageDWH- per a especificar una clàusula d'emmagatzematge determinada (freqüent en tots els entorns) per a cada tipus de taula.

Una vegada creats aquests dos tipus, creem un Paquet PL (Package), per incloure els subprogrames que més endavant utilitzarem per crear els objectes de negoci, i manipular-los. Aquestes funcionalitats són bàsicament, la seva creació i eliminació, i l'actualització, esborrat i inserció de les dades que processen, en taules de la BD. En empaquetar els procediments, normalitzem la seva definició per a la resta d'objectes de l'esquema que crearem tot seguit simplificant el seu desenvolupament i sobretot, el seu manteniment.

La definició de qualsevol objecte, es pot fer ara, de forma molt més simple, genèrica i normalitzada, tal i com es mostra en el llistat número 4.

4. Definició del Paquet PL de l'Objecte de Negoci Persona

CREATE TYPE Persona AS OBJECT (dni VARCHAR2(50),nomsencer VARCHAR2(250),
sexe VARCHAR2(50),datanaixement NUMBER,nacionalitat VARCHAR2(50));
/
CREATE PACKAGE Persona AS
PROCEDURE elimina_persones(vProces VARCHAR2);
PROCEDURE crea_persones(vProces VARCHAR2);
PROCEDURE actualitza_persones(nom_taula VARCHAR2,camps Columnes);
PROCEDURE esborra_persones(nom_taula VARCHAR2,camps Columnes, valors Columnes);
PROCEDURE insereix_persones(nom_taula VARCHAR2,camps Columnes, valors Columnes);
END Persona;
/

El cos del paquet Persona, seguint les directrius marcades, cridarà doncs a les utilitats que hem creat en el paquet UTL_Objecte a tal efecte. Aquesta directiva s'aplicarà a tots els objectes de negoci, per tal de simplificar el desenvolupament i minimitzar el temps emprat en la introducció de modificacions. Si canviem la manera de crear i manipular els objectes, només haurem de modificar el paquet UTL_Objecte, i en el cas d'introduir noves variables, les crides que es facin en la resta de paquets.

De tota manera, una altra aproximació seria la de separar els procediments que creen les estructures en un paquet separat, per tal distingir entre l'administració de l'objecte i la seva manipulació de la següent manera:

6. Definició del Paquet PL d'administració - construcció de les estructures- de l'Objecte de Negoci Persona.

CREATE PACKAGE Constructor_Persona AS
..PROCEDURE crea_tipus_persona;
..PROCEDURE elimina_tipus_persona;
..PROCEDURE crea_paquet_persona;
..PROCEDURE elimina_paquet_persona;
..PROCEDURE crea_Persona;
END Constructor_Persona;
/

En aquest cas, el procediment crea_persona del Paquet cridaria als procediments crea_tipus_persona i crea_paquet_persona, sent el constructor. El cos del paquet Constructor_Persona podria ser com el que es mostra en el llistat número 6.

7. Cos del Paquet PL de construcció de l'Objecte de Negoci Persona.

CREATE PACKAGE BODY Constructor_Persona AS

..PROCEDURE crea_tipus_persona IS
....vProces Varchar2(30):='';
....vProcedure Varchar2(30):= CREA_TIPUS_PERSONA';
....vMissatge Varchar2(4000);
....vRol Varchar2(50);
....ErrorProc Exception;
....vSQL Varchar2(32767);
....vCompta Integer;
..BEGIN
....vRol:=pkg_Conf.c_Estat;
....vMissatge:= vRol||'#'||'Iniciant execució';
....FES_LOG(vProces,vProcedure,vMissatge);
....vRol:=pkg_Conf.c_Info;
....EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
....where name=''PERSONA''' INTO vCompta;
....If vCompta > 0 Then
vMissatge := vRol||'#'||'Eliminant el Tipus PERSONA.';
FES_LOG(vProces,vProcedure,vMissatge);
End If;
vSQL:='CREATE TYPE Persona AS OBJECT (dni VARCHAR2(50),'||
'nomsencer VARCHAR2(250),sexe VARCHAR2(50),datanaixement NUMBER,'||
'nacionalitat VARCHAR2(50))';
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
where name=''PERSONA''' INTO vCompta;
If vCompta > 0 Then
vMissatge:= vRol||'#'||'El Tipus PERSONA NO s'ha creat, o NO és accessible.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||'Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END crea_tipus_persona;

PROCEDURE elimina_tipus_persona IS
vProces Varchar2(30):='';
vProcedure Varchar2(30):= 'ELIMINA_TIPUS_PERSONA';
vMissatge Varchar2(4000);
vRol Varchar2(50);
ErrorProc Exception;
vSQL Varchar2(32767);
vCompta Integer;
BEGIN
vRol:=pkg_Conf.c_Estat;
vMissatge:= vRol||'#'||'Iniciant execució';
FES_LOG(vProces,vProcedure,vMissatge);
vRol:=pkg_Conf.c_Info;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
where name=''PERSONA''' INTO vCompta;
If vCompta = 0 Then
vMissatge:= vRol||'#'||'El Tipus PERSONA NO existeix, o NO és accessible.';
FES_LOG(vProces,vProcedure,vMissatge);
End If;
vSQL:='DROP TYPE Persona';
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
where name=''PERSONA''' INTO vCompta;
If vCompta > 0 Then
vMissatge:= vRol||'#'||'El Tipus PERSONA NO s'ha eliminat, o existeix en un altre ';
vMissatge:= vMissatge||' esquema.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||'Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END elimina_tipus_persona;

PROCEDURE crea_paquet_persona IS
vProces Varchar2(30):='';
vProcedure Varchar2(30):= CREA_PAQUET_PERSONA';
vMissatge Varchar2(4000);
vRol Varchar2(50);
ErrorProc Exception;
vSQL Varchar2(32767);
vCompta Integer;
BEGIN
vRol:=pkg_Conf.c_Estat;
vMissatge:= vRol||'#'||'Iniciant execució';
FES_LOG(vProces,vProcedure,vMissatge);
vRol:=pkg_Conf.c_Info;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
'where name=''PERSONA'' and type=''PACAKGE'''' INTO vCompta;
If vCompta > 0 Then
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
'where name=''PERSONA'' and type=''PACAKGE BODY'''' INTO vCompta;
If vCompta > 0 Then
elimina_paquet_persona;
End If;
End If;
vSQL:= 'DROP PACKAGE PERSONA';
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
vSQL:= 'CREATE PACKAGE Persona AS '||
'PROCEDURE actualitza_persones(nom_taula VARCHAR2,camps Columnes);'||
'PROCEDURE esborra_persones(nom_taula VARCHAR2,camps Columnes, valors Columnes);'||
'PROCEDURE insereix_persones(nom_taula VARCHAR2,camps Columnes, valors Columnes);'||
'END Persona';
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
'where name=''PERSONA'' and type=''PACAKGE'''' INTO vCompta;
If vCompta = 0 Then
vMissatge := vRol||'#'||'La definició del Paquet PERSONA NO s''ha creat, o NO és accessible.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
...
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
'where name=''PERSONA'' and type=''PACAKGE BODY'''' INTO vCompta;
If vCompta > 0 Then
EXECUTE IMMEDIATE 'select status from all_objects'||
where name=''PERSONA'' and type=''PACAKGE'' and status=''VALID'''' INTO vCompta;
If vCompta = 0 Then
vMissatge := vRol||'#'||'El Paquet PERSONA, s''ha creat en estat INVALID.';
FES_LOG(vProces,vProcedure,vMissatge);
End If;
End If;
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||'Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END crea_paquet_persona;

PROCEDURE elimina_paquet_persona IS
vProces Varchar2(30):='';
vProcedure Varchar2(30):= 'ELIMINA_TIPUS_PERSONA';
vMissatge Varchar2(4000);
vRol Varchar2(50);
ErrorProc Exception;
vSQL Varchar2(32767);
vCompta Integer;
BEGIN
vRol:=pkg_Conf.c_Estat;
vMissatge:= vRol||'#'||'Iniciant execució';
FES_LOG(vProces,vProcedure,vMissatge);
vRol:=pkg_Conf.c_Info;
vSQL:='DROP PACKAGE Persona';
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
EXECUTE IMMEDIATE 'select nvl(count(*),0) from all_objects '||
where name=''PERSONA''' INTO vCompta;
If vCompta > 0 Then
vMissatge:= vRol||'#'||'El Tipus PERSONA NO s'ha eliminat.';
FES_LOG(vProces,vProcedure,vMissatge);
Raise ErrorProc;
End If;
vSQL:='DROP PACKAGE BODY Persona';
vMissatge:= vRol||'#'||' Executant: '||vSQL;
EXECUTE IMMEDIATE vSQL;
vMissatge:= vRol||'#'||' Executat: '||vSQL;
vRol:=pkg_Conf.c_Estat;
vMissatge := vRol||'#'||'Execució finalitzada';
FES_LOG(vProces,vProcedure,vMissatge);
EXCEPTION
When ErrorProc Then
vEstat:=pkg_Conf.c_Avis;
vMissatge:=vRol||'#'||'Finalitzada execució';
FES_LOG(vProces,vProcedure,vMissatge);
When Others Then
vEstat:=pkg_Conf.c_Error;
vMissatge:= vRol||'#'||substr(SQLERRM,1,200);
FES_LOG(vProces,vProcedure,vMissatge);
Raise;
END elimina_paquet_persona;

END Constructor_Persona;
/

Cal destacar que el codi del llistat número 7, és a títol d'exemple, i que el constructor de l'Objecte de Negoci Persona, hauria d'avaluar si les seves dependències existeixen per evitar errors de creació o compilació del paquet en temps d'execució. També és interessant destacar, que en general, les sentències d'avaluació d'existència, creació i eliminació d'objectes d'esquema acostumen a definir-se en funcionalitats separades, tal i com havíem comentat anteriorment, i que en el llistat número 7, s'executen directament des del propi paquet.

El següent pas, seria definir els paquets PL de construcció de tots els objectes d'esquema de base de dades necessaris per crear l'Objecte de Negoci Alumne. En un proper article, veurem com tractar les sentències del llenguatge DML dels objectes d'esquema per tal de finalitzar el nostre Objecte de Negoci Alumne.

Concloent, en desenvolupar un Paquet PL per crear l'Objecte de Negoci i un altre per manipular-lo, estem separant les sentències SQL de definició -DDL Data Definition Language- i de manipulació -DML Data Manipulation Language- de forma separada, optimitzant la seva gestió i el seu manteniment.