Clasificación de Bases de Datos Activas
Clasificación de Bases de Datos Activas
1. Introducción
El objetivo de este seminario es por una parte presentar la tecnología de Bases de Datos
Activas y por otra parte verificar el comportamiento de la integridad de los datos, mediante un
caso práctico, implantado de acuerdo a las definiciones de Díaz y Paton (1997).
Una Base de Datos Activa (en adelante BDA si hablamos del concepto o SGBDA si hablamos
del gestor) consiste en una extensión de un SGBD, compuesta de trozos de programas
coordinados de tal manera que permitan almacenar la semántica de los datos además de los
propios datos, para convertirla en un SGBDA.
En este sentido, no basta con aplicar las facilidades que proporcionan los SGBD modernos
tales como ORACLE, SYBASE, INFORMIX etc., si no, que hace falta una infraestructura
que sea capaz de soportar una adecuada interfaz con el usuario, para su configuración y
control. Esta infraestructura puede ser proporcionada por el proveedor del gestor o bien
desarrollarse en base a él, lo que requiere un profundo conocimiento tanto del paradigma de
BDA como del gestor a utilizar, además de adoptar un “aproach” o integrar varios de ellos
para su implementación, por parte de los desarrolladores.
Se puede pensar que las BDA transforma la Aplicación de Bases de Datos moviendo la
conducta reactiva de la aplicación hacia el sistema de gestión de bases de datos. Con esto se
obtiene de inmediato tres mejoras relacionadas con el rendimiento y los costos de mantención,
globales de la aplicación:
Tema abierto: Hacer una interfaz inteligente de BDA. La interfaz a construir en este trabajo, si
bien cumple con las definiciones de BDA y hace disponible el modelo de conocimiento y de
ejecución, aún es compleja ya que aún hay mucho código que manejar.
La integridad de los datos a medir va ligada con las reglas del negocio, las cuáles reflejan las
restricciones que existen en el negocio dado, de modo que nunca sea posible llevar a cabo
acciones no válidas, dejando por sentado que la integridad primaria (PK), referencial (FK) y
de dominio, no es el ámbito prioritario de un SGBDA, aunque los incluye.
SGBD, para odre modificar las definiciones del evento, condición y acción, soportando
además la activación y desactivación de las reglas.
Los triggers son trozos de Programas que realizan la actividad de la BDA, a través de
secuencias de operaciones de manipulación de la base de datos (INSERT, DELETE y
UPDATE), estos también corresponden a las acciones de una regla ECA implementada en los
triggers asociados a las tablas en las cuáles se realiza la manipulación de la Base de Datos.
El Modelo de Conocimiento es el que permite mantener algún mecanismo para que los
usuarios describan la conducta reactiva de la base de datos, a través de las reglas ECA.
Para esto desarrollaremos un Caso Práctico sobre el tratamiento de las Bases De Datos
Activas, utilizando la metodología Case Method para el desarrollo del análisis y construcción
del sistema, en donde propondremos una arquitectura simple, utilizando la versión Oracle
disponible en la universidad.
4
2. Definición de un SGBDA
El SGBDA es aquel que cuando se producen ciertas condiciones, ejecuta de forma automática,
es decir, sin la intervención del usuario, las acciones especificadas de antemano en la fase de
definición de la base de datos. Un SGBDA debe ser capaz, por tanto, de monitorizar y
reaccionar ante eventos de manera oportuna y eficiente.
Una manera eficaz de supervisar las circunstancias es controlando que ninguna regla de
integridad se viole. Una restricción de integridad puede especificar la legalidad de los datos y
por tanto prevenir los errores, esta prevención consiste en rechazar las acciones que violen esta
integridad, para ello existen técnicas en la prevención de inconsistencias que se puedan
producir, o el descubrimiento que implica deshacer transacciones incorrectas.
Por lo tanto es importante que un Sistema de Base de Datos activa (SGBDA) pueda detectar y
corregir, en lo posible las operaciones incorrectas.
2.1 Justificaciones
No se puede hablar de que el sistema gestor de bases de datos Oracle, u otros similares poseen
una arquitectura activa, lo que realmente poseen es un comportamiento activo mediante la
utilización de Triggers, pero es necesaria la construcción de un nivel superior que pueda
almacenar los triggers, las reglas y los datos, ya que existen limitaciones en los Sistemas de
SQL, principalmente una falta de flexibilidad, hay posibilidades en que el compromiso de la
activación de un Trigger depende del compromiso de la transacción del Trigger que lo generó,
posibilidades como éstas no son soportadas usualmente por los modelos de ejecución de
Triggers y requieren el desarrollo de un nivel de regla activo sobre la base de datos designada.
5
Cuando se comparan los cambios de una aplicación con y sin triggers, se observa que las
versiones basadas en triggers corren significativamente más lento, las conclusiones que se
pueden derivar de este comportamiento en las bases de datos activas es la inmadurez de las
implementaciones mediante triggers, la carencia de experiencia en los desarrolladores en los
programas de triggers, sin embargo los triggers son usados para toda clase de tareas, como
código de integridad, seguridad, reglas de negocio, restricciones de tiempo, es decir con
implementaciones de esta clase es que actualmente planea explotar las bases de datos activas,
ya que el mejor camino para hacer los chequeos a tiempo es usar los triggers que pueden ser
accionados una vez ocurrido un evento.
efdjgodfjkgoedjfgodfjgodjfobjdfojglodfjgodfjgojsdfogjhola
2. 2 Modelo de Conocimiento
El Modelo de Conocimiento es el que describe la situación y la conducta correspondiente. Es
un sistema de la base de datos activa e indica lo que puede decirse sobre las reglas activas en
este sistema. Esto está en el contraste con el modelo de ejecución que determina cómo se
comportan las reglas en tiempo de ejecución.
Se considera que el modelo de conocimiento de una regla activa tiene tres componentes
principales que son: el evento, la condición, y la acción ya que Cuando ocurre un
determinado evento se evalúa la condición y se está se satisface se ejecuta la acción.
Avanzando ya sobre los mecanismos de expresión de las respuestas de estos sistemas activos,
se consigna que un conjunto de reglas, habitualmente denominadas triggers, consisten de un
evento, que provoca la evaluación de una condición, que si es satisfecha, dispara un
procedimiento, llamado la acción de la regla.
Entonces se define a una regla como un evento que provoca la evaluación de una condición; si
ésta se satisface, causa la ejecución de una acción predefinida. Las condiciones provocan
consultas a la base de datos y finalmente las acciones ejecutan cambios sobre la base de datos.
Las reglas son denominadas generalmente TRIGGERs o ECAs y son poderosas herramientas
para expresar restricciones de integridad, reglas del negocio, eventos temporales entre otros.
Las reglas ECA son del tipo Evento-Condición-Acción y expresan cuales son las acciones que
se deben disparar ante un determinado evento, habiéndose evaluado satisfactoriamente la
condición.
6
Evento
El evento especifica el suceso a cuya ocurrencia debe responder el sistema. Los eventos
pueden ser clasificados en:
Eventos primitivos: aquellos que son predefinidos en el sistema. Para cada uno de ellos debe
proveerse un mecanismo eficiente de detección, probablemente embebido en el sistema. A su
vez, estos pueden clasificarse en:
Eventos de base de datos están relacionados con las operaciones, en el modelo relacional:
selección, inserción, actualización y borrado.
Eventos temporales son los relacionados con el tiempo y son a su vez de dos tipos: absolutos
y relativos. Los absolutos mapean a puntos discretos a lo largo de la línea de tiempo, mientras
que los relativos son definidos con respecto a un punto de referencia explícito.
Eventos explícitos o externos son aquellos eventos que son detectados y generados junto con
sus parámetros por programas de aplicación y son solo manejados por el sistema. Previo a su
uso, los eventos explícitos y sus parámetros formales necesitan ser registrados con el sistema.
Cada evento tiene un conjunto bien definido de parámetros que son instanciados para cada
ocurrencia del evento.
Eventos complejos o compuestos: son los que se forman por la aplicación de un conjunto de
operadores a otros eventos primitivos o compuestos.
Tipos de Eventos
Composición de Eventos
- Secuencia de eventos
- Composición temporal
7
Condición
Se trata de una expresión que debe ser satisfecha para que se pueda proceder al disparo de la
acción.
En otros más sofisticados, en los que las reglas son disparadas por modificaciones en los
datos, se permite referenciar tanto en la condición como en la acción a los valores previos y
posteriores a la modificación. Estos mecanismos se denominan condiciones de transición.
La problemática que existe en este punto es la de seleccionar o crear un lenguaje que permita
su especificación. En algunas implementaciones la condición se expresa como un query
(consulta), considerándose verdadera cuando la cantidad de filas seleccionadas es mayor que
cero.
Tipos de Condiciones
Instanciación de la Condición
En la condición se pueden hacer referencia a los parámetros del evento instanciándose de esta
forma la condición cundo se activa la regla.
Parametrización de la Condición
cuando la condición es una consulta los parámetros se pueden inicializar con los datos
resultantes de la consulta).
Acción
Especifica las acciones que deben ser ejecutadas por el sistema como respuesta a la
ocurrencia del evento cuando la condición es cierta.
Existe una acción implícita en la evaluación de las condiciones, que es la de aceptar o rechazar
una operación. Pero se debe describir explícitamente el mecanismo que hace a la propagación
de los efectos de la actualización en las relaciones necesarias, en función del modo definido
para la operación (restricto, cascada y nulificación o anulado).
Tipos de Acciones
Instanciación de la Acción
En la acción se puede hacer referencia a los parámetros del evento (respuesta de la condición)
instanciandose de esta forma la acción cuando la regla se activa (respuesta es evaluada por el
sistema de base de datos).
Composición de Acciones
- Secuencia de acciones.
Lenguajes de Reglas
En algunos sistemas de Base de Datos los lenguajes de reglas están limitados a monitorear
solo un evento. En general una regla puede monitorear un conjunto de eventos y ésta es
disparada si cualquiera de ellos ocurrió.
9
A veces la condición puede testear que evento fue el que disparó la regla como por ejemplo
los predicados condicionales en Oracle.
Selección de Reglas
En muchos sistemas varias reglas pueden ser disparadas a la vez, decimos entonces que estas
reglas forman el conjunto conflicto, y el algoritmo que procesa las reglas debe tener una
política para seleccionar las reglas de este conjunto.
En las bases de datos activas, la selección de la siguiente regla a ser procesada típicamente
ocurre antes de la consideración de la regla y posible ejecución. O sea puedo seleccionar todas
las reglas que debo procesar, armar una lista y luego ir tomando de a una hasta que se vacía.
Normalmente los sistemas tienen una manera de definir en que orden se procesan las reglas.
En estos casos las ejecuciones son repetibles, es decir dos ejecuciones de la misma transacción
sobre el mismo estado de la base de datos con el mismo conjunto de triggers da la misma
secuencia de ejecución.
Estrategia de ejecución
Para animar el sistema especificado, se define una estrategia de ejecución e interacción. Esta
estrategia es cercana a las técnicas de realidad virtual, en el sentido de que un objeto activo se
introduce en la sociedad de objetos como miembro de ella e interactúa con los demás enviando
y recibiendo mensajes. Para iniciar una sesión de ejecución, los pasos a seguir son:
11
Activación de servicios
El usuario podrá activar cualquier servicio (evento o transacción) disponible en su visión de la
sociedad. Además, podrá realizar observaciones del sistema (object queries).
Las clases que implementan las tareas de control de acceso y construcción de la vista del
sistema (clases y servicios visibles) se implementarán en el nivel de interfaz. La información
necesaria para configurar la vista del sistema está incluida en la especificación del sistema
(relaciones de agente) obtenida en la fase de modelado conceptual.
Cualquier activación de un servicio tiene dos partes: la construcción del mensaje y la
ejecución (sí es posible).
Introducir los argumentos necesarios para la ejecución del evento: el nivel de interfaz
preguntará por los argumentos del evento que va a activarse (sí es necesario).
Una vez el mensaje se ha enviado, se identifica el objeto servidor (la existencia del objeto
servidor es una condición implícita para ejecutar cualquier evento, excepto si se trata del
evento creación) y se procede a seguir una secuencia de acciones sobre dicho objeto:
Evaluaciones: se modifican los valores de los atributos afectados por la ocurrencia del
servicio (como fuera especificado en el modelo funcional).
Comprobación de las restricciones de integridad: las evaluaciones del servicio deben dejar
al objeto en un estado válido. Se comprueba que no se violan las restricciones de integridad
(estáticas y dinámicas). Si alguna de ellas se viola, se generará una excepción y el cambio de
estado producido se ignorará.
Una vez finalizadas con éxito las acciones precedentes, los componentes de la capa de
persistencia se encargan de actualizar (UPDATE) la BD correspondiente.
Los pasos anteriores guiarán la implementación de cualquier aplicación para asegurar la
equivalencia funcional entre la descripción del sistema, recogida en el modelo conceptual, y su
reificación en un entorno de programación de acuerdo con el modelo de ejecución.
Las fases del modelo de ejecución no se ejecutan necesariamente contiguamente, sino que
dependen de los modos de acoplamiento del evento, de la condición y de la acción.
Acoplamiento Evento-Condición
Determina cuando se evalúa la condición (evaluación) con respecto a la ocurrencia del evento
(Activación).
- Inmediato: La condición se evalúa inmediatamente después de producirse el evento que
activa la regla.
- Diferido: la condición se evalúa en algún instante posterior a la ocurrencia del evento que
activa la regla.
13
Acoplamiento Condición-Acción
Determina cuando se ejecuta la acción (Ejecución) con respecto a la evaluación de la
condición (evaluación).
- Inmediato: la acción se ejecuta inmediatamente después de evaluarse la condición de la
regla.
- Diferido: La acción se ejecuta en algún instante posterior a la evaluación de la condición
de la regla.
Las opciones para los modos de acoplamiento utilizados con más frecuencia son:
Modo de acoplamiento Inmediato: La figura 2.2 nos muestra en forma sencilla este caso,
donde la condición (acción) es evaluada (ejecutada) inmediatamente después del
evento(condición). Los modos inmediatos del acoplador se pueden utilizar, por ejemplo, para
hacer cumplir apremios de la seguridad o propagos de actualizaciones.
Inicio de Transacción
Fin de Transacción
Evaluación
Mientras existan reglas activadas
1. Seleccionar una regla activada R
2. Evaluar la condición de R
3. Si la condición de R es cierta
Ejecutar la acción de R Ejecución
Fin mientras
Inicio de Transacción
Evento
Fin de Transacción
Ejecución de la Acción
Fin Transacción T2
Fin de Transacción T2
Ejecución de la Acción
Fin de Transacción T1
Fin de Transacción T2
Sheduler
Leer/Actualizar Leer
Histórico
Notificación Leer/Actualizar
Base de
Datos
- Intérprete de la base de datos es llamado por el scheduler siempre que una condición de
la regla se evalúe o la acción se haya ejecutado. Este proceso puede requerir información
leída o escrita desde la base de datos, y puede ser posible para el idioma intérprete
reparar ciertas estructuras conforme a lo que ha pasado, mientras se ha usando la
información histórica. Estos accesos que ponen al día la base de datos puede llevar a su
vez el descubrimiento de eventos extensos, mientras la ejecución de la regla ha causado un
proceso para ser repetido.
funcionamiento de la base de datos activa. Las dimensiones más importantes que necesitan
ser consideradas son:
Para explicar con mas detalle, en la Figura 2.8, se observa que en la Arquitectura Física de la
BDA, los Datos y las reglas las almacenan en el mismo lugar físico, dando lugar a todas las
ventajas mencionadas anteriormente.
Optimiz Optimiz
Consult Reglas
Prog APLICACIÓN
De
Reglas
Proces. Gestor
De De
Consul Eventos
DATOS REGLAS
Optimiz
Consult APLICACIÓN
Proces. Consulta SQL
De
Consul
Resultado
DATOS
5.- En las bases de datos pasivas, el número de personal necesario para administrar el Sistema
es mayor; las bases de datos activas necesitan menor número de personal, pero más
especializado.
6.- Los sistemas de bases de datos pasivas son independiente de los datos con respecto a los
tratamientos; las bases de datos activas no sólo son independientes de los datos, sino también
de los eventos.
7.- La base de datos pasiva es coherente, pero generalmente sufre trastornos, ya que la
verificación de la integridad se realiza mediante códigos de procedimientos escritos por los
usuarios; en cambio las bases de datos activas tienen mayor coherencia, debido a la
preocupación por mantener la integridad de la Base de Datos en cada actualización.
8.- La flexibilidad del funcionamiento del sistema de base de datos pasivo está sujeto a la
detección o petición del usuario, quien escribe los eventos mediante el código utilizado por el
Sistema; las bases de datos activas debido a su arquitectura activa ofrece mayor flexibilidad
para atender a demandas cambiantes.
Encapsulamiento de Procedimientos
Esto permite una mayor productividad ya que se pueden normalizar los procesos, sacando
factor común de cierta lógica de los programas que se almacena una sola vez de forma
centralizada.
Permite la Reutilización del código, ya que no es necesario escribirlo cada vez que se quiera
realizar una determinada acción, sino que está almacenado en la Base de Datos, disponible
cada vez que se necesite.
24
Requiere de una interfaz inteligente capas de administrar lar Reglas ECA en forma
Eficiente.
Código
Nombre
Director
telefono
" Los profesores que imparten la asignatura de Código Est1 (Estadística 1) deben ser del
departamento de estadística (Est)". Ver Figura 2.11:
26
Evento
DECLARE X CHAR(4);
BEGIN
- Restauración de la consistencia
- Generación de datos derivados (materialización de vistas)
- Control de la seguridad (accesos permitidos
- Definición de las reglas de funcionamiento interno de la organización.
27
Inventario
Nro_pieza
Descripción Orden_producción
............
cantidda Nro_orden
cant_mínima Nro_pieza
Cantidad
fecha
" Cuando la cantidad en almacén de una pieza esté por debajo de la cantidad mínima
establecida, se debe lanzar un orden de producción para asegurar la cantidad mínima de la
pieza en el almacén", ver Figura 2.13:
Evento
CREATE TRIGGER ordenar_producción
AFTER UPDATE OF cantidad ON Inventario
FOR EACH ROW
WHEN [Link] < NEW.cantidad_minima
Condición
3. Reglas de Integridad
Una regla de integridad esta compuesta por tres componentes, los cuáles son:
La restricción propiamente tal, que establece la condición que deben cumplir los datos.
La respuesta a la transgresión, que especifica las acciones a tomar, como rechazar las
operaciones, informar al usuario, corregir el error con acciones complementarias, etc.
Condición de disparo, que especifica cuando debe desencadenarse la acción especificada en
la restricción de integridad: antes, después o durante cierto evento.
Las reglas de integridad deben almacenarse en el diccionario de datos, como parte integrante
de los datos (como control centralizado de la semántica), de modo que no han de incluirse en
los programas.
Por lo tanto como el término de Integridad de Datos se refiere a la corrección y completitud
de los datos en una base de datos, es decir, que los datos sean correctos, es necesario
implementar por medio de Restricciones en SQL.
Existen 3 tipos de Integridad:
Verificación en 3 momentos:
En realidad, la información puede ser manipulada por muchos programas distintos, el hecho
de que la información sea manipulada por diversos programas hace más difícil garantizar que
todos respetan las reglas, especialmente si las aplicaciones corren en diversas máquinas, bajo
distintos sistemas operativos, y están desarrolladas con distintos lenguajes y herramientas.
Este tipo de Reglas proporcionan Integridad, el cuál es el objetivo central de una BDA.
30
Reglas del Modelo de Datos: El primer grupo de reglas de negocio engloba todas aquellas
reglas que se encargan de controlar que la información básica almacenada para cada atributo o
propiedad de una entidad u objeto es válida: no hay precios de artículos negativos, el sexo de
una persona solo puede ser masculino o femenino, una fecha siempre debe ser una fecha
válida (no existe el 30 de Febrero, ¿cierto?), etc.
Reglas de Relación: Otro grupo importante de reglas incluye todas aquellas reglas que
controlan las relaciones entre los datos. Estas reglas especifican, por ejemplo, que todo pedido
debe ser realizado por un cliente, y que el mismo debe estar dado de alta en nuestro sistema:
además, una vez que un cliente haya hecho algún pedido, se deberá garantizar que no es
posible eliminarlo, a menos que previamente se eliminen todos sus pedidos.
Reglas de Derivación: Es frecuente que a partir de cierta información se pueda derivar otra:
por ejemplo, el total de un pedido se puede calcular a partir de las distintas líneas que lo
componen, mientras que el total de cada línea se puede calcular a partir del número de
unidades vendidas y el precio por unidad. Al conjunto de reglas que especifican y controlan la
obtención de información que se puede calcular a partir de la ya existente se las llama reglas
de derivación.
Reglas de Restricción: Son las que restringen los datos que el sistema puede contener. Nótese
que este grupo de reglas se solapa en cierto modo con las reglas del modelo de datos, dado que
aquellas también impiden la introducción de datos erróneos, como se vio anteriormente. La
diferencia estriba en que las reglas de restricción restringen el valor de los atributos o
propiedades de una entidad más allá de las restricciones básicas que sobre las mismas existen:
por ejemplo, para un saldo existe una regla básica (regla del modelo de datos) que indica que
éste debe ser un número (¡no por obvia es menos regla!), pero, además puede haber una regla
que indique que el saldo nunca puede ser menor que cierta cantidad tope establecida para
cierto tipo de clientes. Esta sería lo que aquí denominamos una regla de restricción, y la
diferencia fundamental estriba en el hecho de que este tipo de reglas requiere para su
verificación del acceso a otros fragmentos de información, algo que no sucede con las reglas
del modelo de datos. Esto tiene ciertas consecuencias que se verán más adelante.
31
Reglas de Flujo: El último grupo de reglas de negocio incluye aquellas reglas que determinan
y limitan cómo fluye la información a través de un sistema. Por ejemplo, un cliente puede
hacer una petición de análisis a un laboratorio, que anota un encargado: hecho esto, se genera
un parte para uno o más analistas, estos realizan las mediciones correspondientes y devuelven
los partes con la información pertinente, a partir de la cuál se genera un informe de análisis,
que será un análisis válido solo cuando sea firmado por los responsables de garantizar su
corrección. A las reglas que indican qué camino recorre la información y obligan a que se
sigan solo los caminos válidos se las llama reglas de flujo.
32
- Diseño conceptual de bases de datos de Batini Ceri, nos entrego información acerca de la
arquitectura lógica de una BD pasiva.
- Active Rules in Database Systems de Norman Paton, nos ayudo a comprender mejor el
comportamiento de las bases de datos activas.
La Figura 5.1, detalla todos los elementos utilizados para poder llevar a acabo la arte practica
de este estudio, para lo cual fue necesario crear una arquitectura básica de una BDA usando
algunos productos de Oracle.
Metodología
CASE
CAD
DESIGNER/
2000
DEVELOPER REPORT
2000
FORMS
BD
Usuario
Especializado
Ingreso Ingreso Consulta Informes
Req Condiciones Acciones Bitácora
Procesos
DBA
Ingreso Ingreso Ingreso
Variables Tablas Eventos
SGBDA
Datos
Packages
5.2 Análisis
5.2.1 Análisis de datos:
MER
EVENTOS
EVENTO
DESCRIPCION
TIPO Desencadena
ev_proc_fk
TABLA
PARTIDA
INTERVAL_DD
INTERVAL_HH Son
INTERVAL_MM registradas
INTERVAL_SS
TRIGGERING proc_bitacora_fk
SENTENCIA
Pertenece
EACH_ROW Son
CONDICION Alma
ACTIVO cenados
JOB_NO Verifica
proc_log_fk
Evalua Evalua Es
verificado
Ev_cond_fk
Tiene
Ev_accion_fk
Es Es Proc_Priv_fk
evaluada evaluada
Pertenece
Puede Puede
tener tener
condicion_fk Accion_fk
Es de Es de
Puede
tener
Es de
SGBDA
Ingreso BDA
Parametros
Condiciones Datos
Procedimientos
Almacenados
Informes
BDA
Manejador Bitacora de
Condiciones Eventos
de Eventos Procesos
Variables Condiciones
Tablas
Package
En nuestra aplicación, la tabla de Eventos es la que almacena todos los Eventos, estos pueden
ser de 2 tipos:
• Tabla: están asociados a un trigger, se ejecuta antes o despues de una inserción,
actualización o eliminación.
• Temporal: están asociados a un Job, se ejecutan a una determinada hora definida por el
usuario.
Cada evento tiene asociado una Condición y una acción, es a través de la Tabla
condiciones_eventos y acciones_eventos que el evento se relaciona con las condiciones y
acciones. Se evalúan las condiciones del evento y si todas son verdaderas ejecuta las
acciones asociadas al evento, siempre y cuando el usuario tenga privilegios.
Esto desencadena finalmente un proceso, el cual tiene los privilegios del usuario para poder
ejecutar la Base de Datos y almacena en la Bitácora de procesos los datos del evento, como la
fecha en que fue ejecutado, el estado en que se encuentra y que usuario lo utilizo, finalmente
en la tabla log_Procesos queda verificado el numero del Proceso según el orden de prioridad
el cual es verificado por la misma Bitácora de Procesos.
Primary key
evento_pk : clave primaria de la tabla eventos
bitacora_pk : clave primaria de la tabla bitacora_procesos
condiciones_pk : clave primaria de la tabla condiciones
acciones_pk : clave primaria de la tabla acciones
privilegios_pk : clave primaria de la tabla privilegios
Foreing Key.
fk_evento_condiciones: Esta clave foránea relaciona la tabla de eventos y
condiciones_eventos.
42
Diagrama de Tablas:
Función get_cond
Parámetro: p_cond
Función que retorna el resultado de la evaluación de la condición p_cond
Función existe_obj
Parámetro: p_obj
Función que retorna TRUE si el objeto existe en la BD y FALSE en caso contrario
Función get_status
Parámetro: p_obj, p_type
función que retorna el STATUS del objeto
Función get_next_date
Parámetro :p_job_no
función que retorna la próxima ejecución del job
Procedimiento create_obj
Parámetros: p_obj, p_cuerpo, p_obj_type, p_return_type
Procedimiento que crea el objeto p_obj de tipo p_type
Procedimiento drop_obj
Parámetro: p_obj, p_type
Procedimiento que borra el objeto p_obj de tipo p_type
Procedimiento drop_job
Parámetro: p_job_no
Procedimiento que borra el job p_job_no
Procedimiento enable_trigger
Parámetro: p_trigger
Función que habilita el Trigger p_trigger asociado al Evento
Procedimiento disable_trigger
Parámetro: p_trigger
Función que deshabilita el Trigger p_trigger asociado al Evento.
Procedimiento active_condicion
Parámetro: p_condicion
Activa la condición, p_condicion, actualizando la tabla condiciones_eventos, para
relacionar la condición con el Evento y la Acción asociada.
45
Procedimiento active_accion
Parámetro: p_accion
Activa la Acción, p_accion, actualizando la tabla acciones_eventos.
Procedimiento desactive_condicion
Parámetro: p_condicion
Desactiva la condicion, p_condicion, actualizando la tabla condiciones_eventos.
Procedimiento desactive_accion
Parámetro: p_accion
Desactiva la Acción, p_accion, actualizando la tabla acciones_eventos.
Procedimiento ins_bitacora
Parámetros: p_evento, p_status, p_glosa
Inserta en la Bitacora de Procesos el Evento(p_evento), el estado del Evento, p_status,
(Valido o Invalido) y la descripción del Evento.
Función get_privilegio
Parámetros: p_evento, p_user
Función que retorna TRUE si el evento y el usuario se encuentran en la tabla de privilegios
FALSE en caso contrario
46
5.4. Construcción
5.4.1 Construcción de la Base de datos
Scripts de creación:
drop table eventos
/
create table eventos (
evento varchar2(30) not null,
descripcion varchar2(100) not null,
tipo varchar2(15) not null, -- tabla / temporal
tabla varchar2(30), -- nombre de tabla
partida date, -- fecha y hora de la primera ejecucion
interval_dd number, -- periodicidad de ejecucion en dias
interval_hh number, -- periodicidad de ejecucion en horas
interval_mm number, -- periodicidad de ejecucion en minutos
interval_ss number, -- periodicidad de ejecucion en segundos
triggering varchar2(10), -- before /after
sentencia varchar2(10), -- insert, update, delete
each_row varchar2(1), -- 'Y' or 'N'
condicion varchar2(200), -- condicion activacion
activo varchar2(1) not null, -- registro habilitado (S/N)
job_no number -- nro de job
)
/
drop table condiciones
/
create table condiciones (
condicion varchar2(30) not null,
descripcion varchar2(100) not null,
expresion varchar2(2000) not null,
activo varchar2(1) not null -- registro activo (S/N)
)
/
drop table acciones
/
create table acciones (
accion varchar2(30) not null,
descripcion varchar2(100) not null,
codigo_pl_java varchar2(2000) not null,
activo varchar2(1) not null -- registro habilitado (S/N)
)
/
drop table condiciones_eventos
/
create table condiciones_eventos (
evento varchar2(30) not null,
condicion varchar2(30) not null,
47
Eventos
La pantalla Eventos de la Figura 5.5, es una pantalla importante, en donde esta el evento a
ejecutarse, las condiciones y las acciones asociadas a ese evento que ejecuta la acción una vez
que la condición sea verdadera, podemos observar diferentes campos, los cuáles son:
Name ON-CLEAR-DETAILS
Class <Null>
Trigger Text
-- Begin default relation program section
BEGIN
Clear_All_Master_Details;
END;
-- End default relation program section
Name ON-CHECK-DELETE-MASTER
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
Dummy_Define CHAR(1);
-- Begin CONDICIONES_EVENTOS detail declare section
CURSOR CONDICIONES_EVENTOS_cur IS
SELECT 1 FROM CONDICIONES_EVENTOS
WHERE EVENTO = :[Link];
-- End CONDICIONES_EVENTOS detail declare section
-- Begin ACCIONES_EVENTOS detail declare section
CURSOR ACCIONES_EVENTOS_cur IS
52
Name POST-CHANGE
Class <Null>
Trigger Text
if :system.record_status in ('NEW','INSERT') THEN
if existe_obj THEN
msg1('Ya existe objeto '||:[Link]);
raise form_trigger_failure;
end if;
end if;
:[Link] := get_status;
if :[Link] = 'VALID' THEN
if :[Link] = 'TEMPORAL' THEN
:eventos.prox_ejec :=
to_char(pkg_sys.get_next_date(:eventos.job_no),'DD/MM/YYYY HH24:MI:SS');
else
:eventos.prox_ejec := null;
end if;
else
:eventos.prox_ejec := null;
:[Link] := 'N';
end if;
Name WHEN-VALIDATE-ITEM
Class <Null>
Trigger Text
if :[Link] = 'TEMPORAL' THEN
if :[Link] <= sysdate THEN
msg1('La hora del evento debe ser en el futuro');
raise form_trigger_failure;
54
end if;
end if;
Triggers
Name WHEN-CHECKBOX-CHANGED
Class <Null>
Trigger Text
if :[Link] <> 'INVALID' THEN
if :[Link] = 'S' THEN
enable_evento;
else
disable_evento;
end if;
else
:[Link] := 'N';
end if;
Triggers
Name POST-CHANGE
Class <Null>
Trigger Text
select descripcion
into :condiciones_eventos.desc_cond
from condiciones
where condicion = :condiciones_eventos.condicion;
EXCEPTION
WHEN others THEN
msg1('Ha ocurrido un error, buscando condicion P-CH, condicion');
raise form_trigger_failure;
Triggers
Name POST-CHANGE
Class <Null>
Trigger Text
select descripcion
into :acciones_eventos.desc_accion
from acciones
where accion = :acciones_eventos.accion;
EXCEPTION
WHEN others THEN
msg1('Ha ocurrido un error, buscando condicion P-CH, accion');
raise form_trigger_failure;
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
RAISE Form_Trigger_Failure;
55
END IF;
END;
BEGIN
-- Init Local Vars
56
mastblk := :System.Master_Block;
coordop := :System.Coordination_Operation;
trigblk := :System.Trigger_Block;
startitm := :System.Trigger_Item;
frmstat := :System.Form_Status;
-- If the coordination operation is anything but CLEAR_RECORD or
-- SYNCHRONIZE_BLOCKS, then continue checking.
IF coordop NOT IN ('CLEAR_RECORD', 'SYNCHRONIZE_BLOCKS') THEN
-- If we're processing the driving master block...
IF mastblk = trigblk THEN
-- If something in the form is changed, find the
-- first changed block below the master
IF frmstat = 'CHANGED' THEN
curblk := First_Changed_Block_Below(mastblk);
-- If we find a changed block below, go there
-- and Ask to commit the changes.
IF curblk IS NOT NULL THEN
Go_Block(curblk);
Check_Package_Failure;
Clear_Block(ASK_COMMIT);
-- If user cancels commit dialog, raise error
IF NOT ( :System.Form_Status = 'QUERY'
OR :System.Block_Status = 'NEW' ) THEN
RAISE Form_Trigger_Failure;
END IF;
END IF;
END IF;
END IF;
END IF;
-- Clear all the detail blocks for this master without
-- any further asking to commit.
currel := Get_Block_Property(trigblk, FIRST_MASTER_RELATION);
WHILE currel IS NOT NULL LOOP
curdtl := Get_Relation_Property(currel, DETAIL_NAME);
IF Get_Block_Property(curdtl, STATUS) <> 'NEW' THEN
Go_Block(curdtl);
Check_Package_Failure;
Clear_Block(NO_VALIDATE);
IF :System.Block_Status <> 'NEW' THEN
RAISE Form_Trigger_Failure;
END IF;
END IF;
currel := Get_Relation_Property(currel, NEXT_MASTER_RELATION);
END LOOP;
-- Put cursor back where it started
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
Check_Package_Failure;
57
END IF;
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
END Clear_All_Master_Details;
:[Link] := 'S';
EXCEPTION
WHEN others THEN
msg1('Error al cerear job: '||:[Link]||': '||SQLERRM);
raise form_trigger_failure;
END;
raise form_trigger_failure;
end;
execute_query;
END IF;
end;
end if;
END;
go_block('EVENTOS');
commit;
drop_evento;
create_evento;
e_query;
:[Link] := get_status;
if nvl(:[Link],'INVALID') = 'INVALID' THEN
:[Link] := 'N';
-- commit_mudo;
end if;
msg1('El evento ha sido compilado');
end if;
END;
EXCEPTION
WHEN Form_Trigger_Failure THEN
:System.Message_Level := oldmsg;
RAISE;
END Query_Master_Details;
set_item_property('[Link]',UPDATEABLE,PROPERTY_TRUE);
set_item_property('[Link]',REQUIRED,PROPERTY_TRUE);
set_item_property('[Link]',ENABLED,PROPERTY_TRUE);
set_item_property('[Link]',UPDATEABLE,PROPERTY_TRUE);
set_item_property('[Link]',REQUIRED,PROPERTY_TRUE);
set_item_property('EVENTOS.EACH_ROW',ENABLED,PROPERTY_TRUE);
set_item_property('EVENTOS.EACH_ROW',UPDATEABLE,PROPERTY_TRUE);
set_item_property('[Link]',ENABLED,PROPERTY_FALSE);
set_item_property('[Link]',REQUIRED,PROPERTY_FALSE);
set_item_property('[Link]',UPDATEABLE,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_DD',ENABLED,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_DD',REQUIRED,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_DD',UPDATEABLE,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_HH',ENABLED,PROPERTY_FALSE);
64
set_item_property('EVENTOS.INTERVAL_HH',REQUIRED,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_HH',UPDATEABLE,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_MM',ENABLED,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_MM',REQUIRED,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_MM',UPDATEABLE,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_SS',ENABLED,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_SS',REQUIRED,PROPERTY_FALSE);
set_item_property('EVENTOS.INTERVAL_SS',UPDATEABLE,PROPERTY_FALSE);
ELSE
set_item_property('[Link]',ENABLED,PROPERTY_FALSE);
set_item_property('[Link]',REQUIRED,PROPERTY_FALSE);
set_item_property('[Link]',UPDATEABLE,PROPERTY_FALSE);
set_item_property('[Link]',ENABLED,PROPERTY_FALSE);
set_item_property('[Link]',REQUIRED,PROPERTY_FALSE);
set_item_property('[Link]',UPDATEABLE,PROPERTY_FALSE);
set_item_property('[Link]',ENABLED,PROPERTY_FALSE);
set_item_property('[Link]',REQUIRED,PROPERTY_FALSE);
set_item_property('[Link]',UPDATEABLE,PROPERTY_FALSE);
set_item_property('EVENTOS.EACH_ROW',ENABLED,PROPERTY_FALSE);
set_item_property('EVENTOS.EACH_ROW',UPDATEABLE,PROPERTY_FALSE);
set_item_property('[Link]',ENABLED,PROPERTY_TRUE);
set_item_property('[Link]',UPDATEABLE,PROPERTY_TRUE);
set_item_property('[Link]',REQUIRED,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_DD',ENABLED,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_DD',UPDATEABLE,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_DD',REQUIRED,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_HH',ENABLED,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_HH',UPDATEABLE,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_HH',REQUIRED,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_MM',ENABLED,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_MM',UPDATEABLE,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_MM',REQUIRED,PROPERTY_TRUE);
65
set_item_property('EVENTOS.INTERVAL_SS',ENABLED,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_SS',UPDATEABLE,PROPERTY_TRUE);
set_item_property('EVENTOS.INTERVAL_SS',REQUIRED,PROPERTY_TRUE);
END IF;
END;
5.4.3 Reportes:
Reporte de Eventos
En base a la relación de los Eventos con las tablas Condiciones_ Evento y Acciones_ Evento,
se basó la construcción del Form, para accesar y mantener un buen funcionamiento de los
datos en la Base de datos, además la interfaz muestra claramente cuales son las condiciones y
acciones asociadas al estado del Evento que también se muestra en Pantalla.
Eventos
Condiciones_ Acciones_
Evento Evento
Reporte de Condiciones
En las Condiciones, la relación con la tabla condiciones_eventos, almacena, esta ultima tabla,
todas las condiciones posibles asociada a cada Evento, para esto se implementó una Interfaz,
con todas las condiciones existentes y un checkbox, al lado del texto que contiene la
Condición, con la finalidad que el administrador del Sistema habilite o deshabilite la
Condición cuando se requiera.
CONDICIONES DESCRIPCION
ERNC Existe reserva no Confirmada
ESAN Existe Sanción
ESSANCIO Usuario esta Sancionado
Reporte de Acciones
En las acciones, la relación con la tabla acciones_eventos, almacena, esta ultima tabla, todas
las acciones posibles asociada a cada Evento, para esto se implementó una Interfaz, con todas
las acciones existentes y un checkbox, al lado del texto que contiene la accion, con la finalidad
que el administrador del Sistema habilite o deshabilite la accion cuando se requiera.
ACCION DESCRIPCION
SANCIÓN Genera Sanción
BORRASAN Borra Sanciones
RECHASANC Rechazar Sanción
La bitácora del Evento esta relacionada con el Evento, ya que almacena todo el historial del
comportamiento de cada Evento que se ha programado en el Sistema, en este caso se
construyo una Interfaz que básicamente contiene los atributos mas importantes de la Tabla
Eventos, para que el administrador del Sistema pueda ver que ha sucedido o está sucediendo
con la Base de datos en cada momento.
5.4.4 Package, módulo de programa almacenado en la base de datos: nivel Servidor coya
funcioón es de proveer el motor de la BDA utilizando tecnología BD Relacional y
actividad nativa ORACLE):
------------------------------------------------------------------------------------------
procedure desactive_condicion(p_condicion in varchar2);
------------------------------------------------------------------------------------------
procedure desactive_accion(p_accion in varchar2);
------------------------------------------------------------------------------------------
procedure ins_bitacora(p_evento in varchar2, p_status in varchar2, p_glosa in varchar2);
------------------------------------------------------------------------------------------
function get_privilegio(p_evento in varchar2, p_user in varchar2) return boolean;
------------------------------------------------------------------------------------------
end pkg_sys;
/
create or replace package body pkg_sys as
---------------------------------------------------------------------------function submit_job(p_proc in
varchar2, p_fecha in date, p_interval in varchar2) return number is
--
-- procedimiento que submite un proceso oracle p_proc, para su ejecucion en la fecha p_fecha
-- con un intervalo de ejecucion p_intervalo medido en segundos
--
v_job number;
begin
dbms_job.submit(v_job,p_proc,p_fecha,p_interval);
return(v_job);
exception
when others then
raise_application_error(-20200,' pkg_sys.submit_job: '||SQLERRM);
end submit_job;
---------------------------------------------------------------------------
function get_tipo_evento(p_evento in varchar2) return varchar2 is
--
-- funcion que retorna el tipo de evento (temporal o tabla)
--
salida varchar2(15);
BEGIN
select tipo
into salida
from eventos
where evento = p_evento;
return(salida);
EXCEPTION
WHEN no_data_found THEN
return(null);
WHEN others THEN
raise_application_error(-20200,' pkg_sys.get_tipo_evento : evento: '||p_evento||':
'||SQLERRM);
--
END get_tipo_evento;
---------------------------------------------------------------------------
procedure execute_eca(p_evento in varchar2) is
72
--
-- procedimiento que verifica las condiciones del evento p_evento y si todas son verdaderas
-- ejecuta las acciones asociadas al evento p_evento, solo si el usuario tiene privilegios
--
cursor c_cond is
select condicion
from condiciones_eventos
where evento = p_evento
and activo = 'S'
order by prioridad;
--
cursor c_acc is
select accion
from acciones_eventos
where evento = p_evento
and activo = 'S'
order by prioridad;
--
v_cond boolean;
v_num_condiciones number;
v_num_condiciones_err number;
v_num_no_cumple number;
v_num_acciones number;
v_num_acciones_err number;
v_tipo_evento varchar2(15);
--
begin
--
ins_bitacora(p_evento,'INICIO','Inicio ejecucion regla ECA');
--
-- verifica privilegios
--
if get_privilegio(p_evento,user) then
--
-- tipo de evento
--
v_tipo_evento := get_tipo_evento(p_evento);
--
-- condiciones
--
v_num_condiciones := 0;
v_num_no_cumple := 0;
v_num_condiciones_err := 0;
--
for i in c_cond loop
begin
v_cond := get_cond([Link]);
if v_cond THEN
73
v_num_condiciones := v_num_condiciones + 1;
else
v_num_no_cumple := v_num_no_cumple + 1;
ins_bitacora(p_evento,'NO CUMPLE CONDICION',' Condicion: '||[Link]);
end if;
EXCEPTION
WHEN others THEN
v_num_condiciones_err := v_num_no_cumple + 1;
ins_bitacora(p_evento,'ERROR','Error en condicion: '||[Link]||': '||SQLERRM);
end;
end loop;
--
if v_num_no_cumple = 0 and v_num_condiciones_err = 0 THEN
if v_num_condiciones = 0 THEN
ins_bitacora(p_evento,'EN PROCESO','Evento sin condiciones');
else
ins_bitacora(p_evento,'EN PROCESO','Cumple: '||v_num_condiciones||', todas las
condiciones');
end if;
else
if v_num_condiciones_err = 0 THEN
if v_tipo_evento = 'TABLA' THEN
ins_bitacora(p_evento,'FIN DE PROCESO','No cumple: '||v_num_no_cumple||'
condiciones');
raise_application_error(-20200,'No cumple: '||v_num_no_cumple||' condiciones');
else
ins_bitacora(p_evento,'FIN DE PROCESO','No cumple: '||v_num_no_cumple||'
condiciones');
return;
end if;
else
if v_num_no_cumple = 0 THEN
if v_tipo_evento = 'TABLA' THEN
ins_bitacora(p_evento,'FIN CON ERROR',v_num_condiciones_err||' condiciones
(todas) erroneas');
raise_application_error(-20200,'ERROR: '||v_num_condiciones_err||' condiciones
(todas) erroneas');
else
ins_bitacora(p_evento,'FIN CON ERROR',v_num_condiciones_err||' condiciones
(todas) erroneas');
return;
end if;
else
if v_tipo_evento = 'TABLA' THEN
ins_bitacora(p_evento,'FIN CON ERROR','No se cumplen '||v_num_no_cumple||
'condiciones y '||v_num_condiciones_err||' erroneas');
raise_application_error(-20200,'ERROR: No se cumplen '||v_num_no_cumple||
'condiciones y '||v_num_condiciones_err||' erroneas');
74
else
ins_bitacora(p_evento,'FIN CON ERROR','No se cumplen '||v_num_no_cumple||
'condiciones y '||v_num_condiciones_err||' erroneas');
return;
end if;
end if;
end if;
end if;
--
-- acciones
--
v_num_acciones := 0;
v_num_acciones_err := 0;
for i in c_acc loop
begin
execute_acc([Link]);
v_num_acciones := v_num_acciones + 1;
Exception
WHEN others THEN
v_num_acciones_err := v_num_acciones_err + 1;
ins_bitacora(p_evento,'ERROR','Error en accion: '||[Link]||': '||SQLERRM);
end;
end loop;
if v_num_acciones_err = 0 THEN
if v_num_acciones = 0 THEN
ins_bitacora(p_evento,'FIN DE PROCESO','Evento sin acciones');
else
ins_bitacora(p_evento,'FIN DE PROCESO','Se procesaron: '||v_num_acciones||', todas
las acciones');
return;
end if;
else
ins_bitacora(p_evento,'FIN CON ERROR',v_num_acciones_err||' acciones con error');
return;
end if;
else
ins_bitacora(p_evento,'ERROR','Usuario: '||user||' no tiene privilegios para ejecutar evento:
'||p_evento);
end if;
EXCEPTION
WHEN others THEN
if v_tipo_evento = 'TABLA' THEN
raise_application_error(-20200,'ERROR:'||substr(SQLERRM,1,2000));
else
ins_bitacora(p_evento,'ERROR',substr(SQLERRM,1,2000));
end if;
--
end execute_eca;
75
------------------------------------------------------------------------------------------
procedure create_tab(p_table in varchar2) is
--
-- procedimiento que crea una tabla correspondiente a la tabla p_table
--
v_cuerpo varchar2(8000) := null;
begin
for i in (select orden, columna, tipo, tamano, nula
from columnas_tablas
where tabla = p_table
order by orden) loop
--
begin
select v_cuerpo||decode([Link],1,null,',')||[Link]||' '||[Link]||
decode([Link],'VARCHAR2','('||[Link]||') ',' ')||
decode([Link],'N','NOT NULL',null)||chr(10)
into v_cuerpo
from dual;
Exception
WHEN others THEN
raise_application_error(-20201,' pkg_sys.create_table: '||SQLERRM);
end;
end loop;
create_obj(p_table,v_cuerpo,'TABLE',null);
EXCEPTION
WHEN others THEN
raise_application_error(-20202,' pkg_sys.create_tab: '||SQLERRM);
--
end create_tab;
------------------------------------------------------------------------------------------
procedure create_pack_tab(p_table in varchar2) is
--
-- procedimiento que crea un package asociado a la tabla p_table con variables
-- correspondientes a las columnas de la tabla
--
v_pack varchar2(8000) := null;
begin
for i in (select column_name, data_type, data_length
from user_tab_columns
where table_name = p_table) loop
--
begin
select v_pack||'new_'||i.column_name||' '||i.data_type||
decode(i.data_type,'VARCHAR2','('||i.data_length||'); ','; ')||chr(10)||
'old_'||i.column_name||' '||i.data_type||
decode(i.data_type,'VARCHAR2','('||i.data_length||'); ','; ')||chr(10)
into v_pack
from dual;
76
Exception
WHEN others THEN
raise_application_error(-20201,' pkg_sys.create_pack_tab: '||SQLERRM);
end;
end loop;
create_obj('g_'||p_table,v_pack,'PACKAGE',null);
EXCEPTION
WHEN others THEN
raise_application_error(-20202,' pkg_sys.create_pack_tab: '||SQLERRM);
--
end create_pack_tab;
------------------------------------------------------------------------------------------
function get_new_old_str(p_table in varchar2) return varchar2 is
--
-- funcion que retorna un string con las asignaciones de las variables new y old
-- correspondientes a las columnas de la tabla
--
v_str varchar2(8000) := null;
begin
for i in (select column_name, data_type, data_length
from user_tab_columns
where table_name = p_table) loop
--
begin
select v_str||'g_'||p_table||'.'||'new_'||i.column_name||' := :new.'||i.column_name||'; '||
'g_'||p_table||'.'||'old_'||i.column_name||' := :old.'||i.column_name||'; '
into v_str
from dual;
Exception
WHEN others THEN
raise_application_error(-20201,' pkg_sys.get_new_old_str: '||SQLERRM);
end;
end loop;
return(v_str);
--
end get_new_old_str;
------------------------------------------------------------------------------------------
procedure execute_acc(p_acc in varchar2) is
--
-- procedimiento que ejecuta una accion p_acc.
--
v_tex varchar2(200);
BEGIN
v_tex := 'begin '||
p_acc||'; '||
'end;';
--
execute_str(v_tex);
77
EXCEPTION
WHEN others THEN
raise_application_error(-20200,' pkg_sys.execute_acc: p_acc: '||p_acc||': '||SQLERRM);
--
END execute_acc;
------------------------------------------------------------------------------------------
procedure execute_str(p_str in varchar2) is
--
-- ejecuta una instruccion ddl p_ddl
--
v_cursor number;
v_ret number;
--
BEGIN
--
v_cursor := dbms_sql.open_cursor;
DBMS_SQL.PARSE(v_cursor,p_str,2);
v_ret := DBMS_SQL.EXECUTE(v_cursor);
DBMS_SQL.CLOSE_CURSOR(v_cursor);
EXCEPTION
WHEN others THEN
raise_application_error(-20200,' pkg_sys.execute_str: '||SQLERRM);
--
END execute_str;
------------------------------------------------------------------------------------------
function get_cond(p_cond in varchar2) return boolean is
--
-- funcion que retorna el resultado de la evaluacion de la condicion p_cond
--
v_cursor number;
v_tex varchar2(200);
BEGIN
v_tex := 'begin '||
'pkg_sys.g_valor_cond := '||p_cond||'; '||
'end;';
--
execute_str(v_tex);
return(g_valor_cond);
EXCEPTION
WHEN others THEN
raise_application_error(-20200,' pkg_sys.get_cond: p_cond: '||p_cond||': '||SQLERRM);
--
END get_cond;
------------------------------------------------------------------------------------------
function existe_obj(p_obj in varchar2) return boolean is
--
-- funcion que retorna TRUE si el objeto existe en la BD y FALSE en caso contrario
--
78
v_dummy varchar2(1);
BEGIN
select 'x'
into v_dummy
from user_objects
where object_name = p_obj
and rownum = 1;
return(TRUE);
EXCEPTION
WHEN no_data_found THEN
return(FALSE);
WHEN others THEN
raise_application_error(-20200,' pkg_sys.existe_obj: objeto: '||p_obj||': '||SQLERRM);
--
END existe_obj;
------------------------------------------------------------------------------------------
function get_status(p_obj in varchar2, p_type in varchar2) return varchar2 is
--
-- funcion que retorna el STATUS del objeto
--
salida varchar2(30);
BEGIN
select status
into salida
from user_objects
where object_name = p_obj
and object_type = p_type;
return(salida);
EXCEPTION
WHEN no_data_found THEN
return(null);
WHEN others THEN
raise_application_error(-20200,' pkg_sys.get_status: objeto: '||p_obj||', tipo: '||p_type||':
'||SQLERRM);
--
END get_status;
------------------------------------------------------------------------------------------
function get_next_date(p_job_no in number) return date is
--
-- funcion que retorna la proxima ejecucion del job
--
salida date;
BEGIN
select next_date
into salida
from user_jobs
where job = p_job_no;
return(salida);
79
EXCEPTION
WHEN no_data_found THEN
return(null);
WHEN others THEN
raise_application_error(-20200,' pkg_sys.get_next_date: job: '||p_job_no||': '||SQLERRM);
--
END get_next_date;
------------------------------------------------------------------------------------------
procedure create_obj(p_obj in varchar2, p_cuerpo in varchar2,
p_obj_type in varchar2, p_return_type in varchar2) is
v_return_type varchar2(15);
BEGIN
if p_obj_type = 'PROCEDURE' THEN
execute_str('create or replace procedure '||p_obj||' as '||
'BEGIN '||
p_cuerpo||' '||
'EXCEPTION '||
'WHEN others THEN '||
'raise_application_error(-20200,'' Error en procedure: '||p_obj||':
''||SQLERRM); '||
'END;');
elsif p_obj_type = 'FUNCTION' THEN
begin
select decode(p_return_type,'VARCHAR2','varchar2(200)',p_return_type)
into v_return_type
from dual;
execute_str('create or replace function '||p_obj||' return '||p_return_type||' as '||chr(10)||
p_obj||' '||v_return_type||'; '||chr(10)||
'BEGIN '||
p_cuerpo||' '||
'return('||p_obj||'); '||chr(10)||
'EXCEPTION '||
'WHEN others THEN '||
'raise_application_error(-20200,'' Error en function: '||p_obj||':
''||SQLERRM); '||
'END;');
end;
elsif p_obj_type = 'PACKAGE' THEN
execute_str('create or replace package '||p_obj||' as '||chr(10)||p_cuerpo||' END;');
elsif p_obj_type = 'TABLE' THEN
drop_obj(p_obj,'TABLE');
execute_str('create table '||p_obj||' ('||chr(10)||p_cuerpo||')');
elsif p_obj_type = 'TRIGGER' THEN
execute_str('CREATE OR REPLACE TRIGGER '||p_obj||' '||chr(10)||p_cuerpo);
else
raise_application_error(-20200,' No existe tipo de objeto: '||p_obj_type);
end if;
EXCEPTION
80
update condiciones_eventos
set activo = 'N'
where condicion = p_condicion;
EXCEPTION
WHEN others THEN
raise_application_error(-20200,' pkg_sys.desactive_condicion: '||p_condicion||':
'||SQLERRM);
end desactive_condicion;
------------------------------------------------------------------------------------------
procedure desactive_accion(p_accion in varchar2) is
BEGIN
update acciones_eventos
set activo = 'N'
where accion = p_accion;
EXCEPTION
WHEN others THEN
raise_application_error(-20200,' pkg_sys.desactive_accion: '||p_accion||': '||SQLERRM);
end desactive_accion;
------------------------------------------------------------------------------------------
procedure ins_bitacora(p_evento in varchar2,p_status in varchar2,p_glosa in varchar2) is
begin
insert into bitacora_procesos
values(p_evento,sec_proc.nextval,sysdate,user,p_status,p_glosa);
end ins_bitacora;
------------------------------------------------------------------------------------------
function get_privilegio(p_evento in varchar2, p_user in varchar2) return boolean is
--
-- funcion que retorna TRUE si el evento y el usuario se encuentra en la tabla de privilegios
-- y FALSE en caso contrario
--
v_dummy varchar2(1);
BEGIN
select 'x'
into v_dummy
from privilegios
where evento = p_evento
and usuario = p_user;
return(TRUE);
EXCEPTION
WHEN no_data_found THEN
return(FALSE);
WHEN others THEN
raise_application_error(-20200,' pkg_sys.get_privilegio: evento: '||p_evento||' usuario
'||p_user||SQLERRM);
--
end get_privilegio;
------------------------------------------------------------------------------------------
end pkg_sys;
83
6. Pruebas
Para realizar las pruebas, es necesario crear 2 tablas: Reservas y Sanciones, tal como se
muestra en la Figura 6.1:
Tabla: Reservas
Campos:
Pista number
Fecha date
Rut number
Confirmada varchar 2(1)
Tabla: Sanciones
Campos:
rut number
Fecha date
RESERVAS
PISTA
FECHA
RUT
CONFIRMADA
M
SANCIONES
RUT
FECHA
Reglas del Negocio, expresadas como condiciones ECA: (Evento, Condición, Acción)
1. Cada día a las 24 hrs. Si existe reserva no confirmada generar una sanción:
Implementación:
C: Condición: ERNC
Expresión: RNC = 1
A: Acción: SANCION
Expresión:
La Figura 6.2 nos muestra a continuación la implementacion del ejemplo dado anteriormente:
2. Cada día a las 24 hrs. Si existe una sanción que termina en la fecha se debe borrar:
Implementación:
C: Condición: ESAN
Descripción: EXISTE SANCION
Expresión: ESANCION = 1
A: Acción: BORRASANC
Descripción: BORRA SANCIONES
Expresión:
FOR I IN (SELECT RUT, ROWID RWD FROM SANCIONES WHERE
TRUNC(FECHA)=TRUNC(SYSDATE))
LOOP
E: Al realizar la reserva
C: Usuario sancionado
A: Rechazar la reserva
Implementación:
C: Condición: ESSANCION
Descripción: USUARIO ESTA SANCIONADO
Expresión: SANCIONADO = 1
A: Acción: RECHSANC
Descripción: RECHAZAR SANCION
Expresión:
BEGIN
RAISE_APLICCATION_ERROR(-20200,’USUARIO TIENE SANCION
PENDIENTE’);
END;
Variable: RNC
Tipo: NUMBER
Expresión:
BEGIN
SELECT 1
INTO RNC
FROM DUAL
WHERE EXISTS ( SELECT 'X'
FROM RESERVAS
WHERE NVL(CONFIRMADA,'N' )='N'
AND TRUNC(FECHA)=TRUNC(SYSDATE));
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 0;
END;
Variable: ESANCION
Tipo: NUMBER
Expresión:
BEGIN
SELECT 1
INTO ESANCION
FROM DUAL
WHERE EXISTS (SELECT 'X'
FROM SANCIONES
WHERE TRUNC(FECHA)=TRUNC(SYSDATE));
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 0;
END;
90
Variable: SANCIONADO
Tipo: NUMBER
Expresión:
SELECT 1
INTO SANCIONADO
FROM DUAL
WHERE EXISTS (
SELECT ‘X’
FROM SANCIONES
WHERE RUT = G_SANCIONES.NEW_RUT)
UNION
SELECT 0
FROM DUAL
WHERE NOT EXISTS(
SELECT ‘X’
FROM SANCIONES
WHERE RUT = G_SANCIONES.NEW_RUT);
Form de PRUEBAS: a través de este se ingresan los datos para realizar las pruebas, como se
ilustra en la Figura 6.5:
Al no ser confirmada la reserva, la Base de Datos Activa esta programada para ejecutarse a
las 12:11 P.M en el evento genera sanciones y así el usuario estará sancionado e
inhabilitado para realizar otra reserva, como se ilustra en la Figura 6.6:
Y en la bitácora, la Base de Datos Activa ha dejado al usuario del RUT 1007 sancionado,
como se ilustra en la Figura 6.7:
92
Al tratar entonces el mismo de usuario de pedir una nueva reserva. La Base de Datos Activa
no lo dejara ya que el usuario esta con sanción pendiente, enviando un mensaje de error,
como se ilustra en la Figura 6.8:
93
Quedando ahora en la bitácora el usuario sin sanción y habilitado para poder realizar otra
reserva, la Figura 6.10 muestra que el Evento Borrado de Sanciones se ha ejecutado
satisfactoriamente.
Se pueden definir por ejemplo el tiempo en que se define un evento (i) y Rj la hora en que el
registro (j) se torna consistente debido a la actividad de la base de datos.
Tij = Rj – Ei Con Ri > Ej (puesto que cada registro se torna consistente en un tiempo posterior
al que se define el evento) y Ei es fijo para cada evento (Esto para los eventos de tipo temporal
en el caso de los eventos de tipo tabla, el tiempo de respuesta es casi instantáneo).
Entonces el tiempo promedio (definido por Tip) en que se encuentra inconsistente la base de
datos respecto del evento i es:
Suma(Tij)
Tip = ------------
N
97
Con las pruebas realizadas se generaron 1000 registros para los cuales se midió el tiempo que
se demoró en ser afectado por el evento, la moda del tiempo inconsistente es 41 segundos para
757 registros.
Con las pruebas realizadas se generaron 1000 registros para los cuales se midió el tiempo que
se demoró en ser afectado por el evento, la moda del tiempo inconsistente es 41 segundos para
757 registros.
A) GENERACIÓN DE SANCIONES
RUT
MUESTRA:
1001
.
.
.
.
1196
15:00 Hrs.
43 Seg.: volvió a ejecutarse y genero sanción nuevamente desde el Rut 1001 al 1196
Ya que la Base de Datos Activa estaba Programada para ejecutarse cada 1
Hr.
99
Con las pruebas realizadas se generaron 196 registros para los cuales se midió el tiempo que se
demoró en ser afectado por el evento, la moda del tiempo inconsistente es 41 segundos para
157 registros.
B) BORRADO DE SANCIONES
Calculo Matemático En El Que La Base De Datos Se Demora En Garantizar La Integridad De
Los Datos Para El Borrado De Sanciones.
RUT
MUESTRA:
1001
.
.
.
.
1196
Con las pruebas realizadas se generaron 196 registros para los cuales se midió el tiempo que se
demoró en ser afectado por el evento Borrado de Sanciones, la moda del tiempo inconsistente
es 41 segundos para 196 registros.
7. Conclusiones
El comportamiento de las reglas de integridad se puede analizar desde dos puntos de vista:
Comportamiento "Reactivo"
Una base de datos con comportamiento reactivo es aquella en la que cada vez que se produce
un evento se ejecuta la acción.
Comportamiento "Proactivo"
La base de datos es la que ejecuta las reglas de manera proactiva se cumplan o no se cumplan
las condiciones. Si estás se cumplen ve a que evento pertenece y en ese momento ejecuta la
acción.
En el caso de nuestra Base de Datos Activa normalmente es de ambos tipos. En cambio una
base de datos pasiva puede tener a lo sumo un comportamiento reactivo y con pocas
posibilidades de modificación de las Reglas, pero si tiene la integridad fuertemente asegurada
pero en un dominio mucho más reducido. En el caso de la base de datos activa esta seguridad
de dominio es más amplia pero más débil.
Pero si, se gana en flexibilidad por parte del usuario. No se garantiza en intervalos de tiempo
pequeño, pero si en intervalos de tiempo más grande, depende de la estabilidad de la base de
datos. La estabilidad de la base de datos activa puede ser menor, ya que necesita de más
procesos que la estén chequeando constantemente.
Esto puede ser despreciable con el advenimiento de procesadores más rápidos y sistemas de
gestión de bases de datos más estables.
Como conclusión del tema de la integridad es claro que las Bases de Datos Activas son de un
dominio mucho más amplio y flexibles que las bases de datos pasiva, sin embargo, esta última
es más segura pero mucho más limitada.
103
8. Anexos
Anexo A : Oracle
Introducción
Oracle es la base de datos más extensamente usada en todo el mundo, es potente y altamente
eficiente. Corre virtualmente sobre cualquier tipo de computador. Funciona sobre cualquier
máquina, así que cuando se aprende a usar en una de ellas, puede usarse en cualquier máquina.
Oracle dispone de un motor principal para la gestión de Bases de Datos basado en Lenguaje
SQL estándar, éste permite la creación de perfiles de usuarios y esquemas físicos de Bases de
datos de cualquier envergadura o tamaño. En él es posible almacenar Tablas y procedimientos
escritos en un lenguaje de programación llamado PL/SQL que comparte con otros productos
de la familia Oracle permitiendo gestionar los datos almacenados.
Oracle dispone de varios otros productos para apoyar la construcción de software orientado a
la gestión de Bases de Datos tales como: Designer/2000, un producto para dar soporte a todas
las fases de los métodos tradicionales de desarrollo de sistemas. Developer/2000 es un
producto para la construcción de software de aplicaciones tales como interfaz de usuario,
diseño de reportes impresos, gráficos y administración de proyectos.
Objetos de Oracle
Oracle soporta todas las funciones que se esperan, tales como: un lenguaje de diseño de bases
de datos muy completo (PL/SQL) que permite implementar diseños "activos", con triggers y
procedimientos almacenados, con una integridad referencial integrada por la estructura física
de las tablas.
PL/SQL
PL/SQL (Lenguaje Procedural/SQL) es una extensión de SQL, que incorpora muchas de las
características de diseño propias de los lenguajes de programación modernos. Permite
manipular datos e incluir sentencias de consulta SQL dentro de unidades de código procedural
estructuradas en bloques, esto hace de PL/SQL un lenguaje poderoso para el procesamiento de
transacciones.
104
Procedimientos Almacenados
Un procedimiento es un bloque de código PL/SQL, que se almacena en el diccionario de datos
y que es llamado por las aplicaciones. Se pueden utilizar para implementar seguridad, no
dando acceso directamente a determinadas tablas sino es a través de procedimientos que
acceden a esas tablas. Cuando se ejecuta un procedimiento se ejecuta con los privilegios del
propietario del procedimiento. Pueden ser llamados usando el nombre que se le haya asignado.
Funciones
Una función es un conjunto de instrucciones en PL/SQL, que pueden ser llamados usando el
nombre con que se le haya creado. Se diferencian de los procedimientos, en que las funciones
retornan un valor al ambiente desde donde fueron llamadas.
Triggers
Un trigger es un bloque PL/SQL asociado a una tabla, que se ejecuta cuando se produce un
determinado evento en la BD. Se pueden utilizar para mejorar y reforzar la integridad y la
seguridad de la BD.
Esta asociado con una tabla o vista y que automáticamente realiza una acción cuando se
ejecuta una operación de INSERT, UPDATE o DELETE sobre la tabla que lo tiene definido.
Un trigger nunca es llamado directamente. sino cuando una aplicación o usuario intenta
insertar, actualizar o eliminar filas de una tabla, cualquier trigger asociado con la tabla y la
operación es automáticamente ejecutado o “disparado” se dice entonces que hay una
activación implícita.
Un trigger puede hacer uso de excepciones para el manejo de errores. Cuando se produce una
excepción en un trigger, retorna un mensaje de error, termina y deshace cualquier cambio
realizado a menos que la excepción este manejada con una sentencia when en el trigger.
Los lenguajes de bajo nivel 4GL requieren que el usuario especifique completamente todas las
condiciones asociadas con las reglas.
Dificultad para tener una visión global de cuáles tareas están siendo ejecutadas por un
conjunto de triggers.
Cuando ocurre una excepción hace un rollback de los cambios hechos por la sentencia
original y la acción.
Fase de Estrategia
La meta de la fase de estrategia es adquirir una idea de conjunto de qué es lo que debería
hacer el sistema que se va a diseñar y definir el alcance del proyecto.
El propósito de la fase de estrategia es formular una descripción básica del alcance global
del proyecto y de cómo transcurrirá el proyecto.
Fase de Análisis
Análisis es el proceso de recoger los requisitos del sistema. El análisis consta de dos partes:
recogida de información y análisis de requisitos.
Se crea el Modelo E/R con sus respectivos Atributos y relaciones. Este es el diagrama
entidad relación final antes de la construcción. Ahora es cuando se debe realizar cualquier
desnormalización necesaria. Hay que considerar los detalles de bajo nivel; y los diseños de las
tablas deben ser rigurosos, probados con datos de ejemplo antes de su implementación.
107
Fase de Diseño:
Del diseño de la base de datos forman parte el diseño de las tablas y columnas junto con la
especificación detallada de los dominios y verificación de las restricciones de las columnas.
El diseño de la base de datos incluye también la desnormalización de la base de datos para
mejorar el rendimiento junto con los disparadores asociados que soporten la desnormalización.
Fase Construcción
La fase de construcción comprende dos áreas: la base de datos y las aplicaciones. Si todas las
fases anteriores han sido cuidadosamente desarrolladas, esta fase se desarrollara sin
problemas. La construcción de la base de datos se genera mediante designer/2000. Todos los
disparadores y estructuras de datos pueden mantenerse con el modelo físico del
designer/2000.
Documentación
La documentación debiera ser un proceso continuo a lo largo de todo el proceso de desarrollo
del sistema. Debe acompañar al primer prototipo que el usuario vea. La documentación no
debe ser simplemente un paso separado al final del proceso.
Así como las aplicaciones se prueban, la documentación también debe pasar un proceso de
pruebas. Probar el sistema en sí es imposible antes de escribir la documentación del sistema,
puesto que no hay nada contar lo que comprobar.
Pruebas
Las pruebas son una de las más importantes pero normalmente peor realizadas fases en el
proceso de diseño de sistemas. La clave para probar correctamente es utilizar pruebas
múltiples. Ninguna prueba única, no importa cuán cuidadosamente efectuada, encontrará
todos los errores del sistema.
Cuando se satisface la fase de pruebas del proceso de desarrollo no se necesita revisar el
diseño lógico o físico de la base de datos. Esto ya se realizó en las fases de análisis y diseño.
108
Implantación
En algún momento, el sistema finalizado tiene que ser traspasado a los usuarios y puesto en
marcha (después de que halla tenido lugar, por supuesto, la formación del usuario sobre el
nuevo sistema).
Mantenimiento
Incluso cuando un sistema está finalizado y puesto en marcha, está cambiando continuamente.
Habrá, por supuesto, algunos problemas con cualquier nuevo sistema junto con la necesidad
de aumentar los usuarios, peticiones de cambio del funcionamiento del sistema, la necesidad
de nuevos informes, etc.
El objetivo principal de la fase de mantenimiento es proporcionar un proceso que pase por un
filtro, clasifique y después gestione estos problemas y cambios del sistema. Es necesario
reconocer estos cambios, que no sólo afectan a la base de datos y a las aplicaciones, sino que
también deben ser reflejados en la documentación del usuario y del sistema, y en la formación.
Al personal involucrado en las funciones de ayuda del usuario se le debe mantener informado
de cualquier cambio.
Developer/2000
Developer/2000 es e Producto de Oracle que hace fácil el desarrollo de aplicaciones de base
de datos.
Una aplicación es un programa informático que realiza una tarea. Una aplicación de base
de datos es un programa que utiliza los datos de un sistema de gestión de base de datos como
Oracle7. La mayoría de las aplicaciones de base de datos presentan datos de forma útil o
introducen y actualizan datos en la base de datos.
Forms
El componente Forms de Developer/2000 es la parte del entorno de desarrollo en la que se
construyen los módulos de formularios. También proporciona el entorno de trabajo para
desarrollar menús y módulos de biblioteca PL/SQL.
Una aplicación de formularios es una aplicación que presenta datos en un formato
interactivo, consiste en un conjunto de campos colocados en una o más ventanas.
109
Módulo de Formularios
El módulo de formularios es el componente principal de las aplicaciones interactivas. También
es el módulo más complejo en términos de la estructura interna, ya que contiene muchas clases
distintas de elementos.
Triggers (Disparadores)
Un disparador es un bloque de código PL/SQL que se asocia a otro elemento: un formulario,
un bloque de datos o un elemento de un bloque de datos. El disparador se lanza o se ejecuta,
cuando se producen ciertos eventos: el evento lanza el código.
Bloques de Datos
El bloque de datos es la unidad de construcción intermedia de los formularios. Un bloque de
datos se puede ver de dos formas, como una colección de elementos o como una colección de
registros, cada uno de los cuáles tiene la misma estructura.
Canvas y Ventanas
Un canvas es la base sobre la que se sitúa el texto plano y los elementos. Cada elemento hace
referencia a un único canvas en su hoja de propiedades. Los elementos de un bloque de datos
se pueden dividir entre diferentes canvas. Ver Figura 8.1:
110
Elementos Atributos
Programables Visuales
Clases
Property Disparadores
Grupos de Grupos de
Objetos Elementos
Hijos
Parámetros
Especificación
Unidades de
Programa Referencia
Bibliotecas Referenciado
Asociadas Por
Un Atributo Visual con nombre es una colección de propiedades visuales a las cuáles se les
puede hacer referencia desde otro elemento. Si se hiciera eso, las propiedades del atributo
visual sobreescribiría las propiedades del elemento. Si se cambiara una propiedad del atributo
visual, ésta se cambiaría en todas las propiedades que la heredan del atributo visual.
Una Clase Property es un elemento que pertenece a un módulo que contiene un conjunto de
propiedades, cualquier propiedad. De la misma forma que con los atributos visuales, cuando
un elemento se basa en una propiedad visual, se obtienen todas las propiedades de dicha clase
que tienen sentido para el tipo e elemento que se está definiendo.
Parámetros
Un parámetro es un formulario, un menú, un informe o un elemento de datos visualizable que
se define al nivel del módulo. En el ámbito del módulo, el parámetro se puede utilizar como
variable en cualquier unidad de programa PL/SQL.
Report
El componente Report de developer/2000 es la parte del entorno del desarrollo con la que se
realizan los módulos de informes. En este entorno se puede hacer referencia a elementos de
consultas externas, y se pueden configurar y almacenar elementos de depuración.
Los componentes básicos de un informe son su modelo de datos, su formulario de parámetros,
sus disparadores de informes y su composición.
El modelo de datos dl informe es la estructura de datos y sus diferentes representaciones en el
informe.
112
Anexo B: Pantallas
Condiciones Posibles
Las condiciones van a estar formadas por valores que tienen el resultado de una consulta,
cuyo resultado va a ser booleano.
113
Acciones
Ejecuta las acciones asociadas al evento cuando la condición se cumple. (Figura 8.3).
- Acción: se ingresa la acción correspondiente.
- Descripción: es descrita la acción
- Código PL Java: es ingresado por el usuario el código de programa PL/SQL que
será capaz de llamar a cualquier servicio del sistema.
Al igual que las pantallas anteriores se encontrara habilitado y en estado valido cuando
el form sea compilado sin errores de compilación.
Las acciones tendrán una prioridad de ejecución.
114
Bitácora de Procesos
En la Figura 8.4, la Bitácora de Procesos con la tabla Log de procesos están relacionadas como
Master-Detail (maestro-detallado), es decir una tabla es dependiente de la otra. Los campos
son los siguientes:
Bitácora de Procesos
- Num Proceso: se ingresa el número del proceso que se esta ejecutando por la BD.
- Proceso: se ingresa el proceso que se esta ejecutando.
- Estado: indica el estado en el que se encuentra el proceso.
- Fecha: indica la fecha de ejecución del proceso.
- Usuario: identifica al usuario esta utilizando la base de datos.
Log de Procesos
- Num Proceso: indica el proceso en el cual se produjo un error.
- Glosa: describe el error del proceso.
115
Como en la bitácora de procesos están almacenados todos los procesos asociados al evento,
indicando el estado en el que se encuentra, al producirse un error va inmediatamente va al log
de procesos para identificar el número del proceso en el que fue producido el error.
Procesos - Privilegios
En la Figura 8.5, las tablas de Procesos y Privilegios están relacionadas como Master-Detail
(maestro-detallado), es decir una tabla es dependiente de la otra. Los campos son los
siguientes:
Procesos
- Proceso: es ingresado el proceso que se esta ejecutando.
- Descripción: describe al proceso en ejecución.
- Evento: indica que evento esta asociado al proceso que se está ejecutando.
Privilegios
- Proceso: indica que proceso esta usando el usuario.
- Usuario: identifica al usuario que esta utilizando la base de datos.
116
Variables Globales
Se ha implementado la Tabla de Variables Globales del Sistema, para que las variables sean
accesibles desde cualquier Form de la aplicación, declarándolas como públicas desde un
módulo de código, una variable es un valor que cambia en el tiempo pero que en un tiempo “t”
determinado y en la evaluación de la expresión tiene un único valor, de lo contrario seria
inconsistente, esta pantalla, como lo muestra la Figura 7.4, contiene los siguientes campos:
- Variables Globales: nombre de la variable con su descripción.
- Especificaciones: son definidas las variables globales del sistema a utilizar en el cuerpo.
- Cuerpo: se definen las variables que nos son globales y van a pertenecer solamente al
código de programa ingresado en el cuerpo.
- Errores de Compilación: muestra los errores en tiempo de ejecución.
117
Código de Forms.
Form Condiciones
Triggers
Name ON-CHECK-DELETE-MASTER
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
Dummy_Define CHAR(1);
-- Begin USER_ERRORS detail declare section
CURSOR USER_ERRORS_cur IS
SELECT 1 FROM USER_ERRORS
WHERE NAME = :[Link];
-- End USER_ERRORS detail declare section
-- End default relation declare section
-- Begin default relation program section
BEGIN
-- Begin USER_ERRORS detail program section
OPEN USER_ERRORS_cur;
FETCH USER_ERRORS_cur INTO Dummy_Define;
IF ( USER_ERRORS_cur%found ) THEN
Message('Cannot delete master record when matching detail records exist.');
CLOSE USER_ERRORS_cur;
RAISE Form_Trigger_Failure;
END IF;
CLOSE USER_ERRORS_cur;
-- End USER_ERRORS detail program section
END;
-- End default relation program section
Name ON-POPULATE-DETAILS
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
recstat CHAR(20) := :System.record_status;
startitm CHAR(61) := :System.cursor_item;
rel_id Relation;
-- End default relation declare section
-- Begin default relation program section
--
BEGIN
IF ( recstat = 'NEW' or recstat = 'INSERT' ) THEN
RETURN;
END IF;
119
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
RAISE Form_Trigger_Failure;
120
END IF;
END;
BEGIN
-- Init Local Vars
mastblk := :System.Master_Block;
coordop := :System.Coordination_Operation;
trigblk := :System.Trigger_Block;
startitm := :System.Trigger_Item;
frmstat := :System.Form_Status;
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
END Clear_All_Master_Details;
raise form_trigger_failure;
end;
execute_query;
END IF;
end;
END IF;
END;
END IF;
EXCEPTION
WHEN Form_Trigger_Failure THEN
:System.Message_Level := oldmsg;
RAISE;
END Query_Master_Details;
Form Acciones
Triggers
Name ON-CHECK-DELETE-MASTER
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
Dummy_Define CHAR(1);
-- Begin USER_ERRORS detail declare section
CURSOR USER_ERRORS_cur IS
SELECT 1 FROM USER_ERRORS
WHERE NAME = :[Link];
-- End USER_ERRORS detail declare section
-- End default relation declare section
-- Begin default relation program section
BEGIN
-- Begin USER_ERRORS detail program section
OPEN USER_ERRORS_cur;
FETCH USER_ERRORS_cur INTO Dummy_Define;
IF ( USER_ERRORS_cur%found ) THEN
Message('Cannot delete master record when matching detail records exist.');
CLOSE USER_ERRORS_cur;
RAISE Form_Trigger_Failure;
END IF;
CLOSE USER_ERRORS_cur;
-- End USER_ERRORS detail program section
END;
End default relation program section
Name ON-POPULATE-DETAILS
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
recstat CHAR(20) := :System.record_status;
startitm CHAR(61) := :System.cursor_item;
rel_id Relation;
-- End default relation declare section
126
Triggers
Name POST-CHANGE
Class <Null>
Trigger Text
if :system.record_status in ('NEW','INSERT') THEN
if pkg_sys.existe_obj(:[Link]) THEN
message('Ya existe objeto '||:[Link]);
message('Ya existe objeto '||:[Link]);
raise form_trigger_failure;
end if;
end if;
:[Link] := pkg_sys.get_status(:[Link],'PROCEDURE');
Triggers
Name WHEN-CHECKBOX-CHANGED
Class <Null>
Trigger Text
IF :[Link] is not null and
:acciones.codigo_pl_java is not null THEN
IF :[Link] = 'S' THEN
k_commit;
END IF; -- :[Link] = 'S'
END IF; -- :[Link] is not null
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
RAISE Form_Trigger_Failure;
END IF;
127
END;
BEGIN
-- Init Local Vars
mastblk := :System.Master_Block;
128
coordop := :System.Coordination_Operation;
trigblk := :System.Trigger_Block;
startitm := :System.Trigger_Item;
frmstat := :System.Form_Status;
-- If the coordination operation is anything but CLEAR_RECORD or
-- SYNCHRONIZE_BLOCKS, then continue checking.
IF coordop NOT IN ('CLEAR_RECORD', 'SYNCHRONIZE_BLOCKS') THEN
-- If we're processing the driving master block...
IF mastblk = trigblk THEN
-- If something in the form is changed, find the
-- first changed block below the master
IF frmstat = 'CHANGED' THEN
curblk := First_Changed_Block_Below(mastblk);
-- If we find a changed block below, go there
-- and Ask to commit the changes.
IF curblk IS NOT NULL THEN
Go_Block(curblk);
Check_Package_Failure;
Clear_Block(ASK_COMMIT);
-- If user cancels commit dialog, raise error
IF NOT ( :System.Form_Status = 'QUERY'
OR :System.Block_Status = 'NEW' ) THEN
RAISE Form_Trigger_Failure;
END IF;
END IF;
END IF;
END IF;
END IF;
-- Clear all the detail blocks for this master without
-- any further asking to commit.
currel := Get_Block_Property(trigblk, FIRST_MASTER_RELATION);
WHILE currel IS NOT NULL LOOP
curdtl := Get_Relation_Property(currel, DETAIL_NAME);
IF Get_Block_Property(curdtl, STATUS) <> 'NEW' THEN
Go_Block(curdtl);
Check_Package_Failure;
Clear_Block(NO_VALIDATE);
IF :System.Block_Status <> 'NEW' THEN
RAISE Form_Trigger_Failure;
END IF;
END IF;
currel := Get_Relation_Property(currel, NEXT_MASTER_RELATION);
END LOOP;
-- Put cursor back where it started
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
Check_Package_Failure;
END IF;
129
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
END Clear_All_Master_Details;
COMMIT_MUDO (Procedure Body)
PROCEDURE commit_mudo IS
rlevel varchar2(30);
BEGIN
rlevel := :system.message_level;
:system.message_level := '25';
commit;
:system.message_level := rlevel;
END;
CREATE_ACCION (Procedure Body)
PROCEDURE create_accion IS
BEGIN
pkg_sys.create_obj(:[Link],:ACCIONES.CODIGO_PL_JAVA,'PROCEDURE',null);
EXCEPTION
WHEN others THEN
message('Error al crear accion: '||:[Link]||': '||SQLERRM);
message('Error al crear accion: '||:[Link]||': '||SQLERRM);
raise form_trigger_failure;
END;
PROCEDURE drop_accion IS
-- procedimiento que borra la accion
BEGIN
pkg_sys.drop_obj(:[Link],'PROCEDURE');
EXCEPTION
WHEN others THEN
message('Error al borrar accion: '||SQLERRM);
message('Error al borrar accion: '||SQLERRM);
raise form_trigger_failure;
END;
Triggers
Name ON-CLEAR-DETAILS
Class <Null>
Trigger Text
-- Begin default relation program section
BEGIN
Clear_All_Master_Details;
END;
-- End default relation program section
Triggers
Name ON-CHECK-DELETE-MASTER
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
Dummy_Define CHAR(1);
-- Begin BITACORA_PROCESOS detail declare section
CURSOR BITACORA_PROCESOS_cur IS
SELECT 1 FROM BITACORA_PROCESOS
WHERE EVENTO = :[Link];
-- End BITACORA_PROCESOS detail declare section
-- End default relation declare section
-- Begin default relation program section
132
BEGIN
-- Begin BITACORA_PROCESOS detail program section
OPEN BITACORA_PROCESOS_cur;
FETCH BITACORA_PROCESOS_cur INTO Dummy_Define;
IF ( BITACORA_PROCESOS_cur%found ) THEN
Message('Cannot delete master record when matching detail records exist.');
CLOSE BITACORA_PROCESOS_cur;
RAISE Form_Trigger_Failure;
END IF;
CLOSE BITACORA_PROCESOS_cur;
-- End BITACORA_PROCESOS detail program section
END;
-- End default relation program section
Name ON-POPULATE-DETAILS
Class <Null>
Trigger Text
--
-- Begin default relation declare section
DECLARE
recstat CHAR(20) := :System.record_status;
startitm CHAR(61) := :System.cursor_item;
rel_id Relation;
-- End default relation declare section
-- Begin default relation program section
BEGIN
IF ( recstat = 'NEW' or recstat = 'INSERT' ) THEN
RETURN;
END IF;
--Begin BITACORA_PROCESOS detail program section
IF ( (:[Link] is not null) ) THEN
rel_id := Find_Relation('EVENTOS.EV_BIT');
Query_Master_Details(rel_id, 'BITACORA_PROCESOS');
END IF;
-- End BITACORA_PROCESOS detail program section
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
133
RAISE Form_Trigger_Failure;
END IF;
END;
BEGIN
134
Check_Package_Failure;
END IF;
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
END Clear_All_Master_Details;
Check_Package_Failure;
:System.Message_Level := '10';
Execute_Query;
:System.Message_Level := oldmsg;
ELSE
-- Relation is deferred, mark the detail block as un-coordinated
Set_Block_Property(detail, COORDINATION_STATUS, NON_COORDINATED);
END IF;
EXCEPTION
WHEN Form_Trigger_Failure THEN
:System.Message_Level := oldmsg;
RAISE;
END Query_Master_Details;
Form Provilegios
Triggers
Name ON-CLEAR-DETAILS
Class <Null>
Trigger Text
-- Begin default relation program section
BEGIN
Clear_All_Master_Details;
END;
-- End default relation program section
Name ON-POPULATE-DETAILS
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
recstat CHAR(20) := :System.record_status;
startitm CHAR(61) := :System.cursor_item;
rel_id Relation;
-- End default relation declare section
-- Begin default relation program section
BEGIN
IF ( recstat = 'NEW' or recstat = 'INSERT' ) THEN
RETURN;
END IF;
-- Begin PRIVILEGIOS detail program section
IF ( (:[Link] is not null) ) THEN
rel_id := Find_Relation('EVENTOS.EVENTOS_PRIVILEGIOS');
Query_Master_Details(rel_id, 'PRIVILEGIOS');
END IF;
-- End PRIVILEGIOS detail program section
Go_Item(startitm);
Check_Package_Failure;
END IF;
END;
End default relation program section
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
RAISE Form_Trigger_Failure;
END IF;
END;
ELSE
-- Consider the next relation
currel := Get_Relation_Property(currel, NEXT_MASTER_RELATION);
END IF;
END IF;
END LOOP;
-- No changed blocks were found
RETURN NULL;
END First_Changed_Block_Below;
BEGIN
-- Init Local Vars
mastblk := :System.Master_Block;
coordop := :System.Coordination_Operation;
trigblk := :System.Trigger_Block;
startitm := :System.Trigger_Item;
frmstat := :System.Form_Status;
-- If the coordination operation is anything but CLEAR_RECORD or
-- SYNCHRONIZE_BLOCKS, then continue checking.
IF coordop NOT IN ('CLEAR_RECORD', 'SYNCHRONIZE_BLOCKS') THEN
-- If we're processing the driving master block...
IF mastblk = trigblk THEN
-- If something in the form is changed, find the
-- first changed block below the master
--
IF frmstat = 'CHANGED' THEN
curblk := First_Changed_Block_Below(mastblk);
-- If we find a changed block below, go there
-- and Ask to commit the changes.
IF curblk IS NOT NULL THEN
Go_Block(curblk);
Check_Package_Failure;
Clear_Block(ASK_COMMIT);
-- If user cancels commit dialog, raise error
IF NOT ( :System.Form_Status = 'QUERY'
OR :System.Block_Status = 'NEW' ) THEN
RAISE Form_Trigger_Failure;
END IF;
END IF;
END IF;
END IF;
END IF;
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
END Clear_All_Master_Details;
END;
EXCEPTION
WHEN Form_Trigger_Failure THEN
:System.Message_Level := oldmsg;
RAISE;
END Query_Master_Details;
Triggers
Name ON-CHECK-DELETE-MASTER
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
Dummy_Define CHAR(1);
-- Begin USER_ERRORS detail declare section
CURSOR USER_ERRORS_cur IS
SELECT 1 FROM USER_ERRORS
WHERE NAME = :VARIABLES_GLOBALES.NOMBRE;
-- End USER_ERRORS detail declare section
-- End default relation declare section
BEGIN
-- Begin USER_ERRORS detail program section
OPEN USER_ERRORS_cur;
141
:variables_globales.status :=
pkg_sys.get_status(:variables_globales.nombre,'PACKAGE');
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
RAISE Form_Trigger_Failure;
END IF;
END;
END IF;
END LOOP;
-- No changed blocks were found
RETURN NULL;
END First_Changed_Block_Below;
BEGIN
-- Init Local Vars
mastblk := :System.Master_Block;
coordop := :System.Coordination_Operation;
trigblk := :System.Trigger_Block;
startitm := :System.Trigger_Item;
frmstat := :System.Form_Status;
-- If the coordination operation is anything but CLEAR_RECORD or
-- SYNCHRONIZE_BLOCKS, then continue checking.
IF coordop NOT IN ('CLEAR_RECORD', 'SYNCHRONIZE_BLOCKS') THEN
-- If we're processing the driving master block...
IF mastblk = trigblk THEN
-- If something in the form is changed, find the
-- first changed block below the master
IF frmstat = 'CHANGED' THEN
curblk := First_Changed_Block_Below(mastblk);
-- If we find a changed block below, go there
-- and Ask to commit the changes.
IF curblk IS NOT NULL THEN
Go_Block(curblk);
Check_Package_Failure;
Clear_Block(ASK_COMMIT);
--
-- If user cancels commit dialog, raise error
--
IF NOT ( :System.Form_Status = 'QUERY'
OR :System.Block_Status = 'NEW' ) THEN
RAISE Form_Trigger_Failure;
END IF;
END IF;
END IF;
END IF;
END IF;
-- Clear all the detail blocks for this master without
-- any further asking to commit.
currel := Get_Block_Property(trigblk, FIRST_MASTER_RELATION);
WHILE currel IS NOT NULL LOOP
curdtl := Get_Relation_Property(currel, DETAIL_NAME);
IF Get_Block_Property(curdtl, STATUS) <> 'NEW' THEN
Go_Block(curdtl);
Check_Package_Failure;
Clear_Block(NO_VALIDATE);
144
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
END Clear_All_Master_Details;
pkg_sys.create_obj(:variables_globales.nombre,:variables_globales.especificacion,'PACKAG
E',null);
EXCEPTION
WHEN others THEN
msg1('Error al crear pack de variables globales: '||:variables_globales.nombre||':
'||SQLERRM);
raise form_trigger_failure;
END;
IF get_permiso_borrar THEN
go_block('VARIABLES_GLOBALES');
drop_pack;
begin
delete_record;
commit_mudo;
EXCEPTION
WHEN others THEN
message('Error al borrar registro de variables globales: '||SQLERRM);
message('Error al borrar registro de variables globales: '||SQLERRM);
raise form_trigger_failure;
end;
execute_query;
END IF;
end;
create_pack;
commit;
go_block('USER_ERRORS');
execute_query;
go_block('VARIABLES_GLOBALES');
:variables_globales.status :=
pkg_sys.get_status(:variables_globales.nombre,'PACKAGE');
END IF;
END;
EXCEPTION
WHEN Form_Trigger_Failure THEN
:System.Message_Level := oldmsg;
RAISE;
END Query_Master_Details;
Form Pruebas
Triggers
Name ON-CHECK-DELETE-MASTER
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
Dummy_Define CHAR(1);
-- Begin SANCIONES detail declare section
CURSOR SANCIONES_cur IS
SELECT 1 FROM sanciones
WHERE RUT = :[Link];
-- End SANCIONES detail declare section
-- End default relation declare section
-- Begin default relation program section
BEGIN
-- Begin SANCIONES detail program section
OPEN SANCIONES_cur;
FETCH SANCIONES_cur INTO Dummy_Define;
IF ( SANCIONES_cur%found ) THEN
Message('Cannot delete master record when matching detail records exist.');
CLOSE SANCIONES_cur;
RAISE Form_Trigger_Failure;
END IF;
CLOSE SANCIONES_cur;
-- End SANCIONES detail program section
END;
End default relation program section
Name ON-POPULATE-DETAILS
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
recstat CHAR(20) := :System.record_status;
startitm CHAR(61) := :System.cursor_item;
148
rel_id Relation;
-- End default relation declare section
-- Begin default relation program section
BEGIN
IF ( recstat = 'NEW' or recstat = 'INSERT' ) THEN
RETURN;
END IF;
-- Begin SANCIONES detail program section
IF ( (:[Link] is not null) ) THEN
rel_id := Find_Relation('RESERVAS.RES_SANC');
Query_Master_Details(rel_id, 'SANCIONES');
END IF;
-- End SANCIONES detail program section
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
RAISE Form_Trigger_Failure;
END IF;
END;
curblk := Master;
currel := Get_Block_Property(curblk, FIRST_MASTER_RELATION);
-- While there exists another relation for this block
WHILE currel IS NOT NULL LOOP
-- Get the name of the detail block
curblk := Get_Relation_Property(currel, DETAIL_NAME);
-- If this block has changes, return its name
IF ( Get_Block_Property(curblk, STATUS) IN('CHANGED','INSERT') ) THEN
RETURN curblk;
ELSE
-- No changes, recursively look for changed blocks below
retblk := First_Changed_Block_Below(curblk);
-- If some block below is changed, return its name
IF retblk IS NOT NULL THEN
RETURN retblk;
ELSE
-- Consider the next relation
currel := Get_Relation_Property(currel, NEXT_MASTER_RELATION);
END IF;
END IF;
END LOOP;
-- No changed blocks were found
RETURN NULL;
END First_Changed_Block_Below;
BEGIN
-- Init Local Vars
mastblk := :System.Master_Block;
coordop := :System.Coordination_Operation;
trigblk := :System.Trigger_Block;
startitm := :System.Trigger_Item;
frmstat := :System.Form_Status;
-- If the coordination operation is anything but CLEAR_RECORD or
-- SYNCHRONIZE_BLOCKS, then continue checking.
IF coordop NOT IN ('CLEAR_RECORD', 'SYNCHRONIZE_BLOCKS') THEN
-- If we're processing the driving master block...
IF mastblk = trigblk THEN
-- If something in the form is changed, find the
-- first changed block below the master
IF frmstat = 'CHANGED' THEN
curblk := First_Changed_Block_Below(mastblk);
-- If we find a changed block below, go there
-- and Ask to commit the changes.
IF curblk IS NOT NULL THEN
Go_Block(curblk);
Check_Package_Failure;
Clear_Block(ASK_COMMIT);
150
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
END Clear_All_Master_Details;
oldmsg := :System.Message_Level;
--
-- If NOT Deferred, Goto detail and execute the query.
--
IF reldef = 'FALSE' THEN
Go_Block(detail);
Check_Package_Failure;
:System.Message_Level := '10';
Execute_Query;
:System.Message_Level := oldmsg;
ELSE
--
-- Relation is deferred, mark the detail block as un-coordinated
--
Set_Block_Property(detail, COORDINATION_STATUS, NON_COORDINATED);
END IF;
EXCEPTION
WHEN Form_Trigger_Failure THEN
:System.Message_Level := oldmsg;
RAISE;
END Query_Master_Details;
FORM TABLAS
Name ON-POPULATE-DETAILS
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
recstat CHAR(20) := :System.record_status;
startitm CHAR(61) := :System.cursor_item;
rel_id Relation;
-- End default relation declare section
-- Begin default relation program section
BEGIN
IF ( recstat = 'NEW' or recstat = 'INSERT' ) THEN
RETURN;
END IF;
-- Begin COLUMNAS_TABLAS detail program section
IF ( (:[Link] is not null) ) THEN
rel_id := Find_Relation('TABLAS.TABLAS_COLUMNAS_TABLAS');
Query_Master_Details(rel_id, 'COLUMNAS_TABLAS');
END IF;
-- End COLUMNAS_TABLAS detail program section
Check_Package_Failure;
END IF;
END;
-- End default relation program section
Triggers
Name POST-CHANGE
Class <Null>
Trigger Text
if :system.record_status in ('NEW','INSERT') THEN
if pkg_sys.existe_obj(:[Link]) THEN
message('Ya existe objeto '||:[Link]);
message('Ya existe objeto '||:[Link]);
raise form_trigger_failure;
end if;
end if;
:tablas.tab_status := nvl(pkg_sys.get_status(:[Link],'TABLE'),'INVALID');
:tablas.pack_status :=
nvl(pkg_sys.get_status('G_'||:[Link],'PACKAGE'),'INVALID');
Triggers
Name WHEN-LIST-CHANGED
Class <Null>
Trigger Text
if :columnas_tablas.tipo = 'VARCHAR2' THEN
set_item_property('columnas_tablas.tamano',ENABLED,PROPERTY_TRUE);
else
set_item_property('columnas_tablas.tamano',ENABLED,PROPERTY_FALSE);
end if;
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
RAISE Form_Trigger_Failure;
END IF;
END;
BEGIN
-- Init Local Vars
mastblk := :System.Master_Block;
coordop := :System.Coordination_Operation;
trigblk := :System.Trigger_Block;
startitm := :System.Trigger_Item;
frmstat := :System.Form_Status;
-- If the coordination operation is anything but CLEAR_RECORD or
-- SYNCHRONIZE_BLOCKS, then continue checking.
IF coordop NOT IN ('CLEAR_RECORD', 'SYNCHRONIZE_BLOCKS') THEN
-- If we're processing the driving master block...
IF mastblk = trigblk THEN
-- If something in the form is changed, find the
-- first changed block below the master
IF frmstat = 'CHANGED' THEN
154
curblk := First_Changed_Block_Below(mastblk);
-- If we find a changed block below, go there
-- and Ask to commit the changes.
IF curblk IS NOT NULL THEN
Go_Block(curblk);
Check_Package_Failure;
Clear_Block(ASK_COMMIT);
-- If user cancels commit dialog, raise error
IF NOT ( :System.Form_Status = 'QUERY'
OR :System.Block_Status = 'NEW' ) THEN
RAISE Form_Trigger_Failure;
END IF;
END IF;
END IF;
END IF;
END IF;
--
-- Clear all the detail blocks for this master without
-- any further asking to commit.
--
currel := Get_Block_Property(trigblk, FIRST_MASTER_RELATION);
WHILE currel IS NOT NULL LOOP
curdtl := Get_Relation_Property(currel, DETAIL_NAME);
IF Get_Block_Property(curdtl, STATUS) <> 'NEW' THEN
Go_Block(curdtl);
Check_Package_Failure;
Clear_Block(NO_VALIDATE);
IF :System.Block_Status <> 'NEW' THEN
RAISE Form_Trigger_Failure;
END IF;
END IF;
currel := Get_Relation_Property(currel, NEXT_MASTER_RELATION);
END LOOP;
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
155
END Clear_All_Master_Details;
:tablas.pack_status :=
nvl(pkg_sys.get_status('G_'||:[Link],'PACKAGE'),'INVALID');
END;
EXCEPTION
WHEN Form_Trigger_Failure THEN
:System.Message_Level := oldmsg;
158
RAISE;
END Query_Master_Details;
FORM VARIABLES
Triggers
Name ON-CHECK-DELETE-MASTER
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
Dummy_Define CHAR(1);
-- Begin USER_ERRORS detail declare section
CURSOR USER_ERRORS_cur IS
SELECT 1 FROM user_errors
WHERE NAME = :[Link];
-- End USER_ERRORS detail declare section
-- End default relation declare section
-- Begin default relation program section
BEGIN
-- Begin USER_ERRORS detail program section
OPEN USER_ERRORS_cur;
FETCH USER_ERRORS_cur INTO Dummy_Define;
IF ( USER_ERRORS_cur%found ) THEN
Message('Cannot delete master record when matching detail records exist.');
CLOSE USER_ERRORS_cur;
RAISE Form_Trigger_Failure;
END IF;
CLOSE USER_ERRORS_cur;
-- End USER_ERRORS detail program section
END;
-- End default relation program section
Name ON-POPULATE-DETAILS
Class <Null>
Trigger Text
-- Begin default relation declare section
DECLARE
recstat CHAR(20) := :System.record_status;
startitm CHAR(61) := :System.cursor_item;
rel_id Relation;
-- End default relation declare section
-- Begin default relation program section
BEGIN
159
Triggers
Name POST-CHANGE
Class <Null>
Trigger Text
if :system.record_status in ('NEW','INSERT') THEN
if pkg_sys.existe_obj(:[Link]) THEN
message('Ya existe objeto '||:[Link]);
message('Ya existe objeto '||:[Link]);
raise form_trigger_failure;
end if;
end if;
:[Link] := pkg_sys.get_status(:[Link],'FUNCTION');
Program Units
CHECK_PACKAGE_FAILURE (Procedure Body)
Procedure Check_Package_Failure IS
BEGIN
IF NOT ( Form_Success ) THEN
RAISE Form_Trigger_Failure;
END IF;
END;
BEGIN
-- Init Local Vars
mastblk := :System.Master_Block;
coordop := :System.Coordination_Operation;
trigblk := :System.Trigger_Block;
startitm := :System.Trigger_Item;
frmstat := :System.Form_Status;
EXCEPTION
WHEN Form_Trigger_Failure THEN
IF :System.Cursor_Item <> startitm THEN
Go_Item(startitm);
END IF;
RAISE;
END Clear_All_Master_Details;
162
pkg_sys.create_obj(:[Link],:VARIABLES.CONSULTA_SQL,'FUNCTION',:varia
bles.tipo_variable);
EXCEPTION
WHEN others THEN
message('Error al crear variable: '||:[Link]||': '||SQLERRM);
message('Error al crear variable: '||:[Link]||': '||SQLERRM);
raise form_trigger_failure;
END;
pkg_sys.drop_obj(:[Link],'FUNCTION');
EXCEPTION
WHEN others THEN
message('Error al borrar accion: '||SQLERRM);
message('Error al borrar accion: '||SQLERRM);
raise form_trigger_failure;
END;
Set_Alert_Property('UNA_VIA',alert_message_text,p_msg);
v_resp := show_alert('UNA_VIA');
END;
EXCEPTION
WHEN Form_Trigger_Failure THEN
:System.Message_Level := oldmsg;
RAISE;
END Query_Master_Details;
OLA
165
OLA
Anexo C: Código de Programas
clear screen
--
-- script de creación de objetos Seminario "Base de datos Activas"
-- Autoras: Sandra Macaya, Julia Cáceres
-- Prof Guía: Francisco Venegas
-- 05/2001
--
-- Eliminación de claves foráneas
--
alter table condiciones_eventos drop constraint fk_evento_condiciones
/
alter table condiciones_eventos drop constraint fk_condicion_condiciones
/
alter table acciones_eventos drop constraint fk_evento_acciones
/
alter table acciones_eventos drop constraint fk_accion_acciones
/
alter table bitacora_procesos drop constraint fk_evento_bitacora
/
alter table privilegios drop constraint fk_evento_privilegios
/
--
-- Tablas
--
drop table eventos
/
create table eventos (
evento varchar2(30) not null,
descripcion varchar2(100) not null,
tipo varchar2(15) not null, -- tabla / temporal
tabla varchar2(30), -- nombre de tabla
partida date, -- fecha y hora de la primera ejecucion
interval_dd number, -- periodicidad de ejecucion en dias
interval_hh number, -- periodicidad de ejecucion en horas
interval_mm number, -- periodicidad de ejecucion en minutos
interval_ss number, -- periodicidad de ejecucion en segundos
triggering varchar2(10), -- before /after
sentencia varchar2(10), -- insert, update, delete
each_row varchar2(1), -- 'Y' or 'N'
condicion varchar2(200), -- condicion activacion
activo varchar2(1) not null, -- registro habilitado (S/N)
job_no number -- nro de job
)
/
drop table condiciones
166
/
create table condiciones (
condicion varchar2(30) not null,
descripcion varchar2(100) not null,
expresion varchar2(2000) not null,
activo varchar2(1) not null -- registro activo (S/N)
)
/
drop table acciones
/
create table acciones (
accion varchar2(30) not null,
descripcion varchar2(100) not null,
codigo_pl_java varchar2(2000) not null,
activo varchar2(1) not null -- registro habilitado (S/N)
)
/
drop table condiciones_eventos
/
create table condiciones_eventos (
evento varchar2(30) not null,
condicion varchar2(30) not null,
activo varchar2(1) not null, -- registro activo (S/N)
prioridad number not null
)
/
drop table acciones_eventos
/
create table acciones_eventos (
evento varchar2(30) not null,
accion varchar2(30) not null,
prioridad number not null,
activo varchar2(1) not null -- registro activo (S/N)
)
/
drop table variables
/
create table variables (
variable varchar2(30) not null,
descripcion varchar2(100) not null,
tipo_variable varchar2(30) not null,
consulta_sql varchar2(2000) not null
)
/
drop table variables_globales
/
create table variables_globales (
nombre varchar2(30) not null,
167
/
alter table condiciones add constraint condiciones_pk primary key (condicion) using
index
/
alter table acciones add constraint acciones_pk primary key (accion) using index
/
alter table privilegios add constraint privilegios_pk primary key (evento,usuario) using
index
/
--
-- foreign keys
--
alter table condiciones_eventos add constraint fk_evento_condiciones foreign key
(evento) references eventos(evento)
/
alter table condiciones_eventos add constraint fk_condicion_condiciones foreign key
(condicion) references condiciones(condicion)
/
alter table acciones_eventos add constraint fk_evento_acciones foreign key (evento)
references eventos(evento)
/
alter table acciones_eventos add constraint fk_accion_acciones foreign key (accion)
references acciones(accion)
/
alter table bitacora_procesos add constraint fk_evento_bitacora foreign key (evento)
references eventos(evento)
/
alter table privilegios add constraint fk_evento_privilegios foreign key (evento)
references eventos(evento)
/
--
-- secuencias
drop sequence sec_proc
/
create sequence sec_proc
/
--
create or replace package pkg_sys as
g_valor_cond boolean;
------------------------------------------------------------------------------------------
function submit_job(p_proc in varchar2, p_fecha in date, p_interval in varchar2) return
number;
------------------------------------------------------------------------------------------
procedure execute_eca(p_evento in varchar2);
------------------------------------------------------------------------------------------
procedure create_tab(p_table in varchar2);
------------------------------------------------------------------------------------------
procedure create_pack_tab(p_table in varchar2);
169
------------------------------------------------------------------------------------------
function get_new_old_str(p_table in varchar2) return varchar2;
------------------------------------------------------------------------------------------
procedure execute_acc(p_acc in varchar2);
------------------------------------------------------------------------------------------
procedure execute_str(p_str in varchar2);
------------------------------------------------------------------------------------------
function get_cond(p_cond in varchar2) return boolean;
------------------------------------------------------------------------------------------
function existe_obj(p_obj in varchar2) return boolean;
------------------------------------------------------------------------------------------
function get_status(p_obj in varchar2, p_type in varchar2) return varchar2;
------------------------------------------------------------------------------------------
function get_next_date(p_job_no in number) return date;
------------------------------------------------------------------------------------------
procedure create_obj(p_obj in varchar2, p_cuerpo in varchar2,
p_obj_type in varchar2, p_return_type in varchar2);
------------------------------------------------------------------------------------------
procedure drop_obj(p_obj in varchar2, p_type in varchar2);
------------------------------------------------------------------------------------------
procedure drop_job(p_job_no in number);
------------------------------------------------------------------------------------------
procedure enable_trigger(p_trigger in varchar2);
------------------------------------------------------------------------------------------
procedure disable_trigger(p_trigger in varchar2);
------------------------------------------------------------------------------------------
procedure active_condicion(p_condicion in varchar2);
------------------------------------------------------------------------------------------
procedure active_accion(p_accion in varchar2);
------------------------------------------------------------------------------------------
procedure desactive_condicion(p_condicion in varchar2);
------------------------------------------------------------------------------------------
procedure desactive_accion(p_accion in varchar2);
------------------------------------------------------------------------------------------
procedure ins_bitacora(p_evento in varchar2, p_status in varchar2, p_glosa in
varchar2);
------------------------------------------------------------------------------------------
function get_privilegio(p_evento in varchar2, p_user in varchar2) return boolean;
------------------------------------------------------------------------------------------
end pkg_sys;
/
create or replace package body pkg_sys as
------------------------------------------------------------------------------------------
function submit_job(p_proc in varchar2, p_fecha in date, p_interval in varchar2) return
number is
--
-- procedimiento que submite un proceso oracle p_proc, para su ejecucion en la fecha
p_fecha
170
if v_num_condiciones = 0 THEN
ins_bitacora(p_evento,'EN PROCESO','Evento sin condiciones');
else
ins_bitacora(p_evento,'EN PROCESO','Cumple: '||v_num_condiciones||', todas
las condiciones');
end if;
else
if v_num_condiciones_err = 0 THEN
if v_tipo_evento = 'TABLA' THEN
ins_bitacora(p_evento,'FIN DE PROCESO','No cumple: '||v_num_no_cumple||'
condiciones');
raise_application_error(-20200,'No cumple: '||v_num_no_cumple||'
condiciones');
else
ins_bitacora(p_evento,'FIN DE PROCESO','No cumple: '||v_num_no_cumple||'
condiciones');
return;
end if;
else
if v_num_no_cumple = 0 THEN
if v_tipo_evento = 'TABLA' THEN
ins_bitacora(p_evento,'FIN CON ERROR',v_num_condiciones_err||'
condiciones (todas) erroneas');
raise_application_error(-20200,'ERROR: '||v_num_condiciones_err||'
condiciones (todas) erroneas');
else
ins_bitacora(p_evento,'FIN CON ERROR',v_num_condiciones_err||'
condiciones (todas) erroneas');
return;
end if;
else
if v_tipo_evento = 'TABLA' THEN
ins_bitacora(p_evento,'FIN CON ERROR','No se cumplen
'||v_num_no_cumple||
'condiciones y '||v_num_condiciones_err||' erroneas');
raise_application_error(-20200,'ERROR: No se cumplen
'||v_num_no_cumple||
'condiciones y '||v_num_condiciones_err||' erroneas');
else
ins_bitacora(p_evento,'FIN CON ERROR','No se cumplen
'||v_num_no_cumple||
'condiciones y '||v_num_condiciones_err||' erroneas');
return;
end if;
end if;
end if;
end if;
--
173
-- acciones
--
v_num_acciones := 0;
v_num_acciones_err := 0;
for i in c_acc loop
begin
execute_acc([Link]);
v_num_acciones := v_num_acciones + 1;
Exception
WHEN others THEN
v_num_acciones_err := v_num_acciones_err + 1;
ins_bitacora(p_evento,'ERROR','Error en accion: '||[Link]||': '||SQLERRM);
end;
end loop;
if v_num_acciones_err = 0 THEN
if v_num_acciones = 0 THEN
ins_bitacora(p_evento,'FIN DE PROCESO','Evento sin acciones');
else
ins_bitacora(p_evento,'FIN DE PROCESO','Se procesaron: '||v_num_acciones||',
todas las acciones');
return;
end if;
else
ins_bitacora(p_evento,'FIN CON ERROR',v_num_acciones_err||' acciones con
error');
return;
end if;
else
ins_bitacora(p_evento,'ERROR','Usuario: '||user||' no tiene privilegios para ejecutar
evento: '||p_evento);
end if;
EXCEPTION
WHEN others THEN
if v_tipo_evento = 'TABLA' THEN
raise_application_error(-20200,'ERROR:'||substr(SQLERRM,1,2000));
else
ins_bitacora(p_evento,'ERROR',substr(SQLERRM,1,2000));
end if;
--
end execute_eca;
------------------------------------------------------------------------------------------
174
Exception
WHEN others THEN
raise_application_error(-20201,' pkg_sys.create_pack_tab: '||SQLERRM);
end;
end loop;
create_obj('g_'||p_table,v_pack,'PACKAGE',null);
EXCEPTION
WHEN others THEN
raise_application_error(-20202,' pkg_sys.create_pack_tab: '||SQLERRM);
--
end create_pack_tab;
------------------------------------------------------------------------------------------
function get_new_old_str(p_table in varchar2) return varchar2 is
--
-- funcion que retorna un string con las asignaciones de las variables new y old
-- correspondientes a las columnas de la tabla
--
v_str varchar2(8000) := null;
begin
for i in (select column_name, data_type, data_length
from user_tab_columns
where table_name = p_table) loop
--
begin
select v_str||'g_'||p_table||'.'||'new_'||i.column_name||' := :new.'||i.column_name||'; '||
'g_'||p_table||'.'||'old_'||i.column_name||' := :old.'||i.column_name||'; '
into v_str
from dual;
Exception
WHEN others THEN
raise_application_error(-20201,' pkg_sys.get_new_old_str: '||SQLERRM);
end;
end loop;
return(v_str);
--
end get_new_old_str;
------------------------------------------------------------------------------------------
176
end active_condicion;
------------------------------------------------------------------------------------------
procedure active_accion(p_accion in varchar2) is
BEGIN
update acciones_eventos
set activo = 'S'
where accion = p_accion;
EXCEPTION
WHEN others THEN
raise_application_error(-20200,' pkg_sys.active_accion: '||p_accion||':
'||SQLERRM);
end active_accion;
------------------------------------------------------------------------------------------
procedure desactive_condicion(p_condicion in varchar2) is
BEGIN
update condiciones_eventos
set activo = 'N'
where condicion = p_condicion;
EXCEPTION
WHEN others THEN
raise_application_error(-20200,' pkg_sys.desactive_condicion: '||p_condicion||':
'||SQLERRM);
end desactive_condicion;
------------------------------------------------------------------------------------------
procedure desactive_accion(p_accion in varchar2) is
BEGIN
update acciones_eventos
set activo = 'N'
where accion = p_accion;
EXCEPTION
WHEN others THEN
raise_application_error(-20200,' pkg_sys.desactive_accion: '||p_accion||':
'||SQLERRM);
end desactive_accion;
------------------------------------------------------------------------------------------
procedure ins_bitacora(p_evento in varchar2,p_status in varchar2,p_glosa in varchar2)
is
begin
insert into bitacora_procesos
values(p_evento,sec_proc.nextval,sysdate,user,p_status,p_glosa);
end ins_bitacora;
------------------------------------------------------------------------------------------
183
-- convenciones usadas
-- -------------------
-- pr_ = procedure
-- fn_ o get_ = function
-- pkg_ = pakage
-- trg_ = trigger
-- t_ = tipo definidos por el usuario
-- p_ = parametro
-- fk_ foreign key
-- pk_ primary_key
-- ind_ indice
-- v_ variable local
-- g_ variable global
-- tab_ tabla pl_sql
-- c_ cursores
185
9. Bibliografía
[Ull1999] Ullman, Jefrey, “Introducción a los Sistemas de Bases de Datos”,1 Ed de., Prentice-
Hall, 1999.
[Cas1999] Castaño, Miguel, “Diseño de Base de Datos Relacionales”, 1 Ed de.,Ra-Ma, 1999.
[Koc1992] Koch, George, “Manual de Referencia”, 1 Ed de., Mcgraw-Hill, 1992.
[Gar1992] Georges Gardanin, “Bases De Donnees Object & relational”, 1 Ed de., Eyrolles,
1992.
[Gro1990] Groff, James, “Aplique SQL”, Falta edicion., Mcgraw-Hill, 1990.
[Cer1994] Ceri, Batini, “Diseño conceptual de bases de datos”, 1 Ed de, Addison-Wesley,
1994.
[Elm1992]Elmasri / Navathe,”Sistemas de Bases de Datos, Conceptos Fundamentales”, 2 Ed
de., Addison Wesley, 1992
[Dor1997] Dorsey, Paul, “ Manual de Oracle”, 1 Ed de., Mcgraw-Hill, 1997
[Mul1997] Muller, Robert, “Manual de Oracle Developer/2000”, 1 Ed de., Mcgraw-Hill,
1997
[Dor1997] Dorsey, Paul, “Manual de Oracle Designer/2000”, 1 Ed de., Mcgraw-Hill, 1997
[Pat1998] Paton, Norman, “Active Rules in Database Systems”, 1 Ed de., Springer-Verlag,
1998
Lecturas Complementarias
[Cel2000] Celma,Matilde. [Link] asignaturas/facultad/bdv/documentos/
teoria/temaII_1.pdf.
Universidad Politécnica de Valencia, Departamento de Sistemas Informáticos y Computación.
[Pia1999]Piattini, Mario[Link] [Link] /doc/ bbddavanzadas/ doc99
[Link].
Universidad Castilla-La Mancha, Departamento de Informática.
[Cal2000] Calero, Coral http:// [Link]/per/ccalero/
Universidad Castilla-La Mancha, Departamento de Informática.
186
10. Glosario
2. Un SGBDA tiene un modelo de reglas ECA, por lo que se debe extender el LDD
(lenguaje de definición de datos) del SGBD para definir reglas.
Las reglas ECA están compuestas por el evento, la condición y la acción, las cuáles están
presentes en nuestra base de datos activa, y también extiende el lenguaje de definición de
datos de una base de datos, ya que no es necesario solamente las sentencias que se utilizan
en una base de datos relacional, (Ej: create table, dop table, etc) sino que necesita de otra
sentencia como lo es el Trigger para poder definir las reglas de la base de datos activa.
4. Un SGBDA tiene un modelo de ejecución, nuestra base de datos activa tiene un modelo
de ejecución, este modelo es esencial ya que en él se especifica como se comportan las
reglas en
tiempo de ejecución, desde el momento en que ocurre el evento hasta que se ejecuta la
ación.
7. Un SGBDA debería ser ajustable, para que no sufra una degradación del
rendimiento en comparación con soluciones realizadas sobre los SGBD pasivos, esto
se refiere a que como una base de datos activa necesita controlar muchas líneas de código
para poder controlar el manejo de la base de datos y la funcionalidad de las reglas, puede
verse afectado su rendimiento, en nuestra BDA el código esta almacenado en la base de
datos, lo que produce una mayor interacción con la base de datos, sin que sea necesario
tener por intermediaria a la aplicación para generar los resultados.
También se requiere un diseño físico para los SGBDA, al momento de poner en
práctica el desarrollo de una aplicación de base de datos activa esta necesita un diseño
físico de cuáles elementos se va a componer la base de datos y como se van a comportar,
en nuestro caso diseñamos el modelo relacional, para luego proceder a la creación de las
tablas que componen la BDA.