aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/tupdesc.c53
-rw-r--r--src/backend/catalog/dependency.c83
-rw-r--r--src/backend/executor/nodeFunctionscan.c6
-rw-r--r--src/backend/nodes/copyfuncs.c5
-rw-r--r--src/backend/nodes/equalfuncs.c5
-rw-r--r--src/backend/nodes/outfuncs.c7
-rw-r--r--src/backend/nodes/readfuncs.c45
-rw-r--r--src/backend/parser/parse_clause.c24
-rw-r--r--src/backend/parser/parse_relation.c63
-rw-r--r--src/backend/utils/adt/ruleutils.c81
-rw-r--r--src/include/access/tupdesc.h4
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/nodes/parsenodes.h14
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):