[DUDA]PL/SQL en v$session

Iniciado por -Ramc-, 5 Noviembre 2009, 19:12 PM

0 Miembros y 1 Visitante están viendo este tema.

^Tifa^

#10
Cielo.

CitarO 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 :)

^Tifa^

#11
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 (sql) [Seleccionar]


set serveroutput on
declare
numero number;
usuario char(20);
begin
select username into usuario from v$session where username is not null;
select command into numero from v$session where user = usuario and command != 0;
dbms_output.put_line(numero||' '||usuario);
end;
/



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 (sql) [Seleccionar]


SQL> describe ejemplo;
Name                                      Null?    Type
----------------------------------------- -------- ----------------------------
NUMERO                                             NUMBER(38)
USUARIO                                            CHAR(20)

CREATE OR REPLACE TRIGGER TRIGO
BEFORE INSERT OR DELETE OR UPDATE ON EJEMPLO
FOR EACH ROW
DECLARE
numero NUMBER;
palabra CHAR(20);
BEGIN

IF INSERTING THEN
 SELECT USERNAME INTO palabra FROM v$session WHERE USERNAME IS NOT NULL;
 SELECT COMMAND INTO numero FROM v$session WHERE USER = palabra AND COMMAND != 0;
 :new.NUMERO := numero;
 :new.USUARIO := palabra;
ELSIF UPDATING THEN
 SELECT USERNAME INTO palabra FROM v$session WHERE USERNAME IS NOT NULL;
 SELECT COMMAND INTO numero FROM v$session WHERE USER = palabra AND COMMAND != 0;
 :new.NUMERO := numero;
 :new.USUARIO := palabra;
ELSE
 :new.NUMERO := 0;
 :new.USUARIO := NULL;
 DELETE FROM ejemplo WHERE NUMERO = 0 AND USUARIO IS NULL;
 COMMIT;
END IF;

END TRIGO;
/

SQL> select * from ejemplo;

no rows selected

SQL> insert into ejemplo values(1,'Mercado');

1 row created.

SQL> select * from ejemplo;

   NUMERO USUARIO
---------- --------------------
        3 PEPE

SQL> insert into ejemplo values(2,'Marta');

1 row created.

SQL> select * from ejemplo;

   NUMERO USUARIO
---------- --------------------
        3 PEPE
        3 PEPE



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