Re: Clean-up callbacks for non-SR functions - Mailing list pgsql-hackers

From James William Pye
Subject Re: Clean-up callbacks for non-SR functions
Date
Msg-id 20040520131530.GM62439@void.ph.cox.net
Whole thread Raw
In response to Re: Clean-up callbacks for non-SR functions  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Clean-up callbacks for non-SR functions
List pgsql-hackers
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
root@void:/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

Attachment

pgsql-hackers by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: add server include files to default installation?
Next
From: Tom Lane
Date:
Subject: Re: Clean-up callbacks for non-SR functions