diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/common/tupdesc.c | 53 | ||||
-rw-r--r-- | src/backend/catalog/dependency.c | 83 | ||||
-rw-r--r-- | src/backend/executor/nodeFunctionscan.c | 6 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 5 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 5 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 7 | ||||
-rw-r--r-- | src/backend/nodes/readfuncs.c | 45 | ||||
-rw-r--r-- | src/backend/parser/parse_clause.c | 24 | ||||
-rw-r--r-- | src/backend/parser/parse_relation.c | 63 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 81 | ||||
-rw-r--r-- | src/include/access/tupdesc.h | 4 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 4 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 14 |
13 files changed, 249 insertions, 145 deletions
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 8726797524b..020011966f0 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.115 2006/03/14 22:48:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.116 2006/03/16 00:31:54 tgl Exp $ * * NOTES * some of the executor utility code such as "ExecTypeFromTL" should be @@ -554,3 +554,54 @@ BuildDescForRelation(List *schema) return desc; } + +/* + * BuildDescFromLists + * + * Build a TupleDesc given lists of column names (as String nodes), + * column type OIDs, and column typmods. No constraints are generated. + * + * This is essentially a cut-down version of BuildDescForRelation for use + * with functions returning RECORD. + */ +TupleDesc +BuildDescFromLists(List *names, List *types, List *typmods) +{ + int natts; + AttrNumber attnum; + ListCell *l1; + ListCell *l2; + ListCell *l3; + TupleDesc desc; + + natts = list_length(names); + Assert(natts == list_length(types)); + Assert(natts == list_length(typmods)); + + /* + * allocate a new tuple descriptor + */ + desc = CreateTemplateTupleDesc(natts, false); + + attnum = 0; + + l2 = list_head(types); + l3 = list_head(typmods); + foreach(l1, names) + { + char *attname = strVal(lfirst(l1)); + Oid atttypid; + int32 atttypmod; + + atttypid = lfirst_oid(l2); + l2 = lnext(l2); + atttypmod = lfirst_int(l3); + l3 = lnext(l3); + + attnum++; + + TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0); + } + + return desc; +} diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 4ed850f1a5b..160647aed72 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.50 2006/03/05 15:58:22 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.51 2006/03/16 00:31:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -850,11 +850,6 @@ doDeletion(const ObjectAddress *object) * * rtable is the rangetable to be used to interpret Vars with varlevelsup=0. * It can be NIL if no such variables are expected. - * - * XXX is it important to create dependencies on the datatypes mentioned in - * the expression? In most cases this would be redundant (eg, a ref to an - * operator indirectly references its input and output datatypes), but I'm - * not quite convinced there are no cases where we need it. */ void recordDependencyOnExpr(const ObjectAddress *depender, @@ -975,6 +970,13 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender, * To do so, we do not scan the joinaliasvars list of a join RTE while * scanning the query rangetable, but instead scan each individual entry * of the alias list when we find a reference to it. + * + * Note: in many cases we do not need to create dependencies on the datatypes + * involved in an expression, because we'll have an indirect dependency via + * some other object. For instance Var nodes depend on a column which depends + * on the datatype, and OpExpr nodes depend on the operator which depends on + * the datatype. However we do need a type dependency if there is no such + * indirect dependency, as for example in Const and CoerceToDomain nodes. */ static bool find_expr_references_walker(Node *node, @@ -1033,6 +1035,10 @@ find_expr_references_walker(Node *node, Const *con = (Const *) node; Oid objoid; + /* A constant must depend on the constant's datatype */ + add_object_address(OCLASS_TYPE, con->consttype, 0, + &context->addrs); + /* * If it's a regclass or similar literal referring to an existing * object, add a reference to that object. (Currently, only the @@ -1081,6 +1087,14 @@ find_expr_references_walker(Node *node, } return false; } + if (IsA(node, Param)) + { + Param *param = (Param *) node; + + /* A parameter must depend on the parameter's datatype */ + add_object_address(OCLASS_TYPE, param->paramtype, 0, + &context->addrs); + } if (IsA(node, FuncExpr)) { FuncExpr *funcexpr = (FuncExpr *) node; @@ -1134,6 +1148,29 @@ find_expr_references_walker(Node *node, /* Extra work needed here if we ever need this case */ elog(ERROR, "already-planned subqueries not supported"); } + if (IsA(node, RelabelType)) + { + RelabelType *relab = (RelabelType *) node; + + /* since there is no function dependency, need to depend on type */ + add_object_address(OCLASS_TYPE, relab->resulttype, 0, + &context->addrs); + } + if (IsA(node, ConvertRowtypeExpr)) + { + ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node; + + /* since there is no function dependency, need to depend on type */ + add_object_address(OCLASS_TYPE, cvt->resulttype, 0, + &context->addrs); + } + if (IsA(node, RowExpr)) + { + RowExpr *rowexpr = (RowExpr *) node; + + add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0, + &context->addrs); + } if (IsA(node, RowCompareExpr)) { RowCompareExpr *rcexpr = (RowCompareExpr *) node; @@ -1151,6 +1188,13 @@ find_expr_references_walker(Node *node, } /* fall through to examine arguments */ } + if (IsA(node, CoerceToDomain)) + { + CoerceToDomain *cd = (CoerceToDomain *) node; + + add_object_address(OCLASS_TYPE, cd->resulttype, 0, + &context->addrs); + } if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ @@ -1160,17 +1204,32 @@ find_expr_references_walker(Node *node, /* * Add whole-relation refs for each plain relation mentioned in the - * subquery's rtable. (Note: query_tree_walker takes care of - * recursing into RTE_FUNCTION and RTE_SUBQUERY RTEs, so no need to do - * that here. But keep it from looking at join alias lists.) + * subquery's rtable, as well as datatype refs for any datatypes used + * as a RECORD function's output. (Note: query_tree_walker takes care + * of recursing into RTE_FUNCTION and RTE_SUBQUERY RTEs, so no need to + * do that here. But keep it from looking at join alias lists.) */ foreach(rtable, query->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtable); + ListCell *ct; - if (rte->rtekind == RTE_RELATION) - add_object_address(OCLASS_CLASS, rte->relid, 0, - &context->addrs); + switch (rte->rtekind) + { + case RTE_RELATION: + add_object_address(OCLASS_CLASS, rte->relid, 0, + &context->addrs); + break; + case RTE_FUNCTION: + foreach(ct, rte->funccoltypes) + { + add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0, + &context->addrs); + } + break; + default: + break; + } } /* Examine substructure of query */ diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index 45cbc6c1fcb..494ac209a92 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.37 2006/03/05 15:58:26 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.38 2006/03/16 00:31:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -202,7 +202,9 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) } else if (functypclass == TYPEFUNC_RECORD) { - tupdesc = BuildDescForRelation(rte->coldeflist); + tupdesc = BuildDescFromLists(rte->eref->colnames, + rte->funccoltypes, + rte->funccoltypmods); } else { diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index b38efcdec8b..0a0e5f40b0b 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.330 2006/03/14 22:48:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.331 2006/03/16 00:31:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1355,7 +1355,8 @@ _copyRangeTblEntry(RangeTblEntry *from) COPY_SCALAR_FIELD(relid); COPY_NODE_FIELD(subquery); COPY_NODE_FIELD(funcexpr); - COPY_NODE_FIELD(coldeflist); + COPY_NODE_FIELD(funccoltypes); + COPY_NODE_FIELD(funccoltypmods); COPY_SCALAR_FIELD(jointype); COPY_NODE_FIELD(joinaliasvars); COPY_NODE_FIELD(alias); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 0275b01c28e..9696925c2f3 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.266 2006/03/14 22:48:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.267 2006/03/16 00:31:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1730,7 +1730,8 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b) COMPARE_SCALAR_FIELD(relid); COMPARE_NODE_FIELD(subquery); COMPARE_NODE_FIELD(funcexpr); - COMPARE_NODE_FIELD(coldeflist); + COMPARE_NODE_FIELD(funccoltypes); + COMPARE_NODE_FIELD(funccoltypmods); COMPARE_SCALAR_FIELD(jointype); COMPARE_NODE_FIELD(joinaliasvars); COMPARE_NODE_FIELD(alias); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index ef87fedbc21..70e48c071b3 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.270 2006/03/14 22:48:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.271 2006/03/16 00:31:54 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -1450,7 +1450,7 @@ _outTypeName(StringInfo str, TypeName *node) WRITE_BOOL_FIELD(pct_type); WRITE_INT_FIELD(typmod); WRITE_NODE_FIELD(arrayBounds); - /* location is deliberately not stored */ + WRITE_INT_FIELD(location); } static void @@ -1580,7 +1580,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node) break; case RTE_FUNCTION: WRITE_NODE_FIELD(funcexpr); - WRITE_NODE_FIELD(coldeflist); + WRITE_NODE_FIELD(funccoltypes); + WRITE_NODE_FIELD(funccoltypmods); break; case RTE_JOIN: WRITE_ENUM_FIELD(jointype, JoinType); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index c7490a9567c..4e762d3a2ec 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.186 2006/03/14 22:48:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.187 2006/03/16 00:31:55 tgl Exp $ * * NOTES * Path and Plan nodes do not have any readfuncs support, because we @@ -863,42 +863,6 @@ _readFromExpr(void) * Stuff from parsenodes.h. */ -static ColumnDef * -_readColumnDef(void) -{ - READ_LOCALS(ColumnDef); - - READ_STRING_FIELD(colname); - READ_NODE_FIELD(typename); - READ_INT_FIELD(inhcount); - READ_BOOL_FIELD(is_local); - READ_BOOL_FIELD(is_not_null); - READ_NODE_FIELD(raw_default); - READ_STRING_FIELD(cooked_default); - READ_NODE_FIELD(constraints); - READ_NODE_FIELD(support); - - READ_DONE(); -} - -static TypeName * -_readTypeName(void) -{ - READ_LOCALS(TypeName); - - READ_NODE_FIELD(names); - READ_OID_FIELD(typeid); - READ_BOOL_FIELD(timezone); - READ_BOOL_FIELD(setof); - READ_BOOL_FIELD(pct_type); - READ_INT_FIELD(typmod); - READ_NODE_FIELD(arrayBounds); - /* location is deliberately not stored */ - local_node->location = -1; - - READ_DONE(); -} - /* * _readRangeTblEntry */ @@ -923,7 +887,8 @@ _readRangeTblEntry(void) break; case RTE_FUNCTION: READ_NODE_FIELD(funcexpr); - READ_NODE_FIELD(coldeflist); + READ_NODE_FIELD(funccoltypes); + READ_NODE_FIELD(funccoltypmods); break; case RTE_JOIN: READ_ENUM_FIELD(jointype, JoinType); @@ -1042,10 +1007,6 @@ parseNodeString(void) return_value = _readJoinExpr(); else if (MATCH("FROMEXPR", 8)) return_value = _readFromExpr(); - else if (MATCH("COLUMNDEF", 9)) - return_value = _readColumnDef(); - else if (MATCH("TYPENAME", 8)) - return_value = _readTypeName(); else if (MATCH("RTE", 3)) return_value = _readRangeTblEntry(); else if (MATCH("NOTIFY", 6)) diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 4384a4eaab8..9bdb91b4744 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.148 2006/03/14 22:48:20 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.149 2006/03/16 00:31:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -537,23 +537,27 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r) } /* - * If a coldeflist is supplied, ensure it defines a legal set of names (no - * duplicates) and datatypes (no pseudo-types, for instance). + * OK, build an RTE for the function. + */ + rte = addRangeTableEntryForFunction(pstate, funcname, funcexpr, + r, true); + + /* + * If a coldeflist was supplied, ensure it defines a legal set of names + * (no duplicates) and datatypes (no pseudo-types, for instance). + * addRangeTableEntryForFunction looked up the type names but didn't + * check them further than that. */ if (r->coldeflist) { TupleDesc tupdesc; - tupdesc = BuildDescForRelation(r->coldeflist); + tupdesc = BuildDescFromLists(rte->eref->colnames, + rte->funccoltypes, + rte->funccoltypmods); CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE); } - /* - * OK, build an RTE for the function. - */ - rte = addRangeTableEntryForFunction(pstate, funcname, funcexpr, - r, true); - return rte; } diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index d0f78b119cd..e8e11ad167a 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.120 2006/03/14 22:48:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.121 2006/03/16 00:31:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -835,7 +835,8 @@ addRangeTableEntryForFunction(ParseState *pstate, rte->relid = InvalidOid; rte->subquery = NULL; rte->funcexpr = funcexpr; - rte->coldeflist = coldeflist; + rte->funccoltypes = NIL; + rte->funccoltypmods = NIL; rte->alias = alias; eref = makeAlias(alias ? alias->aliasname : funcname, NIL); @@ -883,14 +884,28 @@ addRangeTableEntryForFunction(ParseState *pstate, { ListCell *col; - /* Use the column definition list to form the alias list */ + /* + * Use the column definition list to form the alias list and + * funccoltypes/funccoltypmods lists. + */ foreach(col, coldeflist) { - ColumnDef *n = lfirst(col); + ColumnDef *n = (ColumnDef *) lfirst(col); char *attrname; + Oid attrtype; + int32 attrtypmod; attrname = pstrdup(n->colname); + if (n->typename->setof) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("column \"%s\" cannot be declared SETOF", + attrname))); eref->colnames = lappend(eref->colnames, makeString(attrname)); + attrtype = typenameTypeId(pstate, n->typename); + attrtypmod = n->typename->typmod; + rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype); + rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod); } } else @@ -1181,36 +1196,26 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, } else if (functypclass == TYPEFUNC_RECORD) { - List *coldeflist = rte->coldeflist; - ListCell *col; - int attnum = 0; - - foreach(col, coldeflist) + if (colnames) + *colnames = copyObject(rte->eref->colnames); + if (colvars) { - ColumnDef *colDef = lfirst(col); + ListCell *l1; + ListCell *l2; + int attnum = 0; - attnum++; - if (colnames) - { - char *attrname; - - attrname = pstrdup(colDef->colname); - *colnames = lappend(*colnames, makeString(attrname)); - } - - if (colvars) + forboth(l1, rte->funccoltypes, l2, rte->funccoltypmods) { + Oid attrtype = lfirst_oid(l1); + int32 attrtypmod = lfirst_int(l2); Var *varnode; - Oid atttypid; - - atttypid = typenameTypeId(NULL, colDef->typename); + attnum++; varnode = makeVar(rtindex, attnum, - atttypid, - colDef->typename->typmod, + attrtype, + attrtypmod, sublevels_up); - *colvars = lappend(*colvars, varnode); } } @@ -1548,10 +1553,8 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, } else if (functypclass == TYPEFUNC_RECORD) { - ColumnDef *colDef = list_nth(rte->coldeflist, attnum - 1); - - *vartype = typenameTypeId(NULL, colDef->typename); - *vartypmod = colDef->typename->typmod; + *vartype = list_nth_oid(rte->funccoltypes, attnum - 1); + *vartypmod = list_nth_int(rte->funccoltypmods, attnum - 1); } else { diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9942bcc291b..714140e0617 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -2,7 +2,7 @@ * ruleutils.c - Functions to convert stored expressions/querytrees * back to source text * - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.216 2006/03/14 22:48:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.217 2006/03/16 00:31:55 tgl Exp $ **********************************************************************/ #include "postgres.h" @@ -176,7 +176,7 @@ static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context); static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte, deparse_context *context); -static void get_from_clause_coldeflist(List *coldeflist, +static void get_from_clause_coldeflist(List *names, List *types, List *typmods, deparse_context *context); static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf); @@ -1497,13 +1497,16 @@ deparse_context_for_subplan(const char *name, List *tlist, /* * We create an RTE_SPECIAL RangeTblEntry, and store the given tlist - * in its coldeflist field. This is a hack to make the tlist available + * in its funccoltypes field. This is a hack to make the tlist available * to get_name_for_var_field(). RTE_SPECIAL nodes shouldn't appear in * deparse contexts otherwise. + * + * XXX this desperately needs redesign, as it fails to handle cases where + * we need to drill down through multiple tlists. */ rte->rtekind = RTE_SPECIAL; rte->relid = InvalidOid; - rte->coldeflist = tlist; + rte->funccoltypes = tlist; rte->eref = makeAlias(name, attrs); rte->inh = false; rte->inFromCl = true; @@ -2678,9 +2681,9 @@ get_name_for_var_field(Var *var, int fieldno, * Look into the subplan's target list to get the referenced * expression, and then pass it to get_expr_result_type(). */ - if (rte->coldeflist) + if (rte->funccoltypes) { - TargetEntry *ste = get_tle_by_resno(rte->coldeflist, attnum); + TargetEntry *ste = get_tle_by_resno(rte->funccoltypes, attnum); if (ste != NULL) expr = (Node *) ste->expr; @@ -4205,7 +4208,6 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) { int varno = ((RangeTblRef *) jtnode)->rtindex; RangeTblEntry *rte = rt_fetch(varno, query->rtable); - List *coldeflist = NIL; bool gavealias = false; switch (rte->rtekind) @@ -4226,8 +4228,6 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) case RTE_FUNCTION: /* Function RTE */ get_rule_expr(rte->funcexpr, context, true); - /* might need to emit column list for RECORD function */ - coldeflist = rte->coldeflist; break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); @@ -4265,27 +4265,37 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) gavealias = true; } - if (coldeflist != NIL) + if (rte->rtekind == RTE_FUNCTION) { - if (!gavealias) - appendStringInfo(buf, " AS "); - get_from_clause_coldeflist(coldeflist, context); + if (rte->funccoltypes != NIL) + { + /* Function returning RECORD, reconstruct the columndefs */ + if (!gavealias) + appendStringInfo(buf, " AS "); + get_from_clause_coldeflist(rte->eref->colnames, + rte->funccoltypes, + rte->funccoltypmods, + context); + } + else + { + /* + * For a function RTE, always emit a complete column alias + * list; this is to protect against possible instability of + * the default column names (eg, from altering parameter + * names). + */ + get_from_clause_alias(rte->eref, rte, context); + } } else { /* - * For a function RTE, always emit a complete column alias list; - * this is to protect against possible instability of the default - * column names (eg, from altering parameter names). Otherwise - * just report whatever the user originally gave as column - * aliases. + * For non-function RTEs, just report whatever the user originally + * gave as column aliases. */ - if (rte->rtekind == RTE_FUNCTION) - get_from_clause_alias(rte->eref, rte, context); - else - get_from_clause_alias(rte->alias, rte, context); + get_from_clause_alias(rte->alias, rte, context); } - } else if (IsA(jtnode, JoinExpr)) { @@ -4463,30 +4473,35 @@ get_from_clause_alias(Alias *alias, RangeTblEntry *rte, * responsible for ensuring that an alias or AS is present before it. */ static void -get_from_clause_coldeflist(List *coldeflist, deparse_context *context) +get_from_clause_coldeflist(List *names, List *types, List *typmods, + deparse_context *context) { StringInfo buf = context->buf; - ListCell *col; + ListCell *l1; + ListCell *l2; + ListCell *l3; int i = 0; appendStringInfoChar(buf, '('); - foreach(col, coldeflist) + l2 = list_head(types); + l3 = list_head(typmods); + foreach(l1, names) { - ColumnDef *n = lfirst(col); - char *attname; - Oid atttypeid; + char *attname = strVal(lfirst(l1)); + Oid atttypid; int32 atttypmod; - attname = n->colname; - atttypeid = typenameTypeId(NULL, n->typename); - atttypmod = n->typename->typmod; + atttypid = lfirst_oid(l2); + l2 = lnext(l2); + atttypmod = lfirst_int(l3); + l3 = lnext(l3); if (i > 0) appendStringInfo(buf, ", "); appendStringInfo(buf, "%s %s", quote_identifier(attname), - format_type_with_typemod(atttypeid, atttypmod)); + format_type_with_typemod(atttypid, atttypmod)); i++; } diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 1a5e23e1d1b..670ef5c92e0 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/tupdesc.h,v 1.48 2006/03/05 15:58:53 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/tupdesc.h,v 1.49 2006/03/16 00:31:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -92,4 +92,6 @@ extern void TupleDescInitEntry(TupleDesc desc, extern TupleDesc BuildDescForRelation(List *schema); +extern TupleDesc BuildDescFromLists(List *names, List *types, List *typmods); + #endif /* TUPDESC_H */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 4b541531f84..2ae52c723fc 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.320 2006/03/10 20:15:26 neilc Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.321 2006/03/16 00:31:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200603101 +#define CATALOG_VERSION_NO 200603151 #endif diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 0e7d5bf9f51..aea32d236d9 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.304 2006/03/14 22:48:22 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.305 2006/03/16 00:31:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -362,8 +362,8 @@ typedef struct RangeFunction NodeTag type; Node *funccallnode; /* untransformed function call tree */ Alias *alias; /* table alias & optional column aliases */ - List *coldeflist; /* list of ColumnDef nodes for runtime - * assignment of RECORD TupleDesc */ + List *coldeflist; /* list of ColumnDef nodes to describe + * result of function returning RECORD */ } RangeFunction; /* @@ -547,10 +547,14 @@ typedef struct RangeTblEntry /* * Fields valid for a function RTE (else NULL): + * + * If the function returns RECORD, funccoltypes lists the column types + * declared in the RTE's column type specification, and funccoltypmods + * lists their declared typmods. Otherwise, both fields are NIL. */ Node *funcexpr; /* expression tree for func call */ - List *coldeflist; /* list of ColumnDef nodes for runtime - * assignment of RECORD TupleDesc */ + List *funccoltypes; /* OID list of column type OIDs */ + List *funccoltypmods; /* integer list of column typmods */ /* * Fields valid for a join RTE (else NULL/zero): |