diumenge, 14 / juny / 2009

Miopía de Mercado

A mi entender existen importantes incongruencias en esta aportación que caben destacar.


http://ienrmarketing.blogspot.com/2009/05/desaparecen-las-4-ps-del-marketing.html

En primer lugar, entiendo que las empresas no se han visto en la necesidad de trasladar sus acciones de marketing a la red, sino que han incorporado este canal como uno más para llegar a sus clientes potenciales, sin que ello suponga dejar de utilizar los canales convencionales. No con ello, descartamos a aquellas empresas que utilizan exclusivamente internet como canal.


En segundo lugar, si las empresas utilizan la red para captar a los consumidores potenciales -un nicho relativamente pequeño, en crecimiento, pero aún pequeño-, decir que la "p" desaparece, es absurdo, -incluso en la red- se persigue una acción de compra y "Comprar consiste siempre en cambiar las mil satisfacciones potenciales que contiene una suma de dinero, por una única serie de satisfacciones, las que contiene el producto" (M. Joannis,1969). Es el precio precisamente una de las claves de la estrategia de la compra a través de internet. La afirmación de que los servicios ofertados son gratuitos carece de sentido, puesto que persiguen un objetivo concreto, como es la promoción y fidelización de la marca, entre muchos otros.


En tercer lugar afirmar que las principales lecciones del marketing que se enseñan en la Universidad hayan ido desapareciendo, es de un rigor más bien escaso y carente de documentación. A título de ejemplo y como ejercicio básico previo a la publicación de cualquier contenido, recomiendo revisar los temarios que se imparten actualmente, en IESE o ESADE, etc.


En cuarto lugar, en el placement, no sólo influye el buscador, el "portal" constituye un elemento vital, una vez que el consumidor potencial haya accedido a él. A fin de cuentas, no deja de ser un punto de venta, con sus propias características e idiosincrasia.


En quinto lugar, Si entendemos "la publicidad como la creación de ideas al servicio de la comunicación persuasiva es decir, destacar la diferencia, asombrar, sorprender i seducir, dotando de un valor añadido a productos, servicios o personas mediante la palabra, la imagen y el sonido" (J. Mª Ricarte, 1992), ¿Qué patrón ha cambiado, por el mero hecho de utilizar internet como medio?


Y en último lugar, establecer la diferencia existente entre mercadeo directo y promoción de ventas, siempre ha sido tarea difícil para el neófito. En pocas y breves palabras: el marketing directo es una acción de venta, la promoción es un incentivo a la misma, por mucho que nuestro estimado J. R. Zapatero afirme semejante despropósito, como lo es además, el confundir publicidad y editorial.


Tres grans mancances impedeixen a Europa ser una gran potència: profunditat estratègica, de recursos naturals i de visió.

Viacheslav Nikonor

dijous, 7 / maig / 2009

Gestió Automàtica de Documents I

Abstracte
L'Organització es troba davant un repte important: en el darrer informe de situació sobre el sistema de gestió documental s'ha constatat que en el decurs del darrer any, només s'ha procedit a l'enregistrament digital d'una tercera part dels documents que s'han generat en l'arxiu físic.

Aquest escenari implica una pèrdua important d'informació vital i de coneixement, que rau en les estacions de treball dels col·laboradors en lloc del servidor.

En el context del projecte de digitalització de documents i comunicats, iniciat amb la implantació del sistema de gestió documental, aquest no sols no ha aconseguit la fita establerta en l'aspecte administratiu, sinó que a més, ha esdevingut una important despesa de recursos econòmics i humans.

En el context de l'operativa, suposa una gran pèrdua de coneixement, doncs, tota aquesta informació ha de ser en molts casos generada de nou, degut a l'escasa efectivitat que suposa haver de gestionar físicament tota aquesta informació o per la poca cura en l'aplicació dels procediments normals de gestió d'un arxiu, sense responsable aparent.

La direcció ens demana una proposta que recondueixi la situació i que aconsegueixi que en un termini de tres mesos dues terceres parts dels documents generats per l'organització siguin dins del servidor.


Primera aproximació
Els factors que condicionen l'escenari actual, a part de la política de l'organització, són:

  • Els col·laboradors són externs i el temps destinat a tasques administratives, com l'arxiu de documents, no se'ls retribueix.
  • Els col·laboradors tracten de protegir el seu coneixement, com a eina de pressió vers la direcció.
  • Els col·laboradors treballen en local i no en el servidor.
  • El sistema de gestió documental només s'ajusta a les necessitats d'algunes unitats de negoci de l'organització.
  • El correu electrònic no està integrat en el sistema de gestió documental.
  • La integració amb el programari ofimátic és deficient.

En aquest context cal dissenyar una solució tecnològica que incorpori forçosament un automatisme d'arxiu de documents que a més integri el correu electrònic i el programari ofimàtic.


Situació actual
El sistema de gestió documental està constituït per tres bases de dades que comparteixen les quatre unitats de negoci, una d'elles administració, que formen l'organització, ubicades en un únic servidor :
  • documents
  • clients / projectes
  • històric

El correu corporatiu també està ubicat en el mateix servidor, el que implica una càrrega de treball desmesurada, que justifica la posició del col·laborador, a l'hora de procedir a l'arxiu de documents.

NOTA: En la recent renovació del parc informàtic que va dur a terme l'organització, el sistema de fitxers -documents- i el de gestió documental - correu electrònic corporatiu es van separar en dos servidors de prestacions idèntiques. Eliminant doncs d'aquesta manera, segons la direcció, la principal argumentació dels col·laboradors per no utilitzar-lo de forma habitual.

El programari ofimàtic està instal·lat en cada estació de treball, però està actualitzat després de la renovació de tot el parc tecnològic, però no s'ha pogut integrar correctament en migrar de versió el sistema de gestió documental.

Els documents s'organitzen seguint els següents criteris:
  • unitat de negoci
  • any
  • client / projecte
  • tipus de document
  • autor
  • estat

Malgrat es disposi d'un servidor potent i dedicat, el fet de compartir una única base de dades de documents suposa embuts importants -per concurrència- en alguns moments del dia, especialment abans de la pausa pera anar a dinar i al final de la jornada laboral habitual.

D'altra banda, l'accés als documents es feixug, per dues raons fonamentals:
  • Quan s'accedeix a un document, encara que sigui en la modalitat de consulta, aquest roman blocat per a la resta d'usuaris.
  • Els usuaris tenen el costum de gestionar els documents com si fossin propis, en lloc de pensar en grup. En altres paraules, no hi ha esperit de col·laboració entre les diferents unitats de negoci.
Per lo que la solució adoptada per la direcció no satisfà la necessitat real dels col·laboradors, i aquests no mantenen una actitud pròpia d'un entorn col·laboratiu.


Una organització que no col·labora, està condemnada al fracàs.
La nostra primera actuació ha de ser forçosament en l'àmbit dels recursos humans. Si no tenim la complicitat dels clients -prefereixo aquest terme, al d'usuari- no aconseguirem els nostres objectius.

El nostre primer esforç es centra, en establir un clima de col·laboració entre les diferents unitats de negoci, però topa de front amb la direcció de l'organització: si s'estableix una col·laboració molt estreta entre tots, la pressió que podran exercir podrà esdevenir molt gran i en aquesta separació es fonamenta la política laboral de l'organització.

En no poder mantenir reunions o grups de treball en els que participin totes les unitats de negoci, el procés d'implantació d'una solució serà lent i feixug. Poc eficient.

No podem establir i imposar una normativa d'ús del sistema, requeriment obligat de la implantació de la LOPD en una organització com la tractada per raons laborals òbvies, que no citarem per raons també, òbvies.

Per tant, haurem doncs de motivar als col·laboradors a que actuin com a tals, i forçar -de manera que no se n'adonguin- progressivament la implantació d'una normativa d'ús del sistema de gestió documental.

Aquesta actuació es durà a terme des de l'àrea de suport, la que està en contacte directa amb els clients.

En general, els clients -especialment els que pertanyen a professionals lliberals- mantenen una posició dominant vers el personal tècnic, al que considera un ajudant poc qualificat causant dels problemes tecnològics que pateixen. Aquesta afirmació, sustentada en anys d'experiència, ens condueix a que el client no és conscient que gran part dels problemes tecnològics que pateix, els provoca ell mateix.

La nostra estratègia s'ha de centrar en la conscienciació d'aquells elements de l'organització que poden frenar la implantació d'una normativa d'ús, o bé perque tenen poder -ocupen una jerarquia en l'organització- o perque són líders d'un grup d'opinió -lideren a un grup d'elements de l'organització per raons sociològiques.

diumenge, 26 / abril / 2009

Donant forma a les idees: El procés creatiu

El procés creatiu, la creativitat
Em citat anteriorment, que en la etapa 2 s’iniciava el procés creatiu. I hom pot deduir amb facilitat que el procés creatiu, deriva de la creativitat. Ara bé, què ¿s'entén per creativitat o creatiu?¿Quines poden ser les notes que defineixin la creativitat, i per extensió, el pensament creatiu? Paul Torrance1, comenta que analitzant una llista de les característiques o termes d’aprenentatge creatiu–en un termini màxim de cinc minuts- elaborada per dos-cents alumnes, havia validat fins a dos cents trenta indicadors.

Matthew Lipman considera que "aquells termes que em venen més ràpidament a la ment i sense cap ordre en particular són la originalitat, la novetat, la generativitat, la singularitat, la productivitat, la capacitat de ruptura, la capacitat de sorpresa, d'invenció, la qualitat alliberadora, l’espontaneïtat, la imaginació, la inspiració i la capacitat de síntesi. Aquests termes han de ser analitzats per a determinar fins a quin punt són senzillament sinònims del pensament creatiu o bé criteris del mateix".
2

El pensament creatiu
En aquest context, el que sí s'observa es el comú denominador de les definicions o característiques de la creativitat i/o el pensament creatiu, la creació d'una cosa nova i a més, en certa mesura, un element transgressor, que se surt de les pautes habituals, dels convencionalismes. En aquest mateix context, s’expressen Mackinnon o Taylor que defineixen la creativitat com el procés intel•lectual que cerca produir noves idees que siguin vàlides.3

Per a J. Richard Suchman, insistint sobre la idea de l'originalitat, introdueix un nou element que pot ser de vital importància: la referència al subjecte i la seva autonomia. "El pensament creatiu té dos trets característics. Primer, és autònom, no es ni aleatori, ni està controlat per a cap agent extern o esquema fixe, sinó que és completament autodirectiu. Segon, està dirgit a produir una nova forma -nova en el sentit de la consciència del pensador abans d'iniciar el seu pensament".
4 Pren especial rellevància, que la novetat és centra en el subjecte i no en el col•lectiu o societat a la que pertany.

De tota manera podem veure que la interpretació que originalitat i novetat, trets característics de la creativitat i el pensament creatiu, no sempre es fa en la línia que segueixen Jackson, Messick, Ghiselin, Ulmann i Guilford, que la consideren com una proposta que ningú ha fet abans, o una alternativa a tot allò que s'havia plantejat. Steiner considera que
"l’originalitat és la antítesi de la novetat. L'etimologia de la paraula ens alerta. Ens parla d'inici i d'instauració de un retorn, en substància i forma, als inicis. Les invencions estètiques són arcaiques en exacta relació amb la seva originalitat, amb la seva força d'innovació espiritual-formal"
5. Llavors ser original, suposa plantejar una idea de manera autèntica, recreant els diferents elements del nostre pensament o de la nostra actuació i donar-li un ordre propi, una estructura significativa dins del nostre univers personal.

Desenvolupar un pensament creatiu y original més que crear una novetat esdevé trencar amb la convencionalitat, amb lo admès, suposa repensar la realitat per un mateix, amb els seus propis ulls, i no amb els de la societat.6

Creativitat, espontaneïtat i reflexió
El pensament creatiu està subjecte a la reflexió, està sotmès a certs criteris. “També es troba allí, una vegada més, tota la dialèctica entre l'omnipotència de la imaginació i la necessitat d'un compromís amb la realitat".7 Es evident que en el pensament creatiu l’espontaneïtat, la llibertat d'expressió i d'imaginació s'han de canalitzar, explorar i explotar d'una manera sistemàtica i reflexiva. I tot creatiu ho sap, o ho hauria de saber. Hem d'entendre llavors que la creativitat espontània o primària8 i la creativitat reflexiva, no són dos tipus de creativitat, sinó dos estadis o moments diferents del procés creatiu.9

El procés creatiu estarà format per una etapa d’originalitat, que garanteix la novetat del producte i una altra de funció intel•lectual que produeix el caràcter valuós i escaient del mateix. Aquest fet, desmitifica la definició romàntica –i tant acceptada socialment- de que el creatiu no és es un ésser racional. És obvi, que la creativitat necessita vies d’expressió i de comunicació, necessita canals per a la seva elaboració i realització. La creativitat esdevé l’adquisició i interiorització d’instruments i eines mentals, entre les que hi haurà forçosament els processos de raonament lògic-formals. “El cultiu de la racionalitat en l’esfera estètica és tant o més important que el cultiu de la mateixa en les altres dues esferes essencials de l’ésser humà-la teòrica i la pràctica-“.
10

Creativitat i pensament divergent
El pensament divergent és per oposició al convergent aquell que la direcció de la reflexió i argumentació no és única. És a dir, no pretén obtenir una conclusió o resposta única i valida. En no concentrar-se en una única direcció, la investigació esdevé més obert i dispers. Pierce introdueix el raonament explicatiu, que extén el nostre pensament sense ampliar-lo, la deducció en seria un exemple, i el raonament amplificatiu que duu el nostre pensament més enllà de l’experiència, amb analogies, inducció i metàfores. 11



(1) Paul Torrance, E. Creative teaching makes a difference en Creativity: its educational implications. Curtis Gowan, J. Demos. G.D. y Paul Torrance, E. New York, John Wiley and Sons Inc, 1967, p.177.
(2) Lipman, M., Pensament complex i educació, p. 279.

(3) Citat por Jaoui, H., Claves para la creatividad, México, Diana, 1979 p. 249

(4) Richard Suchman, J., Creative thinking and conceptual growth, Cretativity: its educational implications. Curtis Gowan, J. Demos G.D. y Paul Torrance, E. (Comp.) New York, John Wiley and Sons Inc, 1967, p. 89

(5) Steiner, G. Presencias Reales, Hay algo en lo que decimos? Barcelona, Ensayos/Destino, 1989. p-42

(6) Lago Bornstein, Juan Carlos, Redescribiendo la comunidad de investigación, Ed. De la Torre, p-94.

(7) Jaoui,H. Claves para la creatividad, Mexico, Diana, 1979, p-42

(8) Lago Bornstein, Juan Carlos, Redescribiendo la comunidad de investigación, Ed. De la Torre, p-96.

citant a Maslow.
(9) Lago Bornstein, Juan Carlos, Redescribiendo la comunidad de investigación, Ed. De la Torre, p-97.

(10) Ferry, L., Homo Aesthethicus, Paris, Grasset, 1990

(11) Pierce, Ch. S, The probability of Induction, New York, Dover, p.180

dimarts, 10 / març / 2009

La importància de la definició de les extensions

Aquestes darreres setmanes he estat analitzant un servidor de continguts, que corria damunt una base de dades Oracle10g, amb tenia un rendiment molt baix, considerant les prestacions de la màquina i la càrrega de treball a la que estava sent sotmesa.

En els moments de màxima concurrència d'usuaris, el sistema s'alentia de tal manera, que sovint es produien "timeouts" de les aplicacions, un vertader maldecap. Les dades introduides en successives pantalles d'aplicació, es volcaven contra la base de dades i sovint no s'hi enregistraven. Els usuaris i els tècnics de sistemes patien un stress desmesurat, i saltaven espurnes constantment. El deteriorament de les relacions humanes suposa una gran pèrdua de productivitat per a qualsevol organització.

Una de les raons per les que el rendiment no era el que cabia esperar, era la definició de les extensions de les taules més grans, d'uns cinc o sis milions de registres. Concretament, la taula que enregistrava l'activitat de les aplicacions sensibles de l'organització a efectes de la LOPD -Llei Orgànica de Protecció de dades- era un dels coll d'ampolla.

Qualsevol petició, modificació, eliminació o inserció de dades sensibles havia de ser curadosament enregistrada i auditada. I totes les aplicacions del servidor accedien i inserien constantment dades en aquesta taula. L'administrador de la base de dades havia assenyadament partit la taula, seguint el criteri setmanal. Tenint en compte que a efectes legals s'ha de tenir, relativament a mà els darrrers cinc anys, estem parlant d'unes tres-centes particions, i prop de cinc milions de registres.

Analitzant la capa de base de dades, amb una consulta contra DBA_SEGMENTS s'obtenia uns 32 GB per tota la taula. Una quantitat massa gran, tenint en compte de que es tracta d'una taula d'enregistrament (LOG), amb prop de trenta columnes, amb un máxim de dos-cents caràcters per columna.

Triant una partició a l'atzar, s'obtenia una columna mitjana de 40 i uns dos milions tres-centes cinquanta mil files, AVG_ROW_LEN = 42, NUM_ROWS = 2.364.689. És a dir que la partició tenia aproximadament 96.000 KBytes, contenint una quantitat relativament petita de dades. Els blocs obtinguts eren uns tretze mil el que ens donava un pes de 103 KB. Fins aquí les dades eren coherents, però la partició ocupava físicament en disc prop de 2 MB!

On era el problema? Em va preguntar l'Administrador de la base de dades. En la definició de la taula! -li vaig respondre. Li vaig posar un senzill exemple per il·lustrar-ho :

create table tb_test (t varchar2(1))
storage (INITIAL 1 MB
NEXT 1 MB
MINEXTENTS 1
MAXEXTENTS 5 );


Com ja saps cada segment, conté extensions. Si en la taula de l'exemple insereixo dos registres, tindré 2 bytes d'informació, però ocuparan un Mega en disc, i no puc tenir menys d'una extensió... Per tant, el primer que hem de fer és analitzar l'estructura de les taules, especialment la clàusula STORAGE de cadascuna. Però abans executarem:

alter table TB_LOG_LOPD deallocate unused;

dimarts, 12 / agost / 2008

Carregant fitxers directament

Una de les utilitats més utilitzades per a carregar fitxers en una base de dades Oracle, és l'sqlloader. Aquesta funcionalitat ha evolucionat amb les versions, fins assolir una certa maduresa, en la Oracle9iR2 i posteriors. Amb la racionalització de l'ús que proporcionen les Taules Externes, els obstacles de complexitat del LOADER s'esvaeixen.

Sistema d'Arxius
Hem de seguir una llista de comprovació bàsica en la ubicació dels fitxers en el sistema d'arxius:
- que tinguem una partició dedicada, si és possible.
- que tinguem prou espai d'emmagatzematge.
- que sigui sempre la mateixa.
- que sigui accessible pel compte d'usuari oracle.
- que tingui els permisos escaients sobre el fitxer a carregar.

Una vegada satisfets aquests requeriments, podem iniciar el procés de definició en base de dades.

Base de Dades
Els DIRECTORY són punters a una ubicació (PATH) del sistema d'arxius. Per tant, amb l'usuari propietari de l'esquema crearem el directori de càrrega i atorgarem permisos al compte que executarà el programa.

En aquest punt, tenim definit l'accés al fitxer, ara caldrà crear un objecte de base de dades que ens permeti definir el fitxer i la seva estructura. En l'sqlloader tradicional, es tractaria del fitxer de control i configuració.

Les taules externes, ens permeten concentrar en únic objecte la gestió de càrrega sqlloader, simplificant el màxim el procés. Crearem doncs, la taula externa -especificant que es tracta d'una taula LOADER-, definim les columnes de l'entitat, i del fitxer: la seva posició i longitud, fixer o amb caràcter separador. En l'especificació de la taula, haurem d'indicar el directori i opcionalment, l'origen -el nom del fitxer- de les dades.

Un exemple
Una aplicació que transforma fitxers plans (txt) en fitxers xml genera un fitxer de registre -un log- com el que es mostra tot seguit:
...
...
2008-04-04 14:23:06 # SEPAconv.sh # 2598 # LOG # FileLoad 01 : trobat fitxer sepa20080404cicle2.out en directori /app/sepa/data/in

2008-04-04 14:23:06 # SEPAconv.sh # 2598 # LOG # FileLoad 02 : renombrant fitxer sepa20080404cicle2.out per out_20080404_2.conv


2008-04-04 14:23:06 # SEPAconv.sh # 2598 # LOG # FileLoad 04 : movent fitxer out_20080404_2.conv en directori /app/sepa/data/exe

2008-04-04 14:23:06 # SEPAconv.sh # 2598 # LOG # FileLoad 05 : trobat fitxer out_20080404_2.conv en directori /app/sepa/data/exe

2008-04-04 14:23:07 # SEPAconv.sh # 2598 # LOG # FileCheck 01: comprobant la integritat del fitxer out_20080404_2.conv

2008-04-04 14:23:07 # SEPAconv.sh # 2598 # LOG # FileCheck 03 : El fitxer out_20080404_2.conv té el format correcté i un sol bloc.

...


On la primera columna ens mostra la data i hora d'execució, la segona el procés que s'està executant, la tercera l'identificador de procés, la quarta el tipus de missatge (LOG, correspon a registre normal, WRN a una advertència i ERR a un error d'execució) i en darrer lloc el missatge informatiu.

Per generar la taula externa que ens permeti carregar els fitxers de registre de l'aplicació a la base de dades hauríem d'executar les següents instruccions:

create or replace directory APPDUMP as '/app/sepa/data/load/';
grant read on directory APPDUMP to sepa;
grant write on directory APPDUMP to sepa;

create table APP_SEPA_LOG(
..APP_DATAIHORA_EXEC
..date,
..APP_PROCES_EXEC.....varchar2(30),
..APP_PROCES_PID......varchar2(4),
..APP_TIPUS_MISSATGE..char(3),
..APP_PROCES_MISSATGE varchar2(200)
..)
organization external (
type ORACLE_LOADER
default directory APPDUMP
acces parameters (
records delimited by newline
skip 2
fields terminated by ' # '
missing field values are null
.(
APP_DATAIHORA_EXEC.date,APP_PROCES_EXEC varchar2(30),
..APP_PROCES_PID varchar2(4),
APP_TIPUS_MISSATGE char(3),
..APP_PROCES_MISSATGE varchar2(200))
location ('appSEPA.log'));

...
Bé, doncs ara ja estem en condicions de poder carregar les dades en la nostra taula. Per fer-ho haurem de:

  • moure el fitxer de registre fins el directori /app/sepa/data/load.
  • renombrar-lo per appSEPA.log
  • atorgar-li permisos de lectura i escriptura
I tot seguit obrim una sessió en la base de dades amb el compte d'usuari oracle SEPA.
  • executem la instrucció
......select to_date(APP_DATAIHORA_EXEC,'yyyy-mm-dd hh24:mi:ss'),
.............APP_PROCES_EXEC
,APP_PROCES_PID,
.............APP_TIPUS_MISSATGE,APP_PROCES_MISSATGE

........from SEPA.APP_SEPA_LOG;

I tot seguit obtindrem les dades corresponents al fitxer, tabulats per columnes.

En l'enllaç http://www.psoug.org/reference/externaltab.html teniu informació complerta de les taules externes.

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.

diumenge, 8 / juliol / 2007

Corregint l'absència d'un DBA I: Sobrecarregant Procediments empaquetats

Sovint els entorns de desenvolupament no disposen de la figura del DBA. És una qüestió de costos, a una mala gestió dels mateixos, em refereixo, que no es disposi d'un administrador, que posi ordre al caos que acostuma a esdevenir. Quan la situació és insostenible o s'ha de lliurar una versió amb canvis a nivell de base de dades, llavors es contracta a temps parcial a un, per a que intenti restablir l'ordre que hauria d'haver existit des del principi.

No considererem la qüestió dels costos, però si l'absència de DBA. Quan el disseny d'una base de dades està en mans de desenvolupadors poc formats, ens acostumem a trobar una errada habitual: múltiples definicions de tipus de dades per a un únic Atribut o Columna de BD.

Il·lustrem-ho en un exempel molt freqüent: la columna ID_OBJECTE_APL, en la taula MESTRE_OBJECTES és un Number(12), en la taula OBJECTES_RECURSOS és un Varchar2(15), en la taula RECURSOS_DETALL és un Varchar2(50). Hi ha arguments de negoci -i pot ser emotius- per defendre aquesta posició, però no hi ha cap raó o argument tècnic de pes, que la sostingui...

En la taula mestra la columna ID_OBJECTE_APL, és una clau (identificador únic) de l'Objecte que es genera mitjançant una seqüència numèrica.

En la taula OBJECTES_RECURSOS, la columna ID_OBJECTE_APL és una concatenació d'un literal, per exemple l'àrea de negoci, i de l'identificador únic de la taula mestra.

En la taula RECURSOS_DETALL, la columna ID_OBJECTE_APL, li afegim a la columna de la taula OBJECTES_RECURSOS, una altra cadena que ens informa quin tipus de proveïdor és, i l'identificador del proveïdor.

Aquesta aproximació crea més problemes del que hom intueix a primer cop d'ull. Un dels pilars on es fonamenta un desenvolupament eficient, és la reutilització del codi. En l'escenari que tractem, si tenim una funció - FNC_DESCRIPCIO_OBJECTE -, que ens ha de retornar la descripció associada a l'identificador únic d'objecte... Quin utilitzarem? Haurem de fer una funció per a cadascuna de les taules, o incorporar un tractament en funció de l'origen que volem consultar?

Quan hom se n'adona del problema, acostuma a ser massa tard, i llavors la solució implica haver de modificar el codi de forma acurada i invertir uns recursos que en la majoria dels casos, no s'autoritzaran...

Si analitzem la situació, ens adonem que com a mínim, haurem de crear dues funcions diferents: una que ens accepti un VARCHAR2 i l'altra que ens accepti un NUMBER o un INTEGER. O simplificant al màxim, una única funció que retorni VARCHAR2 i controlar la crida en el codi del subprograma que la fa servir.

En aquesta situació, el desenvolupador ja té la solució i es disposa a crear dues funcions, perque en no tenir definits Paquets PL/SQL -una altra de les errades típiques de desenvolupadors no formats- no té cap altra sortida.

Sobrecarregant Subprogrames en un paquet
L'aproximació del DBA és ben diferent. En arribar, el primer que ha fet és empaquetar les funcions i procediments que penjaven directament de l'esquema, agrupant-los per una lògica concreta. Donat que no podrà modificar les definicions de base de dades per l'impacte que suposa en l'aplicació, decideix solucionar el problema de manera ràpida i senzilla.


..CREATE OR REPLACE PACKAGE pkg_Eines_Negoci AS
....FUNCTION fnc_DESCRIPCIO_OBJECTE (vObjecte Varchar2)
....RETURN Varchar2;

....FUNCTION fnc_DESCRIPCIO_OBJECTE (vObjecte Number)
....RETURN Varchar2;

..END pkg_Eines_Negoci;
../

Fixeu-vos que la funció fnc_DESCRIPCIO_OBJECTE es defineix de dues maneres diferents, una per a acceptar NUMBER i l'altre per a acceptar VARCHAR2, però manté el mateix nom.

NOTA: A nivell d'esquema no podriem fer-ho perque en executar la sentència de creació de la segona funció amb el mateix nom, eliminaríem la primera o l'Oracle ens retornaria un error dient que l'objecte ja existeix.

Hom es pot preguntar, Quin avantatge té? Doncs, bàsicament no haver de modificar gairebé el codi per deslligar el canvi i simplificar el desenvolupament en ho haver-se de preocupar un, de si la variable és un Varchar2 o un Number: crida la funció i recupera la descripció de l'objecte.

De fet un exemple clar del que és una sobrecàrrega de funcions ho tenim en les transformacions que fa l'Oracle entre tipus de dades, com són TO_NUMBER, TO_CHAR, TO_DATE, que sempre es criden de la mateixa manera (potser, caldrà incloure una màscara de format) sense tenir en compte el tipus de dada que li passem per paràmetre. Aquestes funcions es defineixen en el paquet DBMS_SQL.


El problema ara rau en com identificar dels possibles ID_OBJECTE_APL quin és el que necessitem, per informar la descripció, car és possible que les descripcions també siguin diferents, per acabar de liar la troca. El tractament, el veurem en una propera aportació, però el següent llistat aporta la solució més senzilla.


..CREATE OR REPLACE PACKAGE BODY pkg_Eines_Negoci AS
....FUNCTION fnc_DESCRIPCIO_OBJECTE (vObjecte Varchar2)
....RETURN Varchar2 IS
......vTaula...Varchar2(30);
......vSQL.....Varchar2(32767);
......vRetorn..Varchar2(50);
....BEGIN
......If length(vObjecte) <= 12 Then
........vTaula := 'OBJECTES_RECURSOS'
......Else
........vTaula := 'RECURSOS_DETALL';
......End If;

......vSQL := 'select NOM_OBJECTE_APL from '||vTaula||
..............' where ID_OBJECTE_APL = '''||vObjecte||''' ';
......execute immediate vSQL into vRetorn;
......Return vRetorn;
....EXCEPTION
......When Others Then
........vRetorn := 'ERROR';
........Return vRetorn;
....END fnc_DESCRIPCIO_OBJECTE;

....FUNCTION fnc_DESCRIPCIO_OBJECTE (vObjecte Number)
....RETURN Varchar2 IS
......vSQL.....Varchar2(32767);
......vRetorn..Varchar2(50);
....BEGIN
......vSQL := 'select NOM_OBJECTE_APL from MESTRE_OBJECTES'
..............' where ID_OBJECTE_APL = '||vObjecte;
......execute immediate vSQL into vRetorn;
......Return vRetorn;
....EXCEPTION
......When Others Then
........vRetorn := 'ERROR';
........Return vRetorn;
....END fnc_DESCRIPCIO_OBJECTE;
..END pkg_Eines_Negoci;
../

PLS-00375: Adreçant-se vers un destí inaccessible

Error
Quan tracto de compilar el meu procediment llançadora em surt el següent missatge d'error, ¿Què és el que passa?


ERROR at line 32:
ORA-06550: line 32, column 12:
PLS-00375: illegal GOTO statement ;
this GOTO cannot branch to label
'PROCEDIMENT3'
ORA-06550: line 39, column 13:
PL/SQL: Statement ignored


Resposta
Bé, si et fixes amb la pila d'error, veuràs que el primer, l'ORA-06550 et fixa l'error, i el segon el PLS-00375 et diu el que l'ha causat.

El que passa és que has construït una estructura de control de manera incorrecta, donat que la instrucció GOTO té un abast (SCOPE) limitat.

El següent exemple de codi, et mostra com usar la instrucció GOTO de manera correcta i incorrecta en la teva llançadora:


.....
..PROCEDIMENT_1(param1, param2, v_ctrl_exec);
..If v_ctrl_exec = 'WRN' Then
....GOTO PROCEDIMENT3;
..Elsif v_ctrl_exec = 'KO' Then
....param3 := v_ctrl_exec;
....Raise ErrorProc;
..End If;

..<<PROCEDIMENT2>>
..PROCEDIMENT_2(param1, param2, v_ctrl_exec);
..If v_ctrl_exec = 'WRN' Then
....GOTO PROCEDIMENT4;
..Elsif v_ctrl_exec = 'KO' Then
....param3 := v_ctrl_exec;
....Raise ErrorProc;
..End If;

..<<PROCEDIMENT3>>
..PROCEDIMENT_3(param1, param2, v_ctrl_exec);
..If v_ctrl_exec = 'WRN' Then
....GOTO PROCEDIMENT5;
..Elsif v_ctrl_exec = 'KO' Then
....param3 := v_ctrl_exec;
....Raise ErrorProc;
..End If;

..PROCEDIMENT_X(v_ctrl_exec);

..If v_ctrl_exec = 'WRN' Then
....GOTO PROCEDIMENTY;
..Elsif v_ctrl_exec = 'KO' Then
....param3 := v_ctrl_exec;
....Raise ErrorProc;
..Elsif v_ctrl_exec = 'OK' Then
....param3 := v_ctrl_exec;
..<<PROCEDIMENT4>>
....PROCEDIMENT_4(param1, param2, v_ctrl_exec);
..End If;

.....



Fixa't que el destí del GOTO (el segon), que ens adreça al procediment PROCEDIMENT_4 està dins d'una estructura de control If-Then-Else. En intentar adreçar l'execució dins del bloc de control directament, l'IF no s'avuluarà per tant Oracle ens retornarà l'error PLS-00375 en intentar compilar el programa.

Mentre que el destí del GOTO (el primer) que ens adreça al procediment PROCEDIMENT_3, està ben construït perque el destí està al seu abast, no és dins de cap bloc de control If-Then-Else.

dissabte, 7 / juliol / 2007

Per l'Edu: RaFA no me jod...

RaFA és una llançadora de procediments fàcil i ràpid de deslligar que funciona de meravella amb càrregues de les que tu saps, sense efectes col·laterals.

Per integrar-ho a qualsevol desenvolupament de paquets PL/SQL no és difícil...

Primer has d'afegir o crear, un paquet de constants... Les dels missatges de resultat i estat d'execució. Aquest exemple senzill ho il·lustra.


....CREATE OR REPLACE PACKAGE pkg_RaFA_Core AS
......c_RAFA Constant Varchar2(50):= 'RaFA';
......c_OK Constant Varchar2(50):= 'OK';
......c_WRN Constant Varchar2(50):= 'WRN';
......c_KO Constant Varchar2(50):= 'KO';
......c_Cua Constant Varchar2(50):= 'CUA';
......c_Error Constant Varchar2(50):= 'ERROR';
......c_Exec Constant Varchar2(50):= 'EXECUCIO';
......c_Fi Constant Varchar2(50):= 'FI';
......c_Inici Constant Varchar2(50):= 'INICI';
......c_Flux Constant Varchar2(50):= 'RaFA';

....FUNCTION FNC_SYSTIMESTAMP Return SYSTIMESTAMP(6);

....-- FUNCTION FNC_FES_TRACA Return Varchar2;

....END PACKAGE pkg_RaFA_Core;
..../

....CREATE OR REPLACE PACKAGE pkg_RaFA_Core AS
......c_RAFA Constant Varchar2(50):= 'RaFA';
......c_OK Constant Varchar2(50):= 'OK';
......c_WRN Constant Varchar2(50):= 'WRN';
......c_KO Constant Varchar2(50):= 'KO';
......c_Cua Constant Varchar2(50):= 'CUA';
......c_Error Constant Varchar2(50):= 'ERROR';
......c_Exec Constant Varchar2(50):= 'EXECUCIO';
......c_Fi Constant Varchar2(50):= 'FI';
......c_Inici Constant Varchar2(50):= 'INICI';
......c_Flux Constant Varchar2(50):= 'RaFA';

....FUNCTION FNC_SYSTIMESTAMP Return SYSTIMESTAMP(6) IS
......vSQL Varchar2(32767);
......vRetorn TimeStamp(6);

....BEGIN
......vSQL := 'select SysTimeStamp from dual';
......execute_immediate vSQL into vRetorn;

......If vRetorn Is Null Then
........Raise;
......End If;
......Return vRetorn;
....EXCEPTION
....-- Brut però efectiu : ·
......When Others Then
......Return Null;
....END FUNCTION FNC_SYSTIMESTAMP;

....--FUNCTION FNC_FES_TRACA Return Varchar2;

....END PACKAGE pkg_RaFA_Core;
..../

....CREATE PUBLIC SYNONYM PKG_RAFA_CORE;
..../

....-- GRANT EXECUTE ON PKG_RAFA_CORE TO :USER;


Quan un treballa en DATAs o OLTPS grans ha de racionalitzar la finestra de temps assignada, i "UN PASE" com diria el Ciborcillo, no sempre és "DIARIO" i d'una passada...

Poc temps ens quedarà per posar-hi les grapes i fer un altre PASE si ha petat... El "cullerot" apareix, li donem a la xurrera i ... ja està!: S'ha mort aquí, podem continuar des d'allà perque això ja ho hem processat, la resta ho podem llençar... a les escombraries!

Quan a un se li aveinen moltes càrregues de cop, o ja viu d'elles pensa, gairebé obsesivament, com automatitzar al màxim el procés de recuperació d'errors (Failover) de la solució existent. En altres paraules, com recuperar forces per la posada en marxa...

Jo ho he estat fent, i perxò m'he animat a explicar el RaFA, Real Application Fire Artillerist (és una broma de l'equip) per no haver de patir més de lo necessari.

Lo primer és traçar com un boig, sense por, jo et recomano crear-te una taula RAFA_CORE_LOG d'auditoria precisa dels llançaments, però de fet, amb les constants en tens prou. Lo de precisa, també va per la taula, no només a l'auditoria em refereixo al temps: has d'enregistrar l'execució amb tipus de dades com TIMESTAMP(6) per exemple. I recorda: AL "TANTO" SI EXECUTES EN PARAL·LEL!

No he posat cap escrit CREATE, a partir d'ara genèricament en direm fnc_FES_LOG...

Comencem, agafa qualsevol PROCEDURE ETL que et faci ràbia! Mira la capçalera, sino els té, li afegeixes als paràmetres, aquests dos:


......pExecucio OUT Varchar2,pResultat OUT Varchar2)


Ves cap l'IS de la definció del PROCEDURE i afegeix-li, aquestes dues, la del nom del procediment és per capturar l'esquema, el Paquet i el nom del procediment, s'hi pot afegir el procés...


......vProcedure Varchar2(100);
......ErrorWRN Exception;


I després en el BEGIN abans d'inicialitzar les variables,


......vProcedure:= <<current_procedure>>;
......pExecucio := pkg_RAFA_CORE.c_Inici;
......pResultat := pkg_RAFA_CORE.c_OK;


I en finalitzar, també haurem de tocar l'EXCEPTION, és clar...


.........
......vProcedure:= <<current_procedure>>;
......pExecucio := pkg_RAFA_CORE.c_Fi;
......pResultat := pkg_RAFA_CORE.c_OK;
....EXCEPTION
.........
......WHEN OTHERS THEN
........vProcedure:= <<current_procedure>>;
........pExecucio := pkg_RAFA_CORE.c_Error;
........pResultat := pkg_RAFA_CORE.c_KO;
.........
....END <<current_procedure>>;


En aquests moments, el teu procediment ja està integrat com un projectil RaFA! Si et fixes, no és gaire difícil imaginar que ens falta una llançadora, i potser -en un altre capítol- una cua...

NOTA: Si el tens en un paquet l'hauràs sobrecarregat i et permet migrar instantàniament si tot ha anat com cal esperar. Si no ho has fet, fes-ho.

Repetim l'operació en tots els procediments que integrin el procés. I tot seguit ens anem al procediment "LLENÇA-HO_TOT" que ve a ser un "dispara"! Segur que si haguessis de disparar un canó d'artilleria, t'asseguraries de que el projectil anterior, s'ha disparat bé... doncs fem-ho.


....CREATE OR REPLACE PACKAGE BODY pkg_Exemple_0805 AS
....PROCEDURE Executa_tot
....IS
......vProces Varchar2(8);
......vProcedure Varchar2(100);
......param1 Varchar2(100);
......param2 Varchar2(100);
......vRAFALOG Varchar2(2000);
....BEGIN
....-- Es pot deslligar de moltes maneres, un literal per
....-- informar el procés, a títol d'exemple només...
........vProces := '08052300';
........vProcedure := 'Executa_Tot';
........pExecucio := pkg_RAFA_CORE.c_Inici;
........pResultat := pkg_RAFA_CORE.c_OK;
........-- Incialitzem variables...
........param1 := 'Valor 1';
........param2 := 'Valor 2';
........-- Executem els procediments seqüencialment.
........PROCEDIMENT_1(param1, param2, vResultat, vExecució);
........PROCEDIMENT_2(param1, param2, vResultat, vExecució);
...........
........PROCEDIMENT_n(param1, param2, vResultat, vExecució);

........vProcedure:= ;
........pExecucio := pkg_RAFA_CORE.c_Fi;
........pResultat := pkg_RAFA_CORE.c_OK;

....EXCEPTION
........When Others Then
..........vProcedure:= ;
..........pExecucio := pkg_RAFA_CORE.c_Error;
..........pResultat := pkg_RAFA_CORE.c_KO;
...........
......END Executa_tot;

......PROCEDIMENT_1(param1 Varchar2, param2 Varchar2) is
...........
....END pkg_Exemple_0805;


Donem un primer pas en el paquet que tenia (o acabem de fer) el procediment. I li afegim l'enregistrament paral·lel per no concórrer en els mateixos segments de LOG de l'execució...


....CREATE OR REPLACE PACKAGE BODY pkg_Exemple_0805 AS
......PROCEDURE Executa_tot IS
........vProces Varchar2(4);
........vProcedure Varchar2(30);
........vResultat pkg_RAFA_CORE.c_Resultat%Type;
........vExecucio pkg_RAFA_CORE.c_Execucio%Type;
........vRAFALOG Varchar2(2000);

........param1 Varchar2(100);
........param2 Varchar2(100);
......BEGIN
........vProces := 'PKG_EXEMPLE_0805';
........vProcedure := 'Executa_Tot';
........param1 := 'Valor 1';
........param2 := 'Valor 2';

........vRAFALOG := v_Procedure' Iniciant execució...';
........-- Afegim traça en iniciar el procediment.
........PKG_RAFA_CORE.FNC_FES_LOG(
..........pkg_RAFA_CORE.FNC_SYSTIMESTAMP,pResultat,pExecucio,
..........vProces,vProcedure,param1||'#'||param2,vRAFALOG
........);

...........

........pExecucio := pkg_RAFA_CORE.c_Fi;
........pResultat := pkg_RAFA_CORE.c_OK;
........vRAFALOG := v_Procedure' Fi d''execució...';
........-- Afegim traça en acabar el procediment.
........PKG_RAFA_CORE.FNC_FES_LOG(
..........pkg_RAFA_CORE.FNC_SYSTIMESTAMP,pResultat,pExecucio,
..........vProces,vProcedure,param1||'#'||param2,vRAFALOG
........);

....EXCEPTION
......When Others Then
........vProcedure:= ;
........pExecucio := pkg_RAFA_CORE.c_Error;
........pResultat := pkg_RAFA_CORE.c_KO;
........vRAFALOG := PKG_RAFA_CORE.C_ERROR||'vProcedure||
........' 'substr(SQLERRM,1,200);
........PKG_RAFA_CORE.FNC_FES_LOG(
........pkg_RAFA_CORE.FNC_SYSTIMESTAMP,pResultat,pExecucio,
..........vProces,vProcedure,param1||'#'||param2,vRAFALOG
........);
...........


Ara ja tenim la llançadora llesta, en condicions de disparat amb precisió, només ens cal executar-la i comprovar que traça correctament.


..DATA_EXECUCIO..............ESTAT.....RESULTAT.PROCES.PROC.MISSATGE
..--------------------------.--------..--------.------.----.-------------------------------------------------------
..06/07/2007 20:21:54,127984.INICI.....OK.......0805...2300 PKG_EXEMPLE_08005.EXECUTA_TOT : Iniciant Execució
..06/07/2007 20:21:56,549932.FI........OK.......0805...2300 PKG_EXEMPLE_08005.EXECUTA_TOT : Fi d''Execució


Comprovem que també enregistra quan es produeixi un error i llavors anem a tractar les crides que fem als procediments. Com he comentat abans, el resultat ens proporciona tres valors possibles, correcte, avís i error. Anem doncs, ha deslligar el tractament del resultat, es tracta d'incloure aquesta estructura de control després de cada llançament o crida.


......PROCEDIMENT_1(param1, param2, vResultat, vExecució);

......If vResultat = pkg_RAFA_CORE.c_WRN Then
........-- Fem alguna cosa...
........ElsIf vResultat = pkg_RAFA_CORE.c_KO Then
........Raise;
......End If


Aquest tractament ens permet determinar tres possibles actuacions:
....- si el procediment cridat ha finalitzat correctament, cridarem el següent,
....- si ens retorna un avís, prendrem una decisió,
....- i si ha finalitzat amb error llavors interromprem la càrrega...

Per l'execució farem el mateix, el tractament pot esdevenir tan complex com els nostres requeriments demanin.

El codi següent il·lustra com deslligar un RaFA amb la instrucció GOTO, sovint oblidada en els entorns de desenvolupament actuals...


..CREATE OR REPLACE PACKAGE BODY pkg_Exemple_0805 AS
....PROCEDURE Executa_tot IS
......vProces Varchar2(4);
......vProcedure Varchar2(30);
......vResultat pkg_RAFA_CORE.c_Resultat%Type;
......vExecucio pkg_RAFA_CORE.c_Execucio%Type;
......vRAFALOG Varchar2(2000);

......param1 Varchar2(100);
......param2 Varchar2(100);
....BEGIN
......vProces := 'PKG_EXEMPLE_0805';
......vProcedure := 'Executa_Tot';
......param1 := 'Valor 1';
......param2 := 'Valor 2';

......vRAFALOG := v_Procedure' Iniciant execució..
......-- Afegim traça en iniciar el procediment.
......PKG_RAFA_CORE.FNC_FES_LOG(
......pkg_RAFA_CORE.FNC_SYSTIMESTAMP,pResultat,pExecucio,
........vProces,vProcedure,param1||'#'||param2,vRAFALOG
......);
......-- Cridem el primer procediment.
......PROCEDIMENT_1(param1, param2, vResultat, vExecució);

......If vResultat = pkg_RAFA_CORE.c_WRN Then
........GOTO PROCEDIMENT3;
......ElsIf vResultat = pkg_RAFA_CORE.c_KO Then
........Raise;
......End If

......<<PROCEDIMENT2>>
......PROCEDIMENT_2(param1, param2, vResultat, vExecució);

......If vResultat = pkg_RAFA_CORE.c_WRN Then
........GOTO PROCEDIMENT4;
......ElsIf vResultat = pkg_RAFA_CORE.c_KO Then
........Raise;
......End If

......<<PROCEDIMENT3>>
......PROCEDIMENT_3(param1, param2, vResultat, vExecució);
.........
......<>
......PROCEDIMENT_n(param1, param2, vResultat, vExecució);

......If vResultat = pkg_RAFA_CORE.c_WRN Then
........GOTO EOF;
......ElsIf vResultat = pkg_RAFA_CORE.c_KO Then
........Raise;
......End If

......<<EOF>>
......pExecucio := pkg_RAFA_CORE.c_Fi;
......pResultat := pkg_RAFA_CORE.c_OK;
......vRAFALOG := v_Procedure' Fi d''execució...';
......-- Afegim traça en acabar el procediment.
......PKG_RAFA_CORE.FNC_FES_LOG(
........pkg_RAFA_CORE.FNC_SYSTIMESTAMP,pResultat,pExecucio,
........vProces,vProcedure,param1||'#'||param2,vRAFALOG
......);

....EXCEPTION
.........
......When Others Then
........vProcedure:= ;
........pExecucio := pkg_RAFA_CORE.c_Error;
........pResultat := pkg_RAFA_CORE.c_KO;
........vRAFALOG := PKG_RAFA_CORE.C_ERROR'vProcedure||
..........' 'substr(SQLERRM,1,200);
........PKG_RAFA_CORE.FNC_FES_LOG(
..........pkg_RAFA_CORE.FNC_SYSTIMESTAMP,pResultat,pExecucio,
..........vProces,vProcedure,param1||'#'||param2,vRAFALOG
........);
.........


Si us fixeu, a la taula de registre RaFA només tindrem l'inici i el fi d'execució del procediment que executa la càrrega, restarà llavors saber quin procediment estem cridant, per enregistrar-ho tot...

Tenim infinitat d'aproximacions per fer-ho, però una d'elles és fer que el procediment que cridem, traci en el registre RaFA...


....PROCEDURE PROCEDIMENT_n (param1 Varchar2, param2 Varchar2,
......pResultat OUT Varchar2, pExecucio pVarchar2)
....IS
......vProcedure Varchar2(100);
......ErrorWRN Exception;
....BEGIN
......vProcedure:= ;
......pExecucio := pkg_RAFA_CORE.c_Inici;
......pResultat := pkg_RAFA_CORE.c_OK;
......vRAFALOG := v_Procedure' Iniciant execució..
......-- Afegim traça en iniciar el procediment.
......PKG_RAFA_CORE.FNC_FES_LOG(
........pkg_RAFA_CORE.FNC_SYSTIMESTAMP,pResultat,pExecucio
........vProces,vProcedure,param1||'#'||param2,vRAFALOG
......);
.........


Amb aquesta aproximació només detectarem errors d'execució si el procediment cridat s'arriba a executar, en cas de no fer-ho la llançadora retornaria l'error mitjançant el seu tractament d'excepcions.

Per tant, per acabar de deslligar la solució RaFA hem de traçar les crides als procediments i ho podrem donar per acabat...


.........
......-- Cridem el primer procediment.
......vRAFALOG :=vProcedure' : Executant PROCEDIMENT_1';
......PROCEDIMENT_1(param1, param2, vResultat, vExecució);
......
......If vResultat = pkg_RAFA_CORE.c_WRN Then
........vRAFALOG := vProcedure' : Avís 'vRAFALOG;
........vRAFALOG := vRAFALOG' -> ''PROCEDIMENT_2 no s''executa';
........PKG_RAFA_CORE.FNC_FES_LOG(
..........pkg_RAFA_CORE.FNC_SYSTIMESTAMP,pResultat,pExecuio
..........vProces,vProcedure,param1'#'param2,vRAFALOG
......);
........GOTO PROCEDIMENT3;
......ElsIf vResultat = pkg_RAFA_CORE.c_KO Then
........Raise;
......End If;

......><<PROCEDIMENT2>>
......vRAFALOG :=vProcedure' : Executant PROCEDIMENT_2';
......PROCEDIMENT_1(param1, param2, vResultat, vExecució);
.........


El registre d'una càrrega utilitzant la tecnologia RaFA és com la que es mostra en el llistat següent:


..DATA_EXECUCIO..............ESTAT.....RESULTAT.PROCES.PROC.MISSATGE
..--------------------------.--------..--------.------.----.-------------------------------------------------------
..06/07/2007 20:21:54,127984.INICI.....OK.......0805...2300 PKG_EXEMPLE_08005.EXECUTA_TOT : Iniciant Execució
..06/07/2007 20:21:54,967894.EXECUCIO..OK.......0805...2300 PKG_EXEMPLE_08005.EXECUTA_TOT : Executant PROCEDIMENT_1
..06/07/2007 20:21:54,998048.EXECUCIO..OK.......0805...7600 PKG_EXEMPLE_08005.PROCEDIMENT_1 : Iniciant Execució
..06/07/2007 20:21:55,000179.EXECUCIO..OK.......0805...7600 PKG_EXEMPLE_08005.PROCEDIMENT_1 : Fi d''execució
..06/07/2007 20:21:55,000395.EXECUCIO..OK.......0805...2300 PKG_EXEMPLE_08005.EXECUTA_TOT : Executant PROCEDIMENT_2
..06/07/2007 20:21:55,004782.EXECUCIO..OK.......0805...7700 PKG_EXEMPLE_08005.PROCEDIMENT_2 : Iniciant Execució
..06/07/2007 20:21:55,719856.EXECUCIO..OK.......0805...7700 PKG_EXEMPLE_08005.PROCEDIMENT_2 : Fi d''execució
..06/07/2007 20:21:55,800059.EXECUCIO..OK.......0805...2300 PKG_EXEMPLE_08005.EXECUTA_TOT : Executant PROCEDIMENT_3
..06/07/2007 20:21:55,910027.EXECUCIO..OK.......0805...7900 PKG_EXEMPLE_08005.PROCEDIMENT_3 : Iniciant Execució
..06/07/2007 20:21:56,478191.EXECUCIO..OK.......0805...7900 PKG_EXEMPLE_08005.PROCEDIMENT_3 : Fi d''execució
..06/07/2007 20:21:56,549932.FI........OK.......0805...2300 PKG_EXEMPLE_08005.EXECUTA_TOT : Fi d''Execució


En properes aportacions deslligarem el tractament del resultat i l'execució de cada procediment, per tal d'incorporar mecanismes de recuperació d'errors, dins de la mateixa càrrega. També crearem un sistema d'encuat de procediments que ens permeti, reprendre l'execució de la càrrega si s'ha produït un error controlat.

dissabte, 21 / abril / 2007

En memòria de l'Héctor.

No hi ha paraules per descriure el dol profund que sento i sentim tots els que hem compartit una part de la nostra vida amb tu. Sense importar el temps que haguem passat al teu costat. No hi ha mots que defineixin l'aflicció que ens engol·leix, quan els nostres pensaments ens projecten la teva persona.

No hi ha una sola raó que justifiqui la teva pèrdua. Quan tenies tota una vida per davant. Quan aquesta vida omplia també la nostra.

Ahir quan vaig veure buida la taula que ocupaves amb discreció, tal i com l'havies deixada quan te'n vas anar per no tornar més....(no puc continuar)



En veure el teu àmbit personal en la impersonalitat d'un lloc de treball, no vaig poder evitar recordar que els sentiments -sovint arraconats pels professionals- són la peça angular on es fonamenta l'èxit de tots els projectes que afrontem.

Ahir quan vaig veure les llàgrimes d'alguns dels companys, em vaig adonar que mai es podrà substituir la teva absència.

En memòria de l'Héctor, que des del dimecres només podrà estar entre nosaltres en els nostres records, però que seguirà ocupant la seva taula i el seu racó en el nostre cor per sempre més.

dimarts, 27 / febrer / 2007

Instal·lant la Base de Dades Oracle 10g R2 en Linux x86 III

Part III: Instal·lant Oracle


Crea un directori que contingui la distribució Oracle10g R2:
.....mkdir 10gR2_db

Per descarregar la base de dades Oracle10g R2 des de l'OTN, orsa fins:
http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10201linuxsoft.html.
Si acceptes les condicions del contracte de llicència, clica en I Accept.

Clica en l'enllaç de 10201_database_linux32.zip, i guarda el fitxer en el directori que has creat per aquesta tasca (10gR2_db).

Descomprimeix i extrau el fitxer:
.....cd 10gR2_db
.....unzip 10201_database_linux32.zip

Instal·la el programari i Crea la Base de dades

Connectat utilitzant el compte d'usuari oracle.

Canvia de directori, fins la ubicació on has descarregat el programari d'Oracle.

Ex:
....$ cd $HOME/10gR2_db

Canvia el directori a Disk1.

Ex:
$ cd database/Disk1


Inicia l'Instal·lador Universal Oracle -Oracle Universal Installer.

.....$ ./runInstaller
.....1. Selecciona el mètode d'instal·lació - Installation Method
..........o Selecciona instal·lació bàsica - Basic Installation
..........o Oracle Home Location: /u01/app/oracle/product/10.2.0/db_1
..........o Installation Type: Enterprise Edition (1.3GB)
..........o UNIX DBA Group: oinstall
..........o Assegura't que Create Starter Database està seleccionat
..........o Global Database Name: demo1
..........o Entra la clau d'accés a la Base de dades i confirma-la
..........o Clica en Next
.....2. Especifica el Directori d'Inventari i les Credencials - Inventory Directory and Credentials
..........o Inventory Directory: /u01/app/oracle/oraInventory
..........o Operating System group name: oinstall
..........o Clica en Next
.....3. Comprovacions dels Pre-requeriments específics del producte
..........o Si has seguit totes les passes de la guia, totes les comprovacions es faran de forma satisfactòria. En un altre cas, corregeix aquelles en les que es produeixi un error abans de continuar.
..........o Clica en Next
....4. Llistat - Summary
..........o Un llistat dels productes que es van a instal·lar es presenta:
..........o Clica en Install.
.....5. Assistents de Configuració – Configuration Assistants
..........o Els asistents de configuració Oracle Net, Oracle Database, i iSQL*Plus s'executen automàticament
.....6. Executa els Escrits de Configuració
..........o En acabar la instal·lació, apareix una finestra emergent indicant que els escrits s'han d'executar com root. Connectat com root i executa'ls.
..........o Clica en OK quan acabi.
.....7. Fi d'Instal·lació - End of Installation
..........o Pren nota de les URLs del llistat i clica en Exit quan estiguis llest.
.....8. Felicitats! La teva base de dades Oracle Database10g R2 ja està llesta.