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 |
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? |