如何解决在尝试插入时出现的触发器错误?Oracle SQL

huangapple go评论74阅读模式
英文:

How to solve this trigger error while trying to insert? oracle sql

问题

I have a sp and a trigger, the trigger is supposed to call the procedure after I insert into the users table so I can create a new session user, but when I try to insert, I get the following errors:

  • ORA-04092: cannot COMMIT in a trigger ORA-06512: at "SQL_VNNKBUUOCEZLLPHWSSGEFNOQE.CREAR_USUARIO", line 10
  • ORA-06512: at "SQL_VNNKBUUOCEZLLPHWSSGEFNOQE.TRG_INSERT_USUARIO", line 2
  • ORA-06512: at "SYS.DBMS_SQL", line 1721

This is my sql code:

CREATE OR REPLACE PROCEDURE crear_usuario(
    p_nombre_de_usuario IN VARCHAR2,
    p_correo IN VARCHAR2,
    p_contrasenia IN VARCHAR2
)
AS
BEGIN
    EXECUTE IMMEDIATE 'CREATE USER ' || p_nombre_de_usuario || ' IDENTIFIED BY ' || p_contrasenia;
END;

CREATE OR REPLACE TRIGGER trg_insert_usuario
AFTER INSERT ON usuario
FOR EACH ROW
BEGIN
crear_usuario(:NEW.nombre_de_usuario, :NEW.correo, :NEW.contrasenia);
END;

The weird thing is that I don't have any commit.

英文:

I have a sp and a trigger, the trigger is supposed to call the procedure after I insert into the users table so I can create a new session user, but when I try to insert, I get the following errors:

  • ORA-04092: cannot COMMIT in a trigger ORA-06512: at "SQL_VNNKBUUOCEZLLPHWSSGEFNOQE.CREAR_USUARIO", line 10
  • ORA-06512: at "SQL_VNNKBUUOCEZLLPHWSSGEFNOQE.TRG_INSERT_USUARIO", line 2
  • ORA-06512: at "SYS.DBMS_SQL", line 1721

This is my sql code:

CREATE OR REPLACE PROCEDURE crear_usuario(
    p_nombre_de_usuario IN VARCHAR2,
    p_correo IN VARCHAR2,
    p_contrasenia IN VARCHAR2
)
AS
BEGIN
    EXECUTE IMMEDIATE 'CREATE USER ' || p_nombre_de_usuario || ' IDENTIFIED BY ' || p_contrasenia;
END;

CREATE OR REPLACE TRIGGER trg_insert_usuario
AFTER INSERT ON usuario
FOR EACH ROW
BEGIN
crear_usuario(:NEW.nombre_de_usuario, :NEW.correo, :NEW.contrasenia);
END;

The weird thing is that I don't have any commit

答案1

得分: 1

从我的角度来看,你应该在这种情况下避免使用触发器。应该将所有操作都放在存储过程中。

顺便说一下,在触发器中会触发提交是什么原因:触发器是由DDL语句触发的,它会在DDL语句之前和之后执行隐式提交。

你能在触发器中执行提交吗?当然可以,如果你将它设置为自主事务,但正如我所说,我不建议这样做。

这是一个可能的示例;代码应该由具有不太常见权限的用户运行 - create user

包含用户的表:当然,将密码存储为明文是明显错误的做法,但这只是一个简单的示例。

SQL> create table users
  2    (user_id     number generated always as identity primary key,
  3     username    varchar2(30) unique,
  4     password    varchar2(30)
  5    );
  
Table created.

存储过程:如果表中不存在行,则将一行插入表中,如果插入了行,则创建用户:

SQL> create or replace procedure p_create_user
  2    (p_username in varchar2,
  3     p_password in varchar2
  4    ) as
  5  begin
  6    insert into users (username, password)
  7    select p_username, p_password
  8    from dual
  9    where not exists (select null
 10                      from users u
 11                      where u.username = p_username
 12                     );
 13    if sql%rowcount = 1 then
 14      execute immediate 'create user ' || p_username || ' identified by ' || p_password;
 15    end if;
 16  end;
 17  /
  
Procedure created.

让我们来试试:

SQL> exec p_create_user('littlefoot', 'whatever');

PL/SQL procedure successfully completed.

SQL> select * From users;

   USER_ID USERNAME                       PASSWORD
---------- ------------------------------ ------------------------------
         1 littlefoot                     whatever

我可以再次插入相同的用户吗?不行:

SQL> exec p_create_user('littlefoot', 'whatever');

PL/SQL procedure successfully completed.

SQL> select * From users;

   USER_ID USERNAME                       PASSWORD
---------- ------------------------------ ------------------------------
         1 littlefoot                     whatever

不同的用户呢?

SQL> exec p_create_user('bigfoot', 'whatever');

PL/SQL procedure successfully completed.

SQL> select * From users;

   USER_ID USERNAME                       PASSWORD
---------- ------------------------------ ------------------------------
         1 littlefoot                     whatever
         2 bigfoot                        whatever

如果我尝试以新创建的用户身份连接会发生什么:

SQL> connect littlefoot/whatever@pdb1
ERROR:
ORA-01045: user LITTLEFOOT lacks CREATE SESSION privilege; logon denied


Warning: You are no longer connected to ORACLE.
SQL>

显然,仅仅创建用户是不够的。用户存在,但不能执行任何操作。我想你以后会处理这个问题。

英文:

From my point of view, you should avoid trigger in this scenario. Do everything in a stored procedure.

BTW, what caused commit in a trigger: it was a DDL, it performs implicit commit right before and right after the DDL statement.

Can you commit in a trigger at all? Sure you can, if you make it an autonomous transaction, but - as I said - I wouldn't do that.


Here's an example of what you might do; code should be ran by user who has privilege that isn't that common - create user.

Table that contains users: of course, storing passwords as plain text is plain wrong, but that's just a simple example.

SQL> create table users
  2    (user_id     number generated always as identity primary key,
  3     username    varchar2(30) unique,
  4     password    varchar2(30)
  5    );

Table created.

Procedure: inserts a row into the table if it doesn't exist, and - if row was inserted - creates user:

SQL> create or replace procedure p_create_user
  2    (p_username in varchar2,
  3     p_password in varchar2
  4    ) as
  5  begin
  6    insert into users (username, password)
  7    select p_username, p_password
  8    from dual
  9    where not exists (select null
 10                      from users u
 11                      where u.username = p_username
 12                     );
 13    if sql%rowcount = 1 then
 14      execute immediate 'create user ' || p_username || ' identified by ' || p_password;
 15    end if;
 16  end;
 17  /

Procedure created.

Let's try it:

SQL> exec p_create_user('littlefoot', 'whatever');

PL/SQL procedure successfully completed.

SQL> select * From users;

   USER_ID USERNAME                       PASSWORD
---------- ------------------------------ ------------------------------
         1 littlefoot                     whatever

Can I insert the same user again? No:

SQL> exec p_create_user('littlefoot', 'whatever');

PL/SQL procedure successfully completed.

SQL> select * From users;

   USER_ID USERNAME                       PASSWORD
---------- ------------------------------ ------------------------------
         1 littlefoot                     whatever

A different user?

SQL> exec p_create_user('bigfoot', 'whatever');

PL/SQL procedure successfully completed.

SQL> select * From users;

   USER_ID USERNAME                       PASSWORD
---------- ------------------------------ ------------------------------
         1 littlefoot                     whatever
         2 bigfoot                        whatever

What if I try to connect as newly created user:

SQL> connect littlefoot/whatever@pdb1
ERROR:
ORA-01045: user LITTLEFOOT lacks CREATE SESSION privilege; logon denied


Warning: You are no longer connected to ORACLE.
SQL>

Apparently, creating user isn't enough. It exists, but can't do anything. I presume you'll handle that later.

huangapple
  • 本文由 发表于 2023年5月21日 00:10:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76296153.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定