Mostrando entradas con la etiqueta truncate. Mostrar todas las entradas
Mostrando entradas con la etiqueta truncate. Mostrar todas las entradas

viernes, 22 de abril de 2016

El Privilegio DROP ANY TABLE es Peligroso

Estaba leyendo el blog de Laurent Schneider aquí. Según él, un usuario debe tener el privilegio DROP ANY TABLE para hacer un TRUNCATE en una tabla que pertenece a otro usuario. Esto me pareció extraño y por eso me decidí a probarlo en Oracle 11.2.0.1. Creé un usuario (USER1) que sería el dueño de una tabla:

SQL> create user user1
  2  identified by user1
  3  default tablespace users
  4  quota 10m on users
  5  /
 
User created.
 
SQL> grant
  2  create session,
  3  create table,
  4  select any dictionary
  5  to user1
  6  /
 
Grant succeeded.
 
SQL>

Luego creé un usuario (USER2) que intentaría emplear el privilegio DROP ANY TABLE para hacer un TRUNCATE en la tabla de USER1:

SQL> create user user2
  2  identified by user2
  3  /
 
User created.
 
SQL> grant
  2  create session,
  3  drop any table to user2
  4  /
 
Grant succeeded.
 
SQL>

El usuario USER1 creó una tabla con datos:

SQL> conn user1/user1
Connected.
SQL> create table tab1 as
  2  select * from dba_tables
  3  /
 
Table created.
 
SQL> grant select on tab1 to user2
  2  /
 
Grant succeeded.
 
SQL>

El usuario USER2 contó las líneas en la tabla, hizo el TRUNCATE y contó las líneas otra vez para verificar que el TRUNCATE había funcionado:

SQL> conn user2/user2
Connected.
SQL> select count(*) from user1.tab1
  2  /
 
  COUNT(*)
----------
      3192
 
SQL> truncate table user1.tab1
  2  /
 
Table truncated.
 
SQL> select count(*) from user1.tab1
  2  /
 
  COUNT(*)
----------
         0
 
SQL>

La idea de dar el privilegio DROP ANY TABLE al usuario USER2 me pareció peligroso y por eso lo revoqué:

SQL> conn / as sysdba
Connected.
SQL> revoke drop any table from user2
  2  /
 
Revoke succeeded.
 
SQL> grant create procedure to user1
  2  /
 
Grant succeeded.
 
SQL>

Entonces el usuario USER1 creó un procedimiento para hacer un TRUNCATE en su tabla:

SQL> conn user1/user1
Connected.
SQL> create procedure truncate_tab1 as
  2  begin
  3    execute immediate 'truncate table tab1';
  4  end;
  5  /
 
Procedure created.
 
SQL>

y le dio al usuario USER2 el derecho de ejecutarlo:

SQL> grant execute on truncate_tab1 to user2
  2  /
 
Grant succeeded.
 
SQL> insert into tab1 select * from dba_tables
  2  /
 
3193 rows created.
 
SQL>

Con este procedimiento el usuario USER2 podía todavía hacer un TRUNCATE en la tabla de USER1:

SQL> conn user2/user2
Connected.
SQL> select count(*) from user1.tab1
  2  /
 
  COUNT(*)
----------
      3193
 
SQL> exec user1.truncate_tab1;
 
PL/SQL procedure successfully completed.
 
SQL> select count(*) from user1.tab1
  2  /
 
  COUNT(*)
----------
         0
 
SQL> 

Pero, por supuesto, no podía borrar las tablas de los otros usuarios.

sábado, 10 de mayo de 2014

Oracle no Ejecuta un Disparador AFTER DELETE Tras Hacer un Truncate

En este ejemplo, quiero mostrar que Oracle no ejecute un disparador AFTER DELETE después de hacer un TRUNCATE. Lo probé en Oracle 11.2. Para empezar, creé una tabla:

SQL> create table tab1 (my_name varchar2(10))
  2  /

Tabla creada.

SQL>

Luego inserté una fila en la tabla:

SQL> insert into tab1 values ('Andrew')
  2  /

1 fila creada.

SQL> commit
  2  /

Confirmación terminada.

SQL> select * from tab1
  2  /

MY_NAME
----------
Andrew

SQL>

Entonces creé una segunda tabla: 

SQL> create table tab2 (my_name varchar2(10))
  2  /

Tabla creada.

SQL>

Creé un disparador para insertar filas en TAB2 tras borrarlas de TAB1:

SQL> create or replace trigger trig1
  2  after delete on tab1
  3  for each row
  4  begin
  5  insert into tab2 (my_name) values (:old.my_name);
  6  end;
  7  /
 
Disparador creado.


SQL>

Para probar el disparador, empleé un DELETE para borrar la fila de TAB1. La fila apareció en TAB2:

SQL> delete tab1
  2  /

1 fila suprimida.

SQL> select * from tab1
  2  /

ninguna fila seleccionada

SQL> select * from tab2
  2  /

MY_NAME
----------
Andrew

SQL>

Ejecuté un ROLLBACK y la fila volvió de TAB2 a TAB1:

SQL> rollback
  2  /
 
Rollback terminado.
 
SQL> select * from tab1
  2  /
 
MY_NAME
----------
Andrew
 
SQL> select * from tab2
  2  /
 
ninguna fila seleccionada


SQL>

Repetí la prueba con TRUNCATE: 

SQL> truncate table tab1
  2  /
 
Tabla truncada.


SQL>

La fila desapareció de TAB1:

SQL> select * from tab1
  2  /
 
ninguna fila seleccionada


SQL>

... pero Oracle no ejecutó el disparador y la fila no apareció en TAB2:

SQL> select * from tab2
  2  /
 
ninguna fila seleccionada
 

SQL>

... y tras hacer un ROLLBACK, la fila no volvió a TAB1 porque TRUNCATE es DDL y incluye un COMMIT:

SQL> rollback
  2  /
 
Rollback terminado.
 
SQL> select * from tab1
  2  /
 
ninguna fila seleccionada
 
SQL> select * from tab2
  2  /
 
ninguna fila seleccionada
 
SQL> 


En inglés / in English