For that, I took almost the same code that I used before: SQL Macro script
drop table t;
drop table t1;
drop table t2;
CREATE OR REPLACE FUNCTION sample(t DBMS_TF.Table_t, how_many number DEFAULT 5)
RETURN VARCHAR2 SQL_MACRO
AS
BEGIN
RETURN q'[SELECT *
FROM t
WHERE rownum <= how_many]';
END sample;
/
create table t
as
select n
from xmltable('1 to 10'
columns
n int path '.');
create table t1
as
select n,
'val_'||to_char(n, 'fm00') val
from xmltable('1 to 10'
columns
n int path '.');
create table t2
as
select 'val_'||to_char(n, 'fm00') s
from xmltable('1 to 10'
columns
n int path '.');
select * from t1;
select * from t2;
select *
from sample(t1, 3);
select *
from sample(t1);
select *
from sample(t2);
A query failed when I was trying to supply the table T - which is the same that is used in the SQL macro's definition:
SQL> select *
2 from sample(t);
from sample(t)
*
ERROR at line 2:
ORA-32039: recursive WITH clause must have column alias list
The errorstack dump for ORA-32039 (level=3) did not provide much information about the underlying cause:
----- Error Stack Dump ----- <error barrier> at 0x7ffd69f7aaf0 placed dbkda.c@296 ORA-32039: recursive WITH clause must have column alias list ----- Current SQL Statement for this session (sql_id=d3ktrfsd4s0sr) ----- select * from sample(t)SQL Trace was referring to the same statement:
PARSE ERROR #140320112869816:len=24 dep=0 uid=119 oct=3 lid=119 tim=1054524149653 err=32039 select * from sample(t)It showed the following statement, though:
PARSING IN CURSOR #140320116348624 len=446 dep=1 uid=119 oct=47 lid=119 tim=1054472624364 hv=3547957408 ad='7cda6688' sqlid='9awjhv79rm250' declare t0 DBMS_TF.Table_t := DBMS_TF.Table_t(column => :0); begin :macro_text := "SAMPLE"(t0); end;While studying those qksptfSQM functions, namely: qksptfSQM_GetTxt and qksptfSQM_Template, I found that they are calling to the PTF_Comp UTS component (Polymorphic Table Functions Compilation (qksptf)):
0x000000000f75c87a <+4202>: mov $0x6000,%ecx 0x000000000f75c87f <+4207>: mov $0x205018b,%esi 0x000000000f75c884 <+4212>: mov $0x2,%edx 0x000000000f75c889 <+4217>: mov -0x200(%rbp),%r8 0x000000000f75c890 <+4224>: mov -0xcb58(%rbx),%rdi 0x000000000f75c897 <+4231>: callq 0x485cef0 <dbgtCtrl_intEvalCtrlEvent>Therefore, I enabled PTF_Comp tracing:
alter session set events 'trace[ptf_comp]' tracefile_identifier=ptf_comp;Here is what I got in the trace file:
qksptfSQM_GetTxt(): Anonymous Block
===================================
declare
t0 DBMS_TF.Table_t := DBMS_TF.Table_t(column => :0);
begin
:macro_text := "SAMPLE"(t0);
end;
qksptfSQM_GetTxt(): Macro Text
==============================
SELECT *
FROM t
WHERE rownum <= how_many
qksptfSQM_Template(): Template Text
===================================
with T as (select /*+ INLINE */ * from "MY_USER"."T")
select "SYS__$".*
from (select 5 "HOW_MANY" from SYS.DUAL) "SAMPLE",
lateral(SELECT *
FROM t
WHERE rownum <= how_many) "SYS__$"
Obviously, the ORA-32039 error is absolutely legit in this case and the PTF_Comp tracing clearly shows where the issue is.
It highlights one of the current limitations of that functionality in Oracle 19.6. Beside it demonstrates how literals (HOW_MANY in the example above) are passed through a subquery and joined to a lateral view - that approach has certain restrictions.
Apparently there seem to be more restrictions than that according to $ORACLE_HOME/plsql/mesg/pcmus.msg:
776, 0, "SQL macro can only return character return types" // INDEX: "SQL macro" // RELEASE: 20.1 // CAUSE: A SQL macro function returned a type that was not a character type like VARCHAR2. // ACTION: Change the return type to one of the character types. 777, 0, "scalar SQL macro cannot have argument of type DBMS_TF.TABLE_T" // INDEX: "SQL macro" // RELEASE: 20.1 // CAUSE: DBMS_TF.TABLE_T argument was used for scalar macros. // ACTION: Change the argument type to a type other than // DBMS_TF.TABLE_T. 778, 0, "PARTITION BY, ORDER BY, CLUSTER BY, or PARALLEL_ENABLE are not allowed for SQL macros" // MANUAL: partition by, order by, cluster by, deterministic, authid or parallel_enable // not allowed for SQL macros // INDEX: "SQL macro" // RELEASE: 20.1 // CAUSE: An attempt was made to use the PARTITION BY, ORDER BY, CLUSTER BY, // DETERMINISTIC, AUTHID, or PARALLEL_ENABLE clause in a // SQL macro. // ACTION: Do not specify the PARTITION BY, CLUSTER BY, ORDER BY, DETERMINISTIC, AUTHID, or // PARALLEL_ENABLE clause with a SQL macro. 779, 0, "Formal parameters of type TABLE cannot have a default value." // MANUAL: A default value cannot be specified for parameter of type TABLE. // INDEX: "SQL macros" // RELEASE: 20.1 // CAUSE: A default value was specified for a formal parameter of type TABLE // in a SQL macro declaration. // ACTION: Remove the default value from the parameter of type TABLE in // the SQL macro declaration. // 780, 0, "Formal parameters of type COLUMNS may only have a NULL default value." // MANUAL: Parameters of type COLUMNS can only have a NULL default value. // INDEX: "SQL macros" // RELEASE: 20.1 // CAUSE: A non-NULL default value was specified for a formal parameter of type COLUMNS // in a polymorphic table function. // ACTION: Change the default value for the parameter of type COLUMNS to // have a NULL default value in the polymorphic table function // specification. // // 781, 0, "SQL macro cannot be a type method" // INDEX: "SQL macros" // RELEASE: 20.1 // CAUSE: The SQL macro could not be declared as a method in a type specification. // ACTION: Use the SQL macro as a package function or a top level function. // 782, 0, "A package containing SQL macro cannot be an invoker's rights package." // INDEX: "SQL macros" // RELEASE: 20.1 // CAUSE: A package could not be declared as AUTHID CURRENT_USER if it had a SQL // macro function declared inside. // ACTION: Declare the package as AUTHID DEFINER if it contains one or more // SQL macro functions.Keep in mind that this functionality is not officially released and only a limited subset of it is available in 19.6: Bug 30324180 SQL Macro should be backported to 19.5. Hence, the final version of SQL Macro in Oracle 20 might be different from what we have now in Oracle 19.6.