On 05/18/04:20/2, Tom Lane wrote:
> Hm?  That functionality works for any function, whether it returns a set
> or not.

Okay, then I think I found a bug:

SELECT * FROM aFunction();
Gives fcinfo->resultinfo != NULL, regardless of the type of return.

SELECT aFunction();
Gives fcinfo->resultinfo != NULL, ONLY IF it is a SRF.(fn_retset != 0)

I think the culprit is in the function ExecMakeFunctionResult in file execQual.c, line 
~1230: 

:e execQual.c
/retset
.......
        /*
         * If function returns set, prepare a resultinfo node for
         * communication
         */
        if (fcache->func.fn_retset)
        {
                fcinfo.resultinfo = (Node *) &rsinfo;
........


And to be nagging:
Utility functions like OidFunctionCall# don't setup resultinfo,
and probably rightfully so in some regards, but ISTM that there should be a
mechanism that is independent of the executor. Maybe an explicit requirement to
call a "FunctionCallCleanup(fcinfo)", or, dare I say, free hooks on
pointers?  :)


I attached a simple patch that seems to make it work, but I'm not sure if there
will be any unwanted side effects, as I'm barely familiar with the executor....


Here's a bunch of data that I collected, probably not very enlightening after
the preceding summary(Discovered the pattern after gathering all this data)..

-----------------------

uname -a
FreeBSD void 4.10-PRERELEASE FreeBSD 4.10-PRERELEASE #5: Wed Apr 28 06:12:01 MST 2004
[EMAIL PROTECTED]:/files/src/freebsd/RELENG_4/sys/compile/void  i386

backend> SELECT version();
1: version = "PostgreSQL 7.4.1 on i386-portbld-freebsd4.9, compiled by GCC 2.95.4"


All this data is retrieved as soon as it hits my handler:

--------------------------------------------
Regular function:
--------------------------------------------
CREATE FUNCTION count()
RETURNS numeric LANGUAGE plpy
AS '
i = 0L
while True:
        i += 1
        yield i
';

backend> SELECT count(), * FROM someTable;
Breakpoint 1, pl_handler (fcinfo=0xbfbff154) at src/pl.c:468

(gdb) print *fcinfo
$2 = {
        flinfo = 0x841d234,
        context = 0x0,
        resultinfo = 0x0, <---------------------- :(
        isnull = 0 '\000',
        nargs = 0,
        arg = {0 <repeats 32 times>},
        argnull = '\000' <repeats 31 times>
}

(gdb) print *fcinfo->flinfo
$4 = {
        fn_addr = 0x285dc118 <pl_handler>,
        fn_oid = 554021,
        fn_nargs = 0,
        fn_strict = 0 '\000',
        fn_retset = 0 '\000',
        fn_extra = 0x0,
        fn_mcxt = 0x82ab858,
        fn_expr = 0x8422838
}

(gdb) bt
#0  pl_handler (fcinfo=0xbfbff154) at src/pl.c:468
#1  0x80f116e in ExecMakeFunctionResult () <---------------
#2  0x80f177a in ExecMakeTableFunctionResult ()
#3  0x80f2911 in ExecEvalExpr ()
#4  0x80f34d4 in ExecCleanTargetListLength ()
#5  0x80f36d2 in ExecProject ()
#6  0x80f37ac in ExecScan ()
#7  0x80fa432 in ExecSeqScan ()
#8  0x80efd11 in ExecProcNode ()
#9  0x80eea48 in ExecEndPlan ()
#10 0x80edff4 in ExecutorRun ()
#11 0x8153d56 in PortalRun ()
#12 0x8153c56 in PortalRun ()
#13 0x8150d87 in pg_plan_queries ()
#14 0x815310f in PostgresMain ()
#15 0x8107096 in main ()
#16 0x806d772 in _start ()


I also tried a simpler SELECT count();, it gave a NULL resultinfo as well.


backend> SELECT * FROM count(); -- gives a not null resultinfo, and puts me:
#0  pl_handler (fcinfo=0xbfbff1f4) at src/pl.c:468
#1  0x80f13a3 in ExecMakeTableFunctionResult ()
#2  0x80f9d47 in ExecReScanNestLoop ()
#3  0x80f3758 in ExecScan ()
#4  0x80f9e0a in ExecFunctionScan ()
#5  0x80efd51 in ExecProcNode ()
#6  0x80eea48 in ExecEndPlan ()
#7  0x80edff4 in ExecutorRun ()
#8  0x8153d56 in PortalRun ()
#9  0x8153c56 in PortalRun ()
#10 0x8150d87 in pg_plan_queries ()
#11 0x815310f in PostgresMain ()
#12 0x8107096 in main ()
#13 0x806d772 in _start ()


--------------------------------------------------
Composite type returning, on the other hand:
--------------------------------------------------

CREATE FUNCTION Composite()
RETURNS someTable LANGUAGE plpy
AS 'return [0L]';

backend> SELECT * FROM Composite();
Breakpoint 1, pl_handler (fcinfo=0xbfbff1f4) at src/pl.c:468

(gdb) print *fcinfo
$5 = {
        flinfo = 0x841d31c,
        context = 0x0,
        resultinfo = 0xbfbff1d4,
        isnull = 0 '\000',
        nargs = 0,
        arg = {0 <repeats 32 times>},
        argnull = '\000' <repeats 31 times>
}

(gdb) print *fcinfo->flinfo
$6 = {
        fn_addr = 0x285dc118 <pl_handler>,
        fn_oid = 554025,
        fn_nargs = 0,
        fn_strict = 0 '\000',
        fn_retset = 0 '\000',
        fn_extra = 0x0,
        fn_mcxt = 0x82ab858,
        fn_expr = 0x8313a60
}

(gdb) print *((ReturnSetInfo *)fcinfo->resultinfo)
$8 = {
        type = T_ReturnSetInfo,
        econtext = 0x841d1b0,
        expectedDesc = 0x841d258,
        allowedModes = 3,
        returnMode = SFRM_ValuePerCall,
        isDone = ExprSingleResult,
        setResult = 0x0,
        setDesc = 0x0
}

(gdb) bt
#0  pl_handler (fcinfo=0xbfbff1f4) at src/pl.c:468
#1  0x80f13a3 in ExecMakeTableFunctionResult ()
#2  0x80f9d47 in ExecReScanNestLoop ()
#3  0x80f3758 in ExecScan ()
#4  0x80f9e0a in ExecFunctionScan ()
#5  0x80efd51 in ExecProcNode ()
#6  0x80eea48 in ExecEndPlan ()
#7  0x80edff4 in ExecutorRun ()
#8  0x8153d56 in PortalRun ()
#9  0x8153c56 in PortalRun ()
#10 0x8150d87 in pg_plan_queries ()
#11 0x815310f in PostgresMain ()
#12 0x8107096 in main ()
#13 0x806d772 in _start ()

NOTE: If I SELECT Composite(); resultinfo is NULL..

--------------------------------------------------
And finally, an actual SRF:
--------------------------------------------------

CREATE FUNCTION SRF()
RETURNS SETOF someTable LANGUAGE plpy
AS 'return [[0L]]';

backend> SELECT * FROM SRF();
Breakpoint 1, pl_handler (fcinfo=0xbfbff1f4) at src/pl.c:468

(gdb) print *fcinfo
$11 = {
        flinfo = 0x842631c,
        context = 0x0,
        resultinfo = 0xbfbff1d4,
        isnull = 0 '\000',
        nargs = 0,
        arg = {0 <repeats 32 times>},
        argnull = '\000' <repeats 31 times>
}

(gdb) print *fcinfo->flinfo
$12 = {
        fn_addr = 0x285dc118 <pl_handler>,
        fn_oid = 554026,
        fn_nargs = 0,
        fn_strict = 0 '\000',
        fn_retset = 1 '\001',
        fn_extra = 0x0,
        fn_mcxt = 0x82ab858,
        fn_expr = 0x8313a60
}

(gdb) print *((ReturnSetInfo *)fcinfo->resultinfo)
$13 = {
        type = T_ReturnSetInfo,
        econtext = 0x84261b0,
        expectedDesc = 0x8426258,
        allowedModes = 3,
        returnMode = SFRM_ValuePerCall,
        isDone = ExprSingleResult,
        setResult = 0x0,
        setDesc = 0x0
}

(gdb) bt
#0  pl_handler (fcinfo=0xbfbff1f4) at src/pl.c:468
#1  0x80f13a3 in ExecMakeTableFunctionResult ()
#2  0x80f9d47 in ExecReScanNestLoop ()
#3  0x80f3758 in ExecScan ()
#4  0x80f9e0a in ExecFunctionScan ()
#5  0x80efd51 in ExecProcNode ()
#6  0x80eea48 in ExecEndPlan ()
#7  0x80edff4 in ExecutorRun ()
#8  0x8153d56 in PortalRun ()
#9  0x8153c56 in PortalRun ()
#10 0x8150d87 in pg_plan_queries ()
#11 0x815310f in PostgresMain ()
#12 0x8107096 in main ()
#13 0x806d772 in _start ()


Probably more info than you need/want, but gdb is fun, so here's lots! 8)

Regards,
        James William Pye
Index: execQual.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/executor/execQual.c,v
retrieving revision 1.159
diff -u -r1.159 execQual.c
--- execQual.c  10 May 2004 22:44:43 -0000      1.159
+++ execQual.c  20 May 2004 11:28:20 -0000
@@ -894,21 +894,20 @@
        }
 
        /*
-        * If function returns set, prepare a resultinfo node for
-        * communication
+        * Prepare a resultinfo node for communication.  We always do this
+        * even if not expecting a set result, so that we can pass
+        * expectedDesc.  In the generic-expression case, the expression
+        * doesn't actually get to see the resultinfo, but set it up anyway
+        * because we use some of the fields as our own state variables.
         */
-       if (fcache->func.fn_retset)
-       {
-               fcinfo.resultinfo = (Node *) &rsinfo;
-               rsinfo.type = T_ReturnSetInfo;
-               rsinfo.econtext = econtext;
-               rsinfo.expectedDesc = NULL;
-               rsinfo.allowedModes = (int) SFRM_ValuePerCall;
-               rsinfo.returnMode = SFRM_ValuePerCall;
-               /* isDone is filled below */
-               rsinfo.setResult = NULL;
-               rsinfo.setDesc = NULL;
-       }
+       fcinfo.resultinfo = (Node *) &rsinfo;
+       rsinfo.type = T_ReturnSetInfo;
+       rsinfo.econtext = econtext;
+       rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize);
+       rsinfo.returnMode = SFRM_ValuePerCall;
+       /* isDone is filled below */
+       rsinfo.setResult = NULL;
+       rsinfo.setDesc = NULL;
 
        /*
         * now return the value gotten by calling the function manager,

Attachment: pgpBPHh9Vf1HP.pgp
Description: PGP signature

Reply via email to