E16 - Diseño de Sistemas de Bases de Datos Boletín 3 Nombre: 1. Esta práctica está dedicada a la creación de disparadores sobre sentencias DDL (lenguaje de definición de datos) y sobre eventos de la Base de Datos. También veremos la ejecución de trabajos de forma periódica. A continuación se detallan los eventos que pueden se capturados, así como los procedimientos del paquete DBMS_JOB: Sobre sentencias DDL Sobre eventos de la BD DBMS_JOB ALTER SERVERERROR SUBMIT ANALYZE LOGON REMOVE ASSOCIATE STATISTICS LOGOFF CHANGE AUDIT STARTUP WHAT COMMENT SHUTDOWN NEXT_DATE CREATE SUSPEND INSTANCE DISASSOCIATE STATISTICS INTERVAL DROP BROKEN GRANT RUN NOAUDIT USER_EXPORT RENAME REVOKE TRUNCATE DDL La documentación en línea con todos los detalles puede ser consultada en http:anubis~oraclemanuales 2. Esta sesión se realizará sobre Oracle9i. Para acceder a esta versión hay que entrar en SQL*Plus con el siguiente nombre de usuario, sustituyendo las X por el número correspondiente: alxxxxxxalxxxxxx@pc Es necesario volver a crear las tablas utilizadas en el Boletín 1, ejecutando SQL> start homeinfdbapublice16crea_tablas.sql 3. Vamos a empezar definiendo 2 disparadores para poder controlar quien se conecta a la base de datos y cuánto tiempo permanece conectado. Para ello, crearemos un disparador sobre el evento LOGON y otro sobre LOGOFF que actualice la fila del LOGON correspondiente. Para realizar este punto, teclearemos el siguiente código en un fichero llamado trg_bd_1.sql create or replace trigger al000000_01 after logon on schema insert into p_logins (owner, f_inicio, ip, session_id) values (ora_login_user, sysdate, nvl(ora_client_ip_address,'desconocida'), dbms_session.unique_session_id);
create or replace trigger al000000_02 before logoff on schema update p_logins set f_fin = sysdate where owner = ora_login_user and session_id = dbms_session.unique_session_id; Una vez creado el fichero, lo ejecutaremos desde el prompt del SQL*Plus: SQL> start trg_bd_1 4. Una vez creados los 2 disparadores, procedemos a realizar las correspondientes pruebas: SQL> connect alxxxxxx********@pc SQL> connect alxxxxxx********@pc Cada connect implica el cierre de la conexión anterior. Para ver si realmente se ha almacenado las conexiones, realizaremos la consulta siguiente: select owner, to_char(f_inicio, 'dd-mm-yyyy hh24:mi:ss'), to_char(f_fin, 'dd-mm-yyyy hh24:mi:ss') from p_logins; Se obtiene la información esperada?... 5. El siguiente disparador que vamos a definir, va a permitir registrar todos los errores que produzcamos. Para ello lo dispararemos sobre el evento SERVERERROR y restringido a nuestro esquema (SCHEMA). Para realizar este punto, teclearemos el siguiente código en un fichero llamado trg_bd_2.sql create or replace trigger al000000_03 after servererror on schema insert into p_errores (fecha, error_texto) values (sysdate, dbms_utility.format_error_stack); Una vez creado el fichero, lo ejecutaremos desde el prompt del sqlplus: SQL> start trg_bd_2 6. Para realizar las pruebas sobre el disparador anterior, podemos lanzar alguna sentencia simple, o incluso alguna sentencia de la sesión anterior. desc patata drop table patata; insert into p_puntuaciones (usu_usuario, ite_id, puntuacion) values ( al000000, 3, 7);
Qué consulta haríamos para comprobar su funcionamiento?... 7. A continuación, vamos a proceder a la creación de un trabajo que guardaremos en la cola de trabajos. Este trabajo, lanzará un procedimiento, que conectándose a anubis, nos mandará un e-mail con un listado de las conexiones que se han realizado. El procedimiento se encuentra en un fichero que hay que ejecutar: SQL> start homeinfdbapublice16crea_proc_mail.sql 8. Una vez creado el procedimiento, teclearemos el bloque PLSQL siguiente. El trabajo almacenado se ejecutará según el campo NEXT_DATE (tercer parámetro), y se ejecutará periódicamente según formula definida en INTERVAL (cuarto parámetro). declare job number; dbms_job.submit(job, 'manda_mail;', sysdate, 'sysdate + 1(24*12)'); commit; Se ha ejecutado el trabajo?... 9. Para comprobar que se ha almacenado correctamente y cuales son sus parámetros, podemos realizar la siguiente consulta: select job, to_char(next_date,'dd-mm-yyy hh24:mi:ss'), interval, what from user_jobs; Se obtiene la fila con los datos previstos?... 10. El trabajo que hemos creado, se ejecutará a intervalos de 5 minutos, lo cual puede ser un poco engorroso, por lo que procederemos a modificar su frecuencia de disparo para situarla a sólo una vez al día. El <número de job> que hay que indicar, es el obtenido en la consulta anterior (JOB). dbms_job.interval(<número de job>, 'trunc(sysdate) + 1'); Sabrías eliminar el trabajo de la cola?...
ANEXO A ANEXO B: DBMS_JOB.SUBMIT ( job OUT BINARY_INTEGER, what IN VARCHAR2, next_date IN DATE DEFAULT sysdate, interval IN VARCHAR2 DEFAULT 'null', no_parse IN BOOLEAN DEFAULT FALSE, instance IN BINARY_INTEGER DEFAULT any_instance, force IN BOOLEAN DEFAULT FALSE); DBMS_JOB.INTERVAL ( job IN BINARY_INTEGER, interval IN VARCHAR2); DBMS_JOB.REMOVE ( job IN BINARY_INTEGER);
ANEXO C create or replace procedure manda_mail is conn utl_tcp.connection; len number(6); res varchar2(3); usuario varchar2(30); cuerpo varchar2(2000); cursor cur is select rpad(owner,20) rpad('conexiones: ' to_char(count(*)),30) 'Minutos: ' to_char(round(sum((f_fin-f_inicio)*60*24))) linea from p_logins group by owner; select user into usuario from dual; cuerpo := ''; for r in cur loop cuerpo := cuerpo r.linea chr(10); end loop; cuerpo := cuerpo '.' chr(10); conn := utl_tcp.open_connection ('anubis.uji.es', 25); len := utl_tcp.write_line(conn, 'HELO anubis.uji.es'); len := utl_tcp.write_line(conn, 'MAIL FROM: job_oracle@anubis.uji.es'); len := utl_tcp.write_line(conn, 'RCPT TO: ' usuario '@alumail.uji.es'); len := utl_tcp.write_line(conn, 'DATA'); len := utl_tcp.write_line(conn, cuerpo); len := utl_tcp.write_line(conn, 'QUIT'); utl_tcp.close_connection(conn);