Solution to "cannot perform a DML operation inside a query"?

You could use the directive pragma autonomous_transaction. This will run the function into an independant transaction that will be able to perform DML without raising the ORA-14551.

Be aware that since the autonomous transaction is independent, the results of the DML will be commited outside of the scope of the parent transaction. In most cases that would not be an acceptable workaround.

SQL> CREATE OR REPLACE FUNCTION supercomplex(datainput IN VARCHAR2)
  2     RETURN VARCHAR2 IS
  3     PRAGMA AUTONOMOUS_TRANSACTION;
  4  BEGIN
  5     INSERT INTO dumtab VALUES (datainput);
  6     COMMIT;
  7     RETURN 'done';
  8  END supercomplex;
  9  /

Function created

SQL> SELECT supercomplex('somevalue') FROM dual;

SUPERCOMPLEX('SOMEVALUE')
--------------------------------------------------------------------------------
done

SQL> select * from dumtab;

A
--------------------------------------------------------------------------------
somevalue

Tom Kyte has a nice explanation about why the error is raised in the first place. It is not safe because it may depend upon the order in which the rows are processed. Furthermore, Oracle doesn't guarantee that the function will be executed at least once and at most once per row.


Just execute the function in a dummy if ... end if; statement to ignore the return value:

exec if supercomplex('somevalue') then null; end if;

Or execute it as a parameter for put_line procedure to output the return value:

exec dbms_ouput ('result of supercomplex='||supercomplex('somevalue'));

result of supercomplex=done

Just declare a variable to accept the return value, for example:

declare
    retvar varchar2(4);
begin
    retvar := supercomplex('somevalue');
end;

The select doesn't work because the function is performing an insert, if all it did was return a value then it would work.