PL/SQL - execute immediate in pipelined function

dzb picture dzb · Sep 25, 2012 · Viewed 12.8k times · Source

I want to execute dynamic query in my pipelined function and return results of this query. Is it possible to do this? Pipelined function is convenient for me to achieve good interface for my application cause it behaves like a table.

The function:

CREATE OR REPLACE FUNCTION MyFunction(p_schema VARCHAR2) RETURN MyTableType Pipelined IS
v_query VARCHAR2(1000);
BEGIN
  v_query := 'SELECT * FROM TABLE ('||p_schema||'.somepackage.SomeFunction)'; --SomeFunction is another pipelined function
  EXECUTE IMMEDIATE v_query;
  --Results of the v_query are compatible with MyTableType's row type. But how to return them from pipelined function?
END;

Answer

Vincent Malgrat picture Vincent Malgrat · Sep 25, 2012

It is possible to combine dynamic SQL and pipelined function but the return type will not be dynamic: the number and type of columns returned will be fixed.

You can use EXECUTE IMMEDIATE with BULK COLLECT (thanks @be here now), dynamic cursors or DBMS_SQL to return more than one row. Here's an example with a dynamic cursor:

SQL> CREATE OR REPLACE PACKAGE pkg AS
  2     TYPE test_tab IS TABLE OF test%ROWTYPE;
  3     FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED;
  4  END;
  5  /

Package created.

SQL> CREATE OR REPLACE PACKAGE BODY pkg IS
  2     FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED IS
  3        cc sys_refcursor;
  4        l_row test%ROWTYPE;
  5     BEGIN
  6        OPEN cc FOR 'SELECT * FROM test WHERE ' || l_where;
  7        LOOP
  8           FETCH cc INTO l_row;
  9           EXIT WHEN cc%NOTFOUND;
 10           PIPE ROW (l_row);
 11        END LOOP;
 12        RETURN;
 13     END;
 14  END;
 15  /

Package body created.

Let's call this dynamic function:

SQL> SELECT *
  2    FROM TABLE(pkg.dynamic_cursor('id <= 2'));

        ID DAT
---------- ---
         1 xxx
         2 xxx

As always with dynamic SQL, beware of SQL Injection.