diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-10-28 22:02:06 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-10-28 22:02:06 +0000 |
commit | e3e3d2a789e34ff6572bdf693beb1516a228c5ff (patch) | |
tree | c5c95ccfe1f4cc79e49c572b13681f628a212fe9 /src/backend/executor/nodeFunctionscan.c | |
parent | a80a12247a99f0bccf47bed5786f28a35fc80845 (diff) | |
download | postgresql-e3e3d2a789e34ff6572bdf693beb1516a228c5ff.tar.gz postgresql-e3e3d2a789e34ff6572bdf693beb1516a228c5ff.zip |
Extend ExecMakeFunctionResult() to support set-returning functions that return
via a tuplestore instead of value-per-call. Refactor a few things to reduce
ensuing code duplication with nodeFunctionscan.c. This represents the
reasonably noncontroversial part of my proposed patch to switch SQL functions
over to returning tuplestores. For the moment, SQL functions still do things
the old way. However, this change enables PL SRFs to be called in targetlists
(observe changes in plperl regression results).
Diffstat (limited to 'src/backend/executor/nodeFunctionscan.c')
-rw-r--r-- | src/backend/executor/nodeFunctionscan.c | 83 |
1 files changed, 6 insertions, 77 deletions
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index 6113a2c9067..8da9fc620a0 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.47 2008/10/01 19:51:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.48 2008/10/28 22:02:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,7 +28,6 @@ static TupleTableSlot *FunctionNext(FunctionScanState *node); -static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc); /* ---------------------------------------------------------------- * Scan Support @@ -62,32 +61,10 @@ FunctionNext(FunctionScanState *node) */ if (tuplestorestate == NULL) { - ExprContext *econtext = node->ss.ps.ps_ExprContext; - TupleDesc funcTupdesc; - node->tuplestorestate = tuplestorestate = ExecMakeTableFunctionResult(node->funcexpr, - econtext, - node->tupdesc, - &funcTupdesc); - - /* - * If function provided a tupdesc, cross-check it. We only really - * need to do this for functions returning RECORD, but might as well - * do it always. - */ - if (funcTupdesc) - { - tupledesc_match(node->tupdesc, funcTupdesc); - - /* - * If it is a dynamically-allocated TupleDesc, free it: it is - * typically allocated in the EState's per-query context, so we - * must avoid leaking it on rescan. - */ - if (funcTupdesc->tdrefcount == -1) - FreeTupleDesc(funcTupdesc); - } + node->ss.ps.ps_ExprContext, + node->tupdesc); } /* @@ -296,9 +273,9 @@ ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt) /* * Here we have a choice whether to drop the tuplestore (and recompute the - * function outputs) or just rescan it. This should depend on whether the - * function expression contains parameters and/or is marked volatile. - * FIXME soon. + * function outputs) or just rescan it. We must recompute if the + * expression contains parameters, else we rescan. XXX maybe we should + * recompute if the function is volatile? */ if (node->ss.ps.chgParam != NULL) { @@ -308,51 +285,3 @@ ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt) else tuplestore_rescan(node->tuplestorestate); } - -/* - * Check that function result tuple type (src_tupdesc) matches or can - * be considered to match what the query expects (dst_tupdesc). If - * they don't match, ereport. - * - * We really only care about number of attributes and data type. - * Also, we can ignore type mismatch on columns that are dropped in the - * destination type, so long as the physical storage matches. This is - * helpful in some cases involving out-of-date cached plans. - */ -static void -tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc) -{ - int i; - - if (dst_tupdesc->natts != src_tupdesc->natts) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("function return row and query-specified return row do not match"), - errdetail("Returned row contains %d attributes, but query expects %d.", - src_tupdesc->natts, dst_tupdesc->natts))); - - for (i = 0; i < dst_tupdesc->natts; i++) - { - Form_pg_attribute dattr = dst_tupdesc->attrs[i]; - Form_pg_attribute sattr = src_tupdesc->attrs[i]; - - if (dattr->atttypid == sattr->atttypid) - continue; /* no worries */ - if (!dattr->attisdropped) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("function return row and query-specified return row do not match"), - errdetail("Returned type %s at ordinal position %d, but query expects %s.", - format_type_be(sattr->atttypid), - i + 1, - format_type_be(dattr->atttypid)))); - - if (dattr->attlen != sattr->attlen || - dattr->attalign != sattr->attalign) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("function return row and query-specified return row do not match"), - errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.", - i + 1))); - } -} |