1. Function should accept only IN parameters (not OUT, IN OUT).
2. Function should accent and return only valid SQL data types (not PL/SQL specific types like boolean, record and etc.).
3. Parameters must be specified with positional notation (not named notation '=>').
4. User should have a Execute privilege.
The above restrictions are quite simple and I can't add something to it. I would like to create a couple of examples about 'DML' and 'Select' restrictions.
There is an easy test case:
SQL> create table test1 (id number, name varchar2(100)); Table created. SQL> insert into test1 select level, 'name'||level from dual connect by level <= 10; 10 rows created. SQL> commit; Commit complete. SQL> select * from test1; ID NAME ---------- ----------------------------------------- 1 name1 2 name2 3 name3 4 name4 5 name5 6 name6 7 name7 8 name8 9 name9 10 name10 10 rows selected. SQL> create table test2 (id number); Table created. SQL>
1. Functions called from select statement can't contain DML statements.
SQL> create or replace function func_sql_run_test (p_id in test1.id%type) 2 return test1.name%type 3 is 4 v_name test1.name%type; 5 begin 6 insert into test1 (id, name) values (-1,'test'); -- DML 7 return 'test'; 8 end func_sql_run_test; 9 / Function created. SQL> select func_sql_run_test(1) from test1 where id =1; select func_sql_run_test(1) from test1 where id =1 * ERROR at line 1: ORA-14551: cannot perform a DML operation inside a query ORA-06512: at "ORATT.FUNC_SQL_RUN_TEST", line 6 SQL>
2. Functions called from update, delete and insert .. select statement can't query or modify the same table.
2.1. Example 1.
SQL> create or replace function func_sql_run_test (p_id in test1.id%type) 2 return test1.name%type 3 is 4 v_name test1.name%type; 5 begin 6 select name into v_name from test1 where id = p_id; 7 return v_name; 8 end func_sql_run_test; 9 / Function created. SQL> update test1 set name = func_sql_run_test(1) where id = 10; update test1 set name = func_sql_run_test(1) where id = 10 * ERROR at line 1: ORA-04091: table ORATT.TEST1 is mutating, trigger/function may not see it ORA-06512: at "ORATT.FUNC_SQL_RUN_TEST", line 6 SQL> delete from test1 where name = func_sql_run_test(1); delete from test1 where name = func_sql_run_test(1) * ERROR at line 1: ORA-04091: table ORATT.TEST1 is mutating, trigger/function may not see it ORA-06512: at "ORATT.FUNC_SQL_RUN_TEST", line 6 SQL> insert into test1 (id, name) select 11, func_sql_run_test(1) from dual; insert into test1 (id, name) select 11, func_sql_run_test(1) from dual * ERROR at line 1: ORA-04091: table ORATT.TEST1 is mutating, trigger/function may not see it ORA-06512: at "ORATT.FUNC_SQL_RUN_TEST", line 6 SQL> -- insert works fine SQL> insert into test1 (id, name) values (11, func_sql_run_test(1)); 1 row created. SQL> rollback; Rollback complete. SQL>
2.2. Example 2.
SQL> create or replace function func_sql_run_test (p_id in test1.id%type) 2 return test1.name%type 3 is 4 v_name test1.name%type; 5 begin 6 insert into test1 (id, name) values (-1,'test'); -- DML 7 return 'test'; 8 end func_sql_run_test; 9 / Function created. SQL> update test1 set name = func_sql_run_test(1) where id = 10; update test1 set name = func_sql_run_test(1) where id = 10 * ERROR at line 1: ORA-04091: table ORATT.TEST1 is mutating, trigger/function may not see it ORA-06512: at "ORATT.FUNC_SQL_RUN_TEST", line 6 SQL> delete from test1 where name = func_sql_run_test(1); delete from test1 where name = func_sql_run_test(1) * ERROR at line 1: ORA-04091: table ORATT.TEST1 is mutating, trigger/function may not see it ORA-06512: at "ORATT.FUNC_SQL_RUN_TEST", line 6 SQL> insert into test1 (id, name) select 11, func_sql_run_test(1) from dual; insert into test1 (id, name) select 11, func_sql_run_test(1) from dual * ERROR at line 1: ORA-04091: table ORATT.TEST1 is mutating, trigger/function may not see it ORA-06512: at "ORATT.FUNC_SQL_RUN_TEST", line 6 SQL> -- insert works fine SQL> insert into test1 (id, name) values (11, func_sql_run_test(1)); 1 row created. SQL> rollback; Rollback complete. SQL>
If I change the table name in DML statement, the function can be invoked through DML.
SQL> create or replace function func_sql_run_test (p_id in test1.id%type) 2 return test1.name%type 3 is 4 v_name test1.name%type; 5 begin 6 insert into test2 (id) values (-1); 7 return 'test'; 8 end func_sql_run_test; 9 / Function created. SQL> update test1 t set name = func_sql_run_test(1) where id = 10; 1 row updated. SQL> select * from test2; ID ---------- -1 SQL> delete from test1 where name = func_sql_run_test(1); 1 row deleted. SQL> rollback; Rollback complete. SQL> insert into test1 (id, name) select 11, func_sql_run_test(1) from dual; 1 row created. SQL> insert into test1 (id, name) values (11, func_sql_run_test(1)); 1 row created. SQL> rollback; Rollback complete.Additionally, there are some additional restrictions related with transactions (commit, rollback, DDL,DCL and etc.) Of course, all these restrictions are obvious, but I still decided to write about it because it's quite important and I can use this post as a hint :).