diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/functions.c | 102 | ||||
-rw-r--r-- | src/backend/executor/nodeFunctionscan.c | 29 |
2 files changed, 49 insertions, 82 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 2ddc614cf7e..d2e101a2d61 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.94 2005/03/29 00:16:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.95 2005/03/31 22:46:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,6 +20,7 @@ #include "commands/trigger.h" #include "executor/executor.h" #include "executor/functions.h" +#include "funcapi.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" #include "parser/parse_type.h" @@ -277,8 +278,8 @@ init_sql_fcache(FmgrInfo *finfo) * form. */ if (haspolyarg || fcache->returnsTuple) - fcache->returnsTuple = check_sql_fn_retval(rettype, - get_typtype(rettype), + fcache->returnsTuple = check_sql_fn_retval(foid, + rettype, queryTree_list, &fcache->junkFilter); @@ -858,7 +859,7 @@ ShutdownSQLFunction(Datum arg) * tuple result), *junkFilter is set to NULL. */ bool -check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, +check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList, JunkFilter **junkFilter) { Query *parse; @@ -866,12 +867,8 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, List *tlist; ListCell *tlistitem; int tlistlen; - Oid typerelid; + char fn_typtype; Oid restype; - Relation reln; - int relnatts; /* physical number of columns in rel */ - int rellogcols; /* # of nondeleted columns in rel */ - int colindex; /* physical column index */ if (junkFilter) *junkFilter = NULL; /* default result */ @@ -922,13 +919,10 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, */ tlistlen = ExecCleanTargetListLength(tlist); - typerelid = typeidTypeRelid(rettype); + fn_typtype = get_typtype(rettype); if (fn_typtype == 'b' || fn_typtype == 'd') { - /* Shouldn't have a typerelid */ - Assert(typerelid == InvalidOid); - /* * For base-type returns, the target list should have exactly one * entry, and its type should agree with what the user declared. @@ -950,10 +944,13 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, errdetail("Actual return type is %s.", format_type_be(restype)))); } - else if (fn_typtype == 'c') + else if (fn_typtype == 'c' || rettype == RECORDOID) { - /* Must have a typerelid */ - Assert(typerelid != InvalidOid); + /* Returns a rowtype */ + TupleDesc tupdesc; + int tupnatts; /* physical number of columns in tuple */ + int tuplogcols; /* # of nondeleted columns in tuple */ + int colindex; /* physical column index */ /* * If the target list is of length 1, and the type of the varnode @@ -969,16 +966,27 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, return false; /* NOT returning whole tuple */ } + /* Is the rowtype fixed, or determined only at runtime? */ + if (get_func_result_type(func_id, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + { + /* + * Assume we are returning the whole tuple. + * Crosschecking against what the caller expects will happen at + * runtime. + */ + if (junkFilter) + *junkFilter = ExecInitJunkFilter(tlist, false, NULL); + return true; + } + Assert(tupdesc); + /* - * Otherwise verify that the targetlist matches the return tuple - * type. This part of the typechecking is a hack. We look up the - * relation that is the declared return type, and scan the - * non-deleted attributes to ensure that they match the datatypes - * of the non-resjunk columns. + * Verify that the targetlist matches the return tuple type. + * We scan the non-deleted attributes to ensure that they match the + * datatypes of the non-resjunk columns. */ - reln = relation_open(typerelid, AccessShareLock); - relnatts = reln->rd_rel->relnatts; - rellogcols = 0; /* we'll count nondeleted cols as we go */ + tupnatts = tupdesc->natts; + tuplogcols = 0; /* we'll count nondeleted cols as we go */ colindex = 0; foreach(tlistitem, tlist) @@ -994,15 +1002,15 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, do { colindex++; - if (colindex > relnatts) + if (colindex > tupnatts) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Final SELECT returns too many columns."))); - attr = reln->rd_att->attrs[colindex - 1]; + attr = tupdesc->attrs[colindex - 1]; } while (attr->attisdropped); - rellogcols++; + tuplogcols++; tletype = exprType((Node *) tle->expr); atttype = attr->atttypid; @@ -1014,19 +1022,19 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, errdetail("Final SELECT returns %s instead of %s at column %d.", format_type_be(tletype), format_type_be(atttype), - rellogcols))); + tuplogcols))); } for (;;) { colindex++; - if (colindex > relnatts) + if (colindex > tupnatts) break; - if (!reln->rd_att->attrs[colindex - 1]->attisdropped) - rellogcols++; + if (!tupdesc->attrs[colindex - 1]->attisdropped) + tuplogcols++; } - if (tlistlen != rellogcols) + if (tlistlen != tuplogcols) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", @@ -1036,40 +1044,12 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, /* Set up junk filter if needed */ if (junkFilter) *junkFilter = ExecInitJunkFilterConversion(tlist, - CreateTupleDescCopy(reln->rd_att), + CreateTupleDescCopy(tupdesc), NULL); - relation_close(reln, AccessShareLock); - /* Report that we are returning entire tuple result */ return true; } - else if (rettype == RECORDOID) - { - /* - * If the target list is of length 1, and the type of the varnode - * in the target list matches the declared return type, this is - * okay. This can happen, for example, where the body of the - * function is 'SELECT func2()', where func2 has the same return - * type as the function that's calling it. - */ - if (tlistlen == 1) - { - restype = ((TargetEntry *) linitial(tlist))->resdom->restype; - if (IsBinaryCoercible(restype, rettype)) - return false; /* NOT returning whole tuple */ - } - - /* - * Otherwise assume we are returning the whole tuple. - * Crosschecking against what the caller expects will happen at - * runtime. - */ - if (junkFilter) - *junkFilter = ExecInitJunkFilter(tlist, false, NULL); - - return true; - } else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID) { /* This should already have been caught ... */ diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index edf5c676352..4cbbb5a65ff 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.31 2005/03/16 21:38:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.32 2005/03/31 22:46:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,18 +22,10 @@ */ #include "postgres.h" -#include "access/heapam.h" -#include "catalog/pg_type.h" -#include "executor/execdebug.h" -#include "executor/execdefs.h" -#include "executor/execdesc.h" #include "executor/nodeFunctionscan.h" +#include "funcapi.h" #include "parser/parsetree.h" -#include "parser/parse_expr.h" -#include "parser/parse_type.h" #include "utils/builtins.h" -#include "utils/lsyscache.h" -#include "utils/typcache.h" static TupleTableSlot *FunctionNext(FunctionScanState *node); @@ -180,18 +172,21 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) */ rte = rt_fetch(node->scan.scanrelid, estate->es_range_table); Assert(rte->rtekind == RTE_FUNCTION); - funcrettype = exprType(rte->funcexpr); /* * Now determine if the function returns a simple or composite type, * and build an appropriate tupdesc. */ - functypclass = get_type_func_class(funcrettype); + functypclass = get_expr_result_type(rte->funcexpr, + &funcrettype, + &tupdesc); if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ - tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(funcrettype, -1)); + Assert(tupdesc); + /* Must copy it out of typcache for safety */ + tupdesc = CreateTupleDescCopy(tupdesc); } else if (functypclass == TYPEFUNC_SCALAR) { @@ -216,14 +211,6 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) elog(ERROR, "function in FROM has unsupported return type"); } - /* - * For RECORD results, make sure a typmod has been assigned. (The - * function should do this for itself, but let's cover things in case - * it doesn't.) - */ - if (tupdesc->tdtypeid == RECORDOID && tupdesc->tdtypmod < 0) - assign_record_type_typmod(tupdesc); - scanstate->tupdesc = tupdesc; ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot, tupdesc, false); |