Ejecutar inmediato dentro de un procedimiento almacenado sigue dando un error de priviligios insuficiente

StackOverflow https://stackoverflow.com/questions/996198

Pregunta

Aquí está la definición del procedimiento almacenado:

CREATE OR REPLACE PROCEDURE usp_dropTable(schema VARCHAR, tblToDrop VARCHAR) IS
BEGIN
  DECLARE v_cnt NUMBER;
  BEGIN
    SELECT COUNT(*) 
      INTO v_cnt 
      FROM all_tables 
     WHERE owner = schema
       AND table_name = tblToDrop;

     IF v_cnt > 0 THEN 
        EXECUTE IMMEDIATE('DROP TABLE someschema.some_table PURGE');
     END IF;
   END;
END;

Aquí está la llamada:

CALL usp_dropTable('SOMESCHEMA', 'SOME_TABLE');

Por alguna razón, sigo recibiendo un error de privilegios insuficientes para el comando de ejecución inmediata. Miré en línea y descubrí que el error de privilegios insuficientes generalmente significa que la cuenta de usuario de Oracle no tiene privilegios para el comando utilizado en la consulta que se pasa, que en este caso se cae. Sin embargo, tengo privilegios de caída. Estoy realmente confundido y parece que no puedo encontrar una solución que funcione para mí.

Gracias de antemano.

SOLUCIÓN:

Como Steve mencionó a continuación, Oracle Security Model es extraño ya que necesita saber explícitamente en algún lugar del procedimiento qué tipo de privilegios usar. La forma de informar a Oracle es usar la palabra clave Authid en la instrucción Crear o Reemplazar. Si desea el mismo nivel de privilegios que el creador del procedimiento, utiliza Authid Definder. Si desea que Oracle use los privilegios del usuario que actualmente ejecuta el procedimiento almacenado, desea usar Authid Current_User. La declaración del procedimiento se ve de la siguiente manera:

CREATE OR REPLACE PROCEDURE usp_dropTable(schema VARCHAR, tblToDrop VARCHAR) 
AUTHID CURRENT_USER IS
BEGIN
  DECLARE v_cnt NUMBER;
  BEGIN
    SELECT COUNT(*) 
      INTO v_cnt 
      FROM all_tables 
     WHERE owner = schema
       AND table_name = tblToDrop;

     IF v_cnt > 0 THEN 
        EXECUTE IMMEDIATE('DROP TABLE someschema.some_table PURGE');
     END IF;
   END;
END;

Gracias a todos por responder. Definitivamente fue un problema muy molesto para llegar a la solución.

¿Fue útil?

Solución

El modelo de seguridad de Oracle es tal que al ejecutar SQL dinámico utilizando Ejecutar inmediato (dentro del contexto de un bloque o procedimiento PL/SQL), el usuario no tiene privilegios a objetos o comandos que se otorgan a través de la membresía de roles. Es probable que su usuario tenga un rol de "DBA" o algo similar. Debe otorgar explícitamente los permisos de "caída de la tabla" a este usuario. Lo mismo se aplicaría si intentara seleccionar entre tablas en otro esquema (como SYS o System); necesitaría otorgar privilegios seleccionados explícitos en esa tabla a este usuario.

Otros consejos

Debe usar este ejemplo con Authid Current_User :

CREATE OR REPLACE PROCEDURE Create_sequence_for_tab (VAR_TAB_NAME IN VARCHAR2)
   AUTHID CURRENT_USER
IS
   SEQ_NAME       VARCHAR2 (100);
   FINAL_QUERY    VARCHAR2 (100);
   COUNT_NUMBER   NUMBER := 0;
   cur_id         NUMBER;
BEGIN
   SEQ_NAME := 'SEQ_' || VAR_TAB_NAME;

   SELECT COUNT (*)
     INTO COUNT_NUMBER
     FROM USER_SEQUENCES
    WHERE SEQUENCE_NAME = SEQ_NAME;

   DBMS_OUTPUT.PUT_LINE (SEQ_NAME || '>' || COUNT_NUMBER);

   IF COUNT_NUMBER = 0
   THEN
      --DBMS_OUTPUT.PUT_LINE('DROP SEQUENCE ' || SEQ_NAME);
      -- EXECUTE IMMEDIATE 'DROP SEQUENCE ' || SEQ_NAME;
      -- ELSE
      SELECT 'CREATE SEQUENCE COMPTABILITE.' || SEQ_NAME || ' START WITH ' || ROUND (DBMS_RANDOM.VALUE (100000000000, 999999999999), 0) || ' INCREMENT BY 1'
        INTO FINAL_QUERY
        FROM DUAL;

      DBMS_OUTPUT.PUT_LINE (FINAL_QUERY);
      cur_id := DBMS_SQL.OPEN_CURSOR;
      DBMS_SQL.parse (cur_id, FINAL_QUERY, DBMS_SQL.v7);
      DBMS_SQL.CLOSE_CURSOR (cur_id);
   -- EXECUTE IMMEDIATE FINAL_QUERY;

   END IF;

   COMMIT;
END;
/

Puede usar "Authid Current_User" en el cuerpo de su definición de procedimiento para sus requisitos.

Alternativamente, puede otorgar al usuario DROP_ANY_TABLE privilegio si es necesario y el procedimiento se ejecutará como es sin la necesidad de ninguna alteración. Peligroso tal vez pero depende de lo que estés haciendo :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top