oracle - 动态 SQL 和 ORA-00911

标签 oracle plsql

我有一个名为 Tamaris 的数据库,其中包含一个表 User。我创建了一个触发器,以便每次在用户表中插入一行时在数据库中创建一个新用户。这是 PL/SQL 代码:

CREATE OR REPLACE
TRIGGER UTILISATEUR_CREATE_USER_TRG 
AFTER INSERT ON UTILISATEUR 
FOR EACH ROW
DECLARE
  nom_compte NVARCHAR2(20 CHAR);
  str_create VARCHAR2(300);
  str_grant VARCHAR(250);
  type_compte NUMBER;
  unauthorized_exception EXCEPTION;
BEGIN

  CASE
    WHEN :new.idtypecompte = 1 THEN
      nom_compte := :new.pseudoutilisateur;
      type_compte := 1;
    WHEN :new.idtypecompte = 2 THEN
      nom_compte := 'AC_'|| :new.pseudoutilisateur;
      type_compte := 2;
    WHEN :new.idtypecompte = 3 THEN
      RAISE unauthorized_exception;
  END CASE;

  str_create := 'CREATE USER '|| nom_compte ||' IDENTIFIED BY '|| :new.passwordutilisateur ||' DEFAULT TABLESPACE tamaris TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON tamaris;' ;
  EXECUTE IMMEDIATE str_create;



  IF type_compte = 1 THEN
    str_grant := 'GRANT Base_User TO '|| nom_compte ||';' ;
    EXECUTE IMMEDIATE str_grant;
  ELSE
    str_grant := 'GRANT Adv_User TO '|| nom_compte ||';' ;
    EXECUTE IMMEDIATE str_grant;
  END IF;

EXCEPTION
  WHEN unauthorized_exception THEN
      dbms_output.put_line('Impossible de créer un autre gestionnaire');
END;

当我在表 User 中插入一行时,触发器会触发,我得到:

保存对“TAMARIS”.“UTILISATEUR”的修改时出错: 第 3 行:ORA-00911:无效字符 ORA-06512: 在“TAMARIS.UTILISATEUR_CREATE_USER_TRG”,第 22 行 ORA-04088: 执行“TAMARIS.UTILISATEUR_CREATE_USER_TRG”时出错 ORA-06512: 在第 1 行

根据记录,str_create 中的请求在带有随机参数的触发器之外工作(仅当用 BEGIN; END; 包装时)。因此我尝试了:

str_create := 'BEGIN CREATE USER '|| nom_compte ||' IDENTIFIED BY '|| :new.passwordutilisateur ||' DEFAULT TABLESPACE tamaris TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON tamaris; END;' ;

仍然无法工作。如果有任何意见,我将不胜感激,谢谢。

编辑:

建议的程序内容:

CREATE OR REPLACE
PROCEDURE CREATE_USER_IN_DB(p_username IN NVARCHAR2, p_password IN UTILISATEUR.passwordutilisateur%type, p_type IN NUMBER ) AS 
BEGIN
  EXECUTE IMMEDIATE 'CREATE USER '|| p_username ||' IDENTIFIED BY '|| p_password ||' DEFAULT TABLESPACE tamaris 
  TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON tamaris';

  IF p_type = 1 THEN
    EXECUTE IMMEDIATE 'GRANT Base_User TO '|| p_username;
  ELSE
    EXECUTE IMMEDIATE 'GRANT Adv_User TO '|| p_username;
  END IF;
END CREATE_USER_IN_DB;

编辑2:

我如何在触发器之外调用该过程:

BEGIN 
CREATE_USER_IN_DB('whatever','quickpass', 2); 
END;

我明白

ORA-00900: 
Invalid SQL instruction
ORA-06512: at "TAMARIS.CREATE_USER_IN_DB", line 3
ORA-06512: at line 2
00900. 00000 -  "invalid SQL statement"
*Cause:    
*Action:

最佳答案

1) 正如 @Bob Jarvis 所建议的,当您构建要传递给 EXECUTE IMMEDIATE 的 SQL 语句时,该 SQL 语句不应包含尾随分号 ;

2) 由于CREATE USERGRANT 是DDL 语句,因此它们在执行之前和之后都会发出隐式提交。这意味着您不能在触发器中调用 DDL 语句,因为触发器不能导致事务结束。如果您确实想这样做(并且创建用户作为在表中插入行的副作用似乎是一个非常有问题的体系结构),则必须异步执行此操作。您的触发器可以调用 DBMS_JOB 来安排作业在当前事务完成后运行,并且该作业可以执行 DDL 语句。例如,如果您创建一个实际创建用户的过程(这是所有 DDL 所在的位置)

CREATE PROCEDURE create_user( p_username IN NVARCHAR2, 
                              p_password IN UTILISATEUR.passwordutilisateur%type,
                              p_type     IN NUMBER )
AS
  <<implement procedure>>

那么你的触发器可以做类似的事情

CREATE OR REPLACE
TRIGGER UTILISATEUR_CREATE_USER_TRG 
AFTER INSERT ON UTILISATEUR 
FOR EACH ROW
DECLARE
  nom_compte NVARCHAR2(20 CHAR);
  str_create VARCHAR2(300);
  str_grant VARCHAR(250);
  type_compte NUMBER;
  l_jobno PLS_INTEGER;
  unauthorized_exception EXCEPTION;
BEGIN

  CASE
    WHEN :new.idtypecompte = 1 THEN
      nom_compte := :new.pseudoutilisateur;
      type_compte := 1;
    WHEN :new.idtypecompte = 2 THEN
      nom_compte := 'AC_'|| :new.pseudoutilisateur;
      type_compte := 2;
    WHEN :new.idtypecompte = 3 THEN
      RAISE unauthorized_exception;
  END CASE;

  dbms_job.submit( l_jobno,
                   'BEGIN create_user( ''' || nom_compte || ''', ' || 
                                       '''' || :new.passwordutilisateur || ''', ' || 
                                       type_compte || '); END;' );
END;

关于oracle - 动态 SQL 和 ORA-00911,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11249878/

相关文章:

sql - 我的 Oracle SQL 想要提高性能

oracle - PL/SQL Developer (allroundautomations.com) 在编译包主体时挂起

eclipse - 在eclipse中添加Oracle服务器的Weblogic Home&Java home的路径

sql - 多表条件插入何时需要别名?

mysql - Hive 查询按年份和 ID 获取日期列组的最小值和最大值

java - ORA-29481 : Implicit results cannot be returned to client when calling Oracle 12c procedure from JDBC

oracle - dbms_aq.dequeue_array,第一条消息返回两次

sql - 表左连接

oracle - SquirreL SQL 客户端 3.7.1 上的 PL/SQL

plsql - 如何在 PL SQL 中检查解码函数内的 2 个表达式