Foro de elhacker.net

Programación => Bases de Datos => Mensaje iniciado por: -Ramc- en 5 Noviembre 2009, 19:12 pm



Título: [DUDA]PL/SQL en v$session
Publicado por: -Ramc- en 5 Noviembre 2009, 19:12 pm
Hola, pasó a estrenar el nuevo subforo con esta duda.

Tengo que hacer un procedimento almacenado que me diga los comandos ejecutados por X usuario en X intervalo fechas que recibo por parametros; se que al ejecutar un comando con un usuario en la vista v$session, específicamente el parametro command se modifica con el código del último comando de ese usuario, pero, no hay manera de poner un trigger en esa vista, ya que me tocó hacer un enredo para obtener los usuarios conectados y guardarlos en una tabla.  :xD

Pero, no tengo idea de como hacer para guardar todas esas modificaciones que se hagan en v$session a mi tabla, lo que tenía pensado si no había otra forma era poner un bucle que fuera consultando v$session y al ver que algo se a modificado, lo guardara junto con la fecha actual, pero, este método, ademas de no ser eficiente, mantendría mi script dentro de un bucle infinito y tendría que abrir otra sesión, para ejecutar otros comandos.

Necesito su ayuda, si alguien sabe de algún otro método para conseguir esa información, que no sea el bucle mortal  :xD por favor hagamelo saber en este post, estaría muy agradecido, no que me den el código, ya que como ven puedo sacarlo con el bucle mortal jaja, pero, si necesito un empujon para saber si hay una forma más eficiente, apenas voy aprendiendo a manejar oracle, supongo que para ustedes será fácil, pero, la documentación tampoco es muy buena en internet.

Gracias y saludos.


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: ^Tifa^ en 5 Noviembre 2009, 19:22 pm
La tienes un pelin dificil  ;D  lo mas cercano que se me podria ocurrir (Ya que no puedes usar triggers y la verdad un bucle  :-\  no quisiera saber cuanto afectaria esto a la lectura de disco). Puedes intentar con un Evento? un Evento que se ejecute cada 60 segundos (1 minuto) y consulte la vista V$SESSION para obtener eso que solicitas... Ya con dicho evento podrias llamar tu procedimiento almacenado acorde a que se cumpla o no algo, lo negativo de los eventos que no es en tiempo real (Como un trigger) pero mejor que lea cada 60 segundos y no que lea cada segundo como haria un Bucle. Si te interesa sobre eventos en Oracle investigate sobre:

DBMS_SCHEDULER

 ;) 


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: Novlucker en 5 Noviembre 2009, 19:25 pm
De que BBDD estamos hablando?

Las consultas las crean los propios usuarios?, porque si lo tienes encapsulado podrías tener procedimientos que hagan lo que sea, y en el proceso llaman a otro que realice el LOG :-\

Saludos


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: -Ramc- en 5 Noviembre 2009, 19:36 pm
Muchas gracias ^TiFa^ , voy a probar con un evento y a investigar porque no me los explicaron en clases  :¬¬.

Porque estoy haciendo todo como sys para poder sacar la información y ni siquiera así me deja ponerle un trigger a esa vista, me dice que no es posible a ese tipo de vistas y blablabla.  :xD

Voy a probar y te comento.

Saludos.

The following error or errors occurred while posting this message:
Warning - while you were typing a new reply has been posted. You may wish to review your post.

Uso oracle.

Es que tengo que registrar todo, tanto comandos DML como DDL, de cualquier usuario.

Hay una vista v$session que me deja ver los usuarios, también tiene un campo llamado command que guarda un número que equivale a un comando, por ejemplo el 1 es CREATE TABLE y el 3 es SELECT y así, pero, a esa vista no le puedo poner un trigger.

Entonces tenía pensando un procedimiento que tomara los datos de la vista y los manipulara con un cursor para saber cualos son los que son :xD y los guardara en mi tabla junto con la fecha actual.

Después otro procedimiento recibiera 2 fechas(X, Y), que tomara los datos de esa tabla y me mostrara los datos que están entre las fechas X y Y.

No puedo dejar a ese procedimiento recopilando información sólo ya que necesito poder ejecutar otros comandos.

Saludos.


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: ^Tifa^ en 5 Noviembre 2009, 20:02 pm
Ahhhhhhhh pero yo pensaba que era que en tu clase los profesores te habian exhigido que no podias crear un TRIGGER sobre esta vista   :xD  por eso sugeri lo del evento, olvidalo.

Prueba lo siguiente:

Código
  1.  
  2. CREATE OR REPLACE TRIGGER trigo
  3.  AFTER LOGON ON DATABASE
  4. DECLARE
  5.  v_prog sys.v_$session.program%TYPE;
  6. BEGIN
  7.   /* Tu codigo Aqui */
  8. END;
  9. /
  10.  
  11.  

:) No me digas tampoco te explicaron sobre los TRIGGERS de sistemas y sus condiciones en Oracle???? (No estoy ya empapada del tema, hace unos meses abandone el PL/SQL en Oracle) Pero esto te puede ayudar, para crear TRIGGERS sobre vistas de SYSTEM.

http://www.psoug.org/reference/system_trigger.html

Tambien existe la posibilidad de que hagas otra vista de la vista v$session solamente con los campos que te interesan ver de v$session y crear un usuario con los roles que le permitan ver dicha vista en su entorno, y asi captar en tiempo real todos los cambios que requieras obtener.  :P Y puedes crear tu Stored Procedure llamando los datos de esta vista nueva que usa de referencia a v$session y mostrar en OUTPUT los resultados obtenidos  ;)  ya sabes que a tu ST puedes concatenarle la fecha actual con current_date();

Suerte con eso :)


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: -Ramc- en 5 Noviembre 2009, 20:12 pm
Sí, eso fue lo que hice para obtener los usuarios conectados, pero, no hay una que diga AFTER COMMAND EXECUTE ON DATABASE o sí??  :huh:


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: ^Tifa^ en 5 Noviembre 2009, 20:16 pm
No puedo afirmartelo lo siento.

Pero porque no creas una vista copia de v$session solo con los campos que deseas obtener ver? y dicha vista otorgale permisos a X usuario para que este usuario cree un procedimiento almacenado (si es requerido) para ver dichos datos llamando los campos de esa vista nueva?


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: ^Tifa^ en 5 Noviembre 2009, 20:51 pm
De hecho hice una mini-prueba en mi Oracle   :-*

Código
  1.  
  2. SQL> CREATE VIEW ejemplo AS SELECT command, USER#, username, STATUS, logon_time FROM v$session;
  3.  
  4. VIEW created.
  5.  
  6. SQL> SELECT * FROM ejemplo;
  7.  
  8.   COMMAND      USER# USERNAME                       STATUS   LOGON_TIM
  9. ---------- ---------- ------------------------------ -------- ---------
  10.         0          0                                ACTIVE   05-NOV-09
  11.         0          0                                ACTIVE   05-NOV-09
  12.         0          0                                ACTIVE   05-NOV-09
  13.         0          0                                ACTIVE   05-NOV-09
  14.         0          0                                ACTIVE   05-NOV-09
  15.         0          0                                ACTIVE   05-NOV-09
  16.         3          0 SYS                            ACTIVE   05-NOV-09
  17.         0          0                                ACTIVE   05-NOV-09
  18.         0          0                                ACTIVE   05-NOV-09
  19.         0          0                                ACTIVE   05-NOV-09
  20.         0          0                                ACTIVE   05-NOV-09
  21.  
  22.   COMMAND      USER# USERNAME                       STATUS   LOGON_TIM
  23. ---------- ---------- ------------------------------ -------- ---------
  24.         0          0                                ACTIVE   05-NOV-09
  25.         0          0                                ACTIVE   05-NOV-09
  26.         0          0                                ACTIVE   05-NOV-09
  27.         0          0                                ACTIVE   05-NOV-09
  28.         0          0                                ACTIVE   05-NOV-09
  29.         0          0                                ACTIVE   05-NOV-09
  30.         0          0                                ACTIVE   05-NOV-09
  31.  
  32. 18 ROWS selected.
  33.  
  34. SQL> CREATE USER pepe IDENTIFIED BY pepe;
  35.  
  36. USER created.
  37.  
  38. SQL> GRANT CONNECT, resource TO pepe;
  39.  
  40. GRANT succeeded.
  41.  
  42. SQL> GRANT SELECT, INSERT, UPDATE ON SYS.EJEMPLO TO pepe;
  43.  
  44. GRANT succeeded.
  45.  
  46. SQL> exit
  47.  
  48. oracle@marian:~$ sqlplus pepe/pepe                                                    
  49.  
  50. SQL*Plus: Release 10.2.0.1.0 - Production ON Thu Nov 5 15:39:45 2009
  51.  
  52. Copyright (c) 1982, 2005, Oracle.  ALL rights reserved.
  53.  
  54.  
  55. Connected TO:
  56. Oracle DATABASE 10g Enterprise Edition Release 10.2.0.1.0 - Production
  57. WITH the Partitioning, OLAP AND DATA Mining options                  
  58.  
  59. SQL> SELECT * FROM SYS.EJEMPLO;
  60.  
  61.   COMMAND      USER# USERNAME                       STATUS   LOGON_TIM
  62. ---------- ---------- ------------------------------ -------- ---------
  63.         0          0                                ACTIVE   05-NOV-09
  64.         3         60 PEPE                           ACTIVE   05-NOV-09
  65.         0          0                                ACTIVE   05-NOV-09
  66.         3          0 SYS                            ACTIVE   05-NOV-09
  67.         0          0                                ACTIVE   05-NOV-09
  68.         0          0                                ACTIVE   05-NOV-09
  69.         0          0                                ACTIVE   05-NOV-09
  70.         0          0                                ACTIVE   05-NOV-09
  71.         0          0                                ACTIVE   05-NOV-09
  72.         0          0                                ACTIVE   05-NOV-09
  73.         0          0                                ACTIVE   05-NOV-09
  74.  
  75.   COMMAND      USER# USERNAME                       STATUS   LOGON_TIM
  76. ---------- ---------- ------------------------------ -------- ---------
  77.         0          0                                ACTIVE   05-NOV-09
  78.         0          0                                ACTIVE   05-NOV-09
  79.         0          0                                ACTIVE   05-NOV-09
  80.         0          0                                ACTIVE   05-NOV-09
  81.         0          0                                ACTIVE   05-NOV-09
  82.         0          0                                ACTIVE   05-NOV-09
  83.         0          0                                ACTIVE   05-NOV-09
  84.         0          0                                ACTIVE   05-NOV-09
  85.  
  86. 19 ROWS selected.
  87.  
  88.  
  89.  
  90.  

Te podria servir... nunca se sabe  :P


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: -Ramc- en 5 Noviembre 2009, 20:54 pm
No puedo afirmartelo lo siento.

Pero porque no creas una vista copia de v$session solo con los campos que deseas obtener ver? y dicha vista otorgale permisos a X usuario para que este usuario cree un procedimiento almacenado (si es requerido) para ver dichos datos llamando los campos de esa vista nueva?
Pero, si creo una vista copia, es lo mismo que con la vista original, no puedo crearle trigger, así que tendría que sacarle los datos, guardarlos en mi tabla y consultarlos como haría con v$session la original.

O sea, necesito sacar el campo command cada vez que se modifique y guardarlo en otra tabla con la fecha actual y el usuario que lo hizo, pero, no puedo ponerle el trigger a v$session, ni a la vista creada de el.  :-\

EDIT: El error al intentar poner el trigger es:
Citar
Error report:
ORA-02030: can only select from fixed tables/views
02030. 00000 -  "can only select from fixed tables/views"
*Cause:    An attempt is being made to perform an operation other than
           a retrieval from a fixed table/view.
*Action:   You may only select rows from fixed tables/views.


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: ^Tifa^ en 5 Noviembre 2009, 21:17 pm
Hasta lo poco que me concierne, no es posible crear triggers en vistas  del esquema SYS  ;) sugeri la creacion de una copia a v$session por si ibas a trabajar sobre otro usuario y no SYSTEM. Tambien recuerda que las vistas reflejan todo en tiempo real, no es una tabla estatica que no se actualiza al menos que intervenga manos humanas.

Podrias crear tu evento con DBMS_SCHEDULER que se reproduzca cada 60 segundos (1 minuto) y llame los datos en ese tiempo y te vaya haciendo un log spool en un archivo fisico, o en una tabla o donde gustes de todo lo que ocurra cada 60 segundos sobre los campos que te interesan de v$session. (Pero esto no seria en tiempo real) sino cada 60 segundos.




Título: Re: [DUDA]PL/SQL en v$session
Publicado por: ^Tifa^ en 6 Noviembre 2009, 04:52 am
Cielo.

Citar
O sea, necesito sacar el campo command cada vez que se modifique y guardarlo en otra tabla con la fecha actual y el usuario que lo hizo, pero, no puedo ponerle el trigger a v$session, ni a la vista creada de el.

V$SESSION es un Sinonimo de V_$SESSION  ;) te he estado buscando otras vueltas al asunto porque como te he venido diciendo y como te dcontinuare diciendo (NO ES POSIBLE CREAR TRIGGERS EN OBJETOS PERTENECIENTES A SYS) Por ende estas tratando de hacer algo que literalmente es imposible.

La unica solucion que veo a lo que quieres hacer... y no te lo recomendaria para nada creeme. Es movilizar V_$SESSION fuera del esquema de SYS (Pero esto es hackear el funcionamiento del motor como tal, y no puedo prevenirte de que problemas puede esto presentarte... y olvidate del soporte). Por lo tanto no puedo guiarte en este proceso, sobretodo porque tendria que buscar la TABLA principal a la cual hace referencia la vista sección, dicha tabla puede ser 1 como puede ser varios Joines de varias tablas, para que entonces mudes esto a otro esquema que no sea SYS para poder crear tu TRIGGER y que sea soportable por el motor.

Obviando lo anterior,  por lo peligroso que resulta. Podrias realizar lo siguiente tambien (como opcion)
 
1) Crea 1 tabla de uso general (con permisos INSERT) que tenga los campos requeridos he importantes por ti (usuario, fecha, comando) esos campos se iran llenando en base a una solicitud que haras a la vista V$SESSION.

2) Crea 1 TRIGGER con tipo AFTER LOGON que tome datos del usuario al este iniciar sección y los mande a dicha tabla.

3)  Crea 1 TRIGGER anidado (after insert, after delete, after update, etc) por cada tabla de usuario donde al realizar una consulta SQL a una tabla esta solicite el campo correspondiente a la vista SESSION y rellene o actualize la tabla donde se van guardando todas las acciones.

Por ejemplo, imaginate que tengo un TRIGGER :

create trigger fulanito, before insert on tablita or after update on tablita for each row begin, if update select COMMAND into variable from v$session; elsif insert select COMMAND into variable1 from v$session;

Se que la sintaxis anterior esta erronea... la hice para ejemplificarte, bien tenemos 1 variable que capta el valor correspondiente a la consulta ejercida en dicha tabla digamos que si el usuario realizo un INSERT en la tabla, la variable que solicita y guarda el registro del campo COMMAND de V$session digamos que el valor es 2, bueno tu TRIGGER tiene que verificar despues de realizar todas esas comparaciones cual accion finalmente se realizo en la tabla, ejemplo:

if ( variable == 2 ); then
update tabla set comando = variable where user = show_user();
elsif (variable == 3) then
update tabla set comando = variable where user = show_user();

Espero que sea mas o menos entendible la idea.

Es una tarea mas pesada, pero menos riesgosa que movilizar objetos de SYS a un esquema individual (Aunque este paso sea mas corto) No es algo seguro.

PD: Se que no me explico muy bien, si tienes alguna duda o si te surge alguna idea compartela :)


Título: Re: [DUDA]PL/SQL en v$session
Publicado por: ^Tifa^ en 6 Noviembre 2009, 15:34 pm
Hola -Ramc-

Bueno, por tu requerimiento he retornado a mi practica con PL/SQL en Oracle (Que jure que jamas volveria a tirar 1 codigo en PL de Oracle) pero bueno  :rolleyes: deseo intentar ayudarte y darte ideas para que llegues a tu objetivo.

Quedamos en que efectivamente dentro del esquema SYS no puedes crear TRIGGERS ni a vistas ni a tablas, movilizar tablas o vistas de la metadata de SYS a otro esquema... no es recomendable (Aunque funcione, esto no es lo ideal). Asi que te sugeri crear en cada esquema de usuario 1 TRIGGER que solicite esos datos que te interesan en V$SESSION y los guarde en una tabla comun. (Es mas trabajoso, sobretodo si tienes miles de tablas, pero esto te dara una idea).

Mira el escenario que he realizado con el usuario PEPE, otorgue permisos de SELECT a V_$SESSION para PEPE asi con su TRIGGER puedo solicitar info de este usuario y irla guardando en una tabla, por ejemplo.

Código
  1.  
  2. SET serveroutput ON
  3. DECLARE
  4. numero NUMBER;
  5. usuario CHAR(20);
  6. BEGIN
  7. SELECT username INTO usuario FROM v$session WHERE username IS NOT NULL;
  8. SELECT command INTO numero FROM v$session WHERE USER = usuario AND command != 0;
  9. dbms_output.put_line(numero||' '||usuario);
  10. END;
  11. /
  12.  
  13.  

Si haces lo anterior veras que obtuve en tiempo real el valor de COMMAND y USUARIO que ejecuta la accion. Ahora chequea esto:

Código
  1.  
  2. SQL> DESCRIBE ejemplo;
  3. Name                                      NULL?    TYPE
  4. ----------------------------------------- -------- ----------------------------
  5. NUMERO                                             NUMBER(38)
  6. USUARIO                                            CHAR(20)
  7.  
  8. CREATE OR REPLACE TRIGGER TRIGO
  9. BEFORE INSERT OR DELETE OR UPDATE ON EJEMPLO
  10. FOR EACH ROW
  11. DECLARE
  12. numero NUMBER;
  13. palabra CHAR(20);
  14. BEGIN
  15.  
  16. IF INSERTING THEN
  17.  SELECT USERNAME INTO palabra FROM v$session WHERE USERNAME IS NOT NULL;
  18.  SELECT COMMAND INTO numero FROM v$session WHERE USER = palabra AND COMMAND != 0;
  19.  :NEW.NUMERO := numero;
  20.  :NEW.USUARIO := palabra;
  21. ELSIF UPDATING THEN
  22.  SELECT USERNAME INTO palabra FROM v$session WHERE USERNAME IS NOT NULL;
  23.  SELECT COMMAND INTO numero FROM v$session WHERE USER = palabra AND COMMAND != 0;
  24.  :NEW.NUMERO := numero;
  25.  :NEW.USUARIO := palabra;
  26. ELSE
  27.  :NEW.NUMERO := 0;
  28.  :NEW.USUARIO := NULL;
  29.  DELETE FROM ejemplo WHERE NUMERO = 0 AND USUARIO IS NULL;
  30.  COMMIT;
  31. END IF;
  32.  
  33. END TRIGO;
  34. /
  35.  
  36. SQL> SELECT * FROM ejemplo;
  37.  
  38. no ROWS selected
  39.  
  40. SQL> INSERT INTO ejemplo VALUES(1,'Mercado');
  41.  
  42. 1 ROW created.
  43.  
  44. SQL> SELECT * FROM ejemplo;
  45.  
  46.    NUMERO USUARIO
  47. ---------- --------------------
  48.         3 PEPE
  49.  
  50. SQL> INSERT INTO ejemplo VALUES(2,'Marta');
  51.  
  52. 1 ROW created.
  53.  
  54. SQL> SELECT * FROM ejemplo;
  55.  
  56.    NUMERO USUARIO
  57. ---------- --------------------
  58.         3 PEPE
  59.         3 PEPE
  60.  
  61.  

Utilize como te dije 1 TRIGGER anidado por cada tabla, y asi se guarda la accion y el usuario en una tercera tabla  ;)  para la fecha actual del comando ejecutado llama al campo LOGON_TIME de V$SESSION dentro del TRIGGER.

Ojala te pueda servir de guia para expandir lo que andas solicitando y puedas llegar a un objetivo final  :P