Oracle 12c SQL 函数调用未按预期工作

Oracle 12c SQL Function call not working as desired

我在 SQL 中有一个函数可以将用户插入到 USERS 中。当我使用 SELECT insert_users('user', 'email', 'hash') FROM dual; 在 Oracle 12c application express 中调用函数时,它 运行s,但是 returns FAIL 来自异常。 SQL Developer 当 运行ning 这个 SQL 语句时,同样的事情发生在 SQL Developer 中,但是当我 运行 或直接在 SQL Developer 中调试函数时,它成功执行.所以我认为问题出在 SQL 语句中。那么需要改变什么才能使其正常工作?

SQL函数

create or replace FUNCTION insert_users(p_user_name in varchar2, 
    p_user_email in varchar2, p_user_password in varchar2)
RETURN VARCHAR2 AS

    p_salt varchar2(20) := '';
BEGIN
    select dbms_random.string('P', 20) str
    into p_salt
    from dual;
INSERT INTO USERS(USER_ID, USER_NAME, USER_EMAIL, SALT, USER_PASSWORD)
    VALUES (seq_users.nextval, p_user_name, p_user_email, p_salt, p_user_password);
return 'SUCCESS';
EXCEPTION
    WHEN others THEN
    RETURN 'FAIL';
END;

SQL 通话

SELECT insert_users('user', 'email', 'hash') FROM dual;

PL/SQL 块(直接来自 运行ning 函数)

DECLARE
  P_USER_NAME VARCHAR2(200);
  P_USER_EMAIL VARCHAR2(200);
  P_USER_PASSWORD VARCHAR2(200);
  v_Return VARCHAR2(200);
BEGIN
  P_USER_NAME := 'user';
  P_USER_EMAIL := 'email';
  P_USER_PASSWORD := 'hash';

  v_Return := USER.INSERT_USERS(
    P_USER_NAME => P_USER_NAME,
    P_USER_EMAIL => P_USER_EMAIL,
    P_USER_PASSWORD => P_USER_PASSWORD
  );
  :v_Return := v_Return;
--rollback; 
END;

如果您没有压缩异常,您会看到:

ORA-14551: cannot perform a DML operation inside a query

您的函数正在执行 DML - 即插入到您的 table。当来自 PL/SQL 上下文的 运行 没问题时,尽管通常认为最好为此使用一个过程。但是由于您的函数正在执行此操作,因此您不能将其作为查询的一部分进行调用。

Catching and squashing errors is often considered a bug。你所做的一切都隐藏了有用的信息。调用者不知道函数调用失败的原因,调查问题的任何人也不知道发生了什么。

更好的方法是只做一个程序。如果插入工作正常,那很好。如果发生任何类型的错误,让异常传播,客户端或调用者将看到它并知道到底出了什么问题。您不能从查询中调用该过程,但可以从匿名块或匿名块周围的 SQL*Plus 和 SQL 开发人员 execute 包装器中调用它。

create or replace PROCEDURE insert_users(p_user_name in varchar2, 
    p_user_email in varchar2, p_user_password in varchar2) AS
BEGIN
    INSERT INTO USERS(USER_ID, USER_NAME, USER_EMAIL, SALT, USER_PASSWORD)
    VALUES (seq_users.nextval, p_user_name, p_user_email, dbms_random.string('P', 20), p_user_password);
END;
/

Procedure INSERT_USERS compiled

EXEC insert_users('user', 'email', 'hash');

PL/SQL procedure successfully completed.

select * from users;

   USER_ID USER_NAME            USER_EMAIL           SALT                 USER_PASSWORD                                                   
---------- -------------------- -------------------- -------------------- ----------------------------------------------------------------
         1 user                 email                Er-U1zL-v0lP%1m*Tz&t hash                                                            

你真的不需要 p_salt 变量,你可以调用 dbms_random 作为插入的一部分,所以我已经删除了它。

您可能希望在存储密码之前使用盐对密码进行哈希处理...