Re: Clean-up callbacks for non-SR functions

From: James William Pye <flaw(at)rhid(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Clean-up callbacks for non-SR functions
Date: 2004-05-20 13:15:30
Message-ID: 20040520131530.GM62439@void.ph.cox.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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(at)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 Content-Type Size
eq.diff text/plain 1.4 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Tom Lane 2004-05-20 14:18:38 Re: Clean-up callbacks for non-SR functions
Previous Message Bruce Momjian 2004-05-20 05:07:14 Re: add server include files to default installation?