aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_relation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r--src/backend/parser/parse_relation.c510
1 files changed, 371 insertions, 139 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index b822a2378ba..857adf05691 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.68 2002/04/28 19:54:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.69 2002/05/12 20:10:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -673,6 +673,117 @@ addRangeTableEntryForSubquery(ParseState *pstate,
}
/*
+ * Add an entry for a function to the pstate's range table (p_rtable).
+ *
+ * This is just like addRangeTableEntry() except that it makes a function RTE.
+ */
+RangeTblEntry *
+addRangeTableEntryForFunction(ParseState *pstate,
+ char *funcname,
+ Node *funcexpr,
+ Alias *alias,
+ bool inFromCl)
+{
+ RangeTblEntry *rte = makeNode(RangeTblEntry);
+ Oid funcrettype = exprType(funcexpr);
+ Oid funcrelid;
+ Alias *eref;
+ int numaliases;
+ int varattno;
+
+ rte->rtekind = RTE_FUNCTION;
+ rte->relid = InvalidOid;
+ rte->subquery = NULL;
+ rte->funcexpr = funcexpr;
+ rte->alias = alias;
+
+ eref = alias ? (Alias *) copyObject(alias) : makeAlias(funcname, NIL);
+ rte->eref = eref;
+
+ numaliases = length(eref->colnames);
+
+ /*
+ * Now determine if the function returns a simple or composite type,
+ * and check/add column aliases.
+ */
+ funcrelid = typeidTypeRelid(funcrettype);
+
+ if (OidIsValid(funcrelid))
+ {
+ /*
+ * Composite data type, i.e. a table's row type
+ *
+ * Get the rel's relcache entry. This access ensures that we have an
+ * up-to-date relcache entry for the rel.
+ */
+ Relation rel;
+ int maxattrs;
+
+ rel = heap_open(funcrelid, AccessShareLock);
+
+ /*
+ * Since the rel is open anyway, let's check that the number of column
+ * aliases is reasonable.
+ */
+ maxattrs = RelationGetNumberOfAttributes(rel);
+ if (maxattrs < numaliases)
+ elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
+ RelationGetRelationName(rel), maxattrs, numaliases);
+
+ /* fill in alias columns using actual column names */
+ for (varattno = numaliases; varattno < maxattrs; varattno++)
+ {
+ char *attrname;
+
+ attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
+ eref->colnames = lappend(eref->colnames, makeString(attrname));
+ }
+
+ /*
+ * Drop the rel refcount, but keep the access lock till end of
+ * transaction so that the table can't be deleted or have its schema
+ * modified underneath us.
+ */
+ heap_close(rel, NoLock);
+ }
+ else
+ {
+ /*
+ * Must be a base data type, i.e. scalar.
+ * Just add one alias column named for the function.
+ */
+ if (numaliases > 1)
+ elog(ERROR, "Too many column aliases specified for function %s",
+ funcname);
+ if (numaliases == 0)
+ eref->colnames = makeList1(makeString(funcname));
+ }
+
+ /*----------
+ * Flags:
+ * - this RTE should be expanded to include descendant tables,
+ * - this RTE is in the FROM clause,
+ * - this RTE should be checked for read/write access rights.
+ *----------
+ */
+ rte->inh = false; /* never true for functions */
+ rte->inFromCl = inFromCl;
+ rte->checkForRead = true;
+ rte->checkForWrite = false;
+
+ rte->checkAsUser = InvalidOid;
+
+ /*
+ * Add completed RTE to pstate's range table list, but not to join
+ * list nor namespace --- caller must do that if appropriate.
+ */
+ if (pstate != NULL)
+ pstate->p_rtable = lappend(pstate->p_rtable, rte);
+
+ return rte;
+}
+
+/*
* Add an entry for a join to the pstate's range table (p_rtable).
*
* This is much like addRangeTableEntry() except that it makes a join RTE.
@@ -834,124 +945,201 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
/* Need the RT index of the entry for creating Vars */
rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
- if (rte->rtekind == RTE_RELATION)
+ switch (rte->rtekind)
{
- /* Ordinary relation RTE */
- Relation rel;
- int maxattrs;
- int numaliases;
+ case RTE_RELATION:
+ {
+ /* Ordinary relation RTE */
+ Relation rel;
+ int maxattrs;
+ int numaliases;
- rel = heap_open(rte->relid, AccessShareLock);
- maxattrs = RelationGetNumberOfAttributes(rel);
- numaliases = length(rte->eref->colnames);
+ rel = heap_open(rte->relid, AccessShareLock);
+ maxattrs = RelationGetNumberOfAttributes(rel);
+ numaliases = length(rte->eref->colnames);
- for (varattno = 0; varattno < maxattrs; varattno++)
- {
- Form_pg_attribute attr = rel->rd_att->attrs[varattno];
+ for (varattno = 0; varattno < maxattrs; varattno++)
+ {
+ Form_pg_attribute attr = rel->rd_att->attrs[varattno];
- if (colnames)
- {
- char *label;
+ if (colnames)
+ {
+ char *label;
- if (varattno < numaliases)
- label = strVal(nth(varattno, rte->eref->colnames));
- else
- label = NameStr(attr->attname);
- *colnames = lappend(*colnames, makeString(pstrdup(label)));
- }
+ if (varattno < numaliases)
+ label = strVal(nth(varattno, rte->eref->colnames));
+ else
+ label = NameStr(attr->attname);
+ *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ }
- if (colvars)
- {
- Var *varnode;
+ if (colvars)
+ {
+ Var *varnode;
- varnode = makeVar(rtindex, attr->attnum,
- attr->atttypid, attr->atttypmod,
- sublevels_up);
+ varnode = makeVar(rtindex, attr->attnum,
+ attr->atttypid, attr->atttypmod,
+ sublevels_up);
+
+ *colvars = lappend(*colvars, varnode);
+ }
+ }
- *colvars = lappend(*colvars, varnode);
+ heap_close(rel, AccessShareLock);
}
- }
+ break;
+ case RTE_SUBQUERY:
+ {
+ /* Subquery RTE */
+ List *aliasp = rte->eref->colnames;
+ List *tlistitem;
- heap_close(rel, AccessShareLock);
- }
- else if (rte->rtekind == RTE_SUBQUERY)
- {
- /* Subquery RTE */
- List *aliasp = rte->eref->colnames;
- List *tlistitem;
+ varattno = 0;
+ foreach(tlistitem, rte->subquery->targetList)
+ {
+ TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
- varattno = 0;
- foreach(tlistitem, rte->subquery->targetList)
- {
- TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
+ if (te->resdom->resjunk)
+ continue;
+ varattno++;
+ Assert(varattno == te->resdom->resno);
- if (te->resdom->resjunk)
- continue;
- varattno++;
- Assert(varattno == te->resdom->resno);
+ if (colnames)
+ {
+ /* Assume there is one alias per target item */
+ char *label = strVal(lfirst(aliasp));
- if (colnames)
- {
- /* Assume there is one alias per target item */
- char *label = strVal(lfirst(aliasp));
+ *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ aliasp = lnext(aliasp);
+ }
- *colnames = lappend(*colnames, makeString(pstrdup(label)));
- aliasp = lnext(aliasp);
- }
+ if (colvars)
+ {
+ Var *varnode;
- if (colvars)
- {
- Var *varnode;
+ varnode = makeVar(rtindex, varattno,
+ te->resdom->restype,
+ te->resdom->restypmod,
+ sublevels_up);
- varnode = makeVar(rtindex, varattno,
- te->resdom->restype,
- te->resdom->restypmod,
- sublevels_up);
+ *colvars = lappend(*colvars, varnode);
+ }
+ }
+ }
+ break;
+ case RTE_FUNCTION:
+ {
+ /* Function RTE */
+ Oid funcrettype = exprType(rte->funcexpr);
+ Oid funcrelid = typeidTypeRelid(funcrettype);
- *colvars = lappend(*colvars, varnode);
+ if (OidIsValid(funcrelid))
+ {
+ /*
+ * Composite data type, i.e. a table's row type
+ * Same as ordinary relation RTE
+ */
+ Relation rel;
+ int maxattrs;
+ int numaliases;
+
+ rel = heap_open(funcrelid, AccessShareLock);
+ maxattrs = RelationGetNumberOfAttributes(rel);
+ numaliases = length(rte->eref->colnames);
+
+ for (varattno = 0; varattno < maxattrs; varattno++)
+ {
+ Form_pg_attribute attr = rel->rd_att->attrs[varattno];
+
+ if (colnames)
+ {
+ char *label;
+
+ if (varattno < numaliases)
+ label = strVal(nth(varattno, rte->eref->colnames));
+ else
+ label = NameStr(attr->attname);
+ *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ }
+
+ if (colvars)
+ {
+ Var *varnode;
+
+ varnode = makeVar(rtindex, attr->attnum,
+ attr->atttypid, attr->atttypmod,
+ sublevels_up);
+
+ *colvars = lappend(*colvars, varnode);
+ }
+ }
+
+ heap_close(rel, AccessShareLock);
+ }
+ else
+ {
+ /*
+ * Must be a base data type, i.e. scalar
+ */
+ if (colnames)
+ *colnames = lappend(*colnames,
+ lfirst(rte->eref->colnames));
+
+ if (colvars)
+ {
+ Var *varnode;
+
+ varnode = makeVar(rtindex, 1,
+ funcrettype, -1,
+ sublevels_up);
+
+ *colvars = lappend(*colvars, varnode);
+ }
+ }
}
- }
- }
- else if (rte->rtekind == RTE_JOIN)
- {
- /* Join RTE */
- List *aliasp = rte->eref->colnames;
- List *aliasvars = rte->joinaliasvars;
+ break;
+ case RTE_JOIN:
+ {
+ /* Join RTE */
+ List *aliasp = rte->eref->colnames;
+ List *aliasvars = rte->joinaliasvars;
- varattno = 0;
- while (aliasp)
- {
- Assert(aliasvars);
- varattno++;
+ varattno = 0;
+ while (aliasp)
+ {
+ Assert(aliasvars);
+ varattno++;
- if (colnames)
- {
- char *label = strVal(lfirst(aliasp));
+ if (colnames)
+ {
+ char *label = strVal(lfirst(aliasp));
- *colnames = lappend(*colnames, makeString(pstrdup(label)));
- }
+ *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ }
- if (colvars)
- {
- Node *aliasvar = (Node *) lfirst(aliasvars);
- Var *varnode;
+ if (colvars)
+ {
+ Node *aliasvar = (Node *) lfirst(aliasvars);
+ Var *varnode;
- varnode = makeVar(rtindex, varattno,
- exprType(aliasvar),
- exprTypmod(aliasvar),
- sublevels_up);
+ varnode = makeVar(rtindex, varattno,
+ exprType(aliasvar),
+ exprTypmod(aliasvar),
+ sublevels_up);
- *colvars = lappend(*colvars, varnode);
- }
+ *colvars = lappend(*colvars, varnode);
+ }
- aliasp = lnext(aliasp);
- aliasvars = lnext(aliasvars);
- }
- Assert(aliasvars == NIL);
+ aliasp = lnext(aliasp);
+ aliasvars = lnext(aliasvars);
+ }
+ Assert(aliasvars == NIL);
+ }
+ break;
+ default:
+ elog(ERROR, "expandRTE: unsupported RTE kind %d",
+ (int) rte->rtekind);
}
- else
- elog(ERROR, "expandRTE: unsupported RTE kind %d",
- (int) rte->rtekind);
}
/*
@@ -1044,57 +1232,101 @@ void
get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
Oid *vartype, int32 *vartypmod)
{
- if (rte->rtekind == RTE_RELATION)
+ switch (rte->rtekind)
{
- /* Plain relation RTE --- get the attribute's type info */
- HeapTuple tp;
- Form_pg_attribute att_tup;
-
- tp = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(rte->relid),
- Int16GetDatum(attnum),
- 0, 0);
- /* this shouldn't happen... */
- if (!HeapTupleIsValid(tp))
- elog(ERROR, "Relation %s does not have attribute %d",
- get_rel_name(rte->relid), attnum);
- att_tup = (Form_pg_attribute) GETSTRUCT(tp);
- *vartype = att_tup->atttypid;
- *vartypmod = att_tup->atttypmod;
- ReleaseSysCache(tp);
- }
- else if (rte->rtekind == RTE_SUBQUERY)
- {
- /* Subselect RTE --- get type info from subselect's tlist */
- List *tlistitem;
+ case RTE_RELATION:
+ {
+ /* Plain relation RTE --- get the attribute's type info */
+ HeapTuple tp;
+ Form_pg_attribute att_tup;
+
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(rte->relid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ /* this shouldn't happen... */
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "Relation %s does not have attribute %d",
+ get_rel_name(rte->relid), attnum);
+ att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ *vartype = att_tup->atttypid;
+ *vartypmod = att_tup->atttypmod;
+ ReleaseSysCache(tp);
+ }
+ break;
+ case RTE_SUBQUERY:
+ {
+ /* Subselect RTE --- get type info from subselect's tlist */
+ List *tlistitem;
- foreach(tlistitem, rte->subquery->targetList)
- {
- TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
+ foreach(tlistitem, rte->subquery->targetList)
+ {
+ TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
- if (te->resdom->resjunk || te->resdom->resno != attnum)
- continue;
- *vartype = te->resdom->restype;
- *vartypmod = te->resdom->restypmod;
- return;
- }
- /* falling off end of list shouldn't happen... */
- elog(ERROR, "Subquery %s does not have attribute %d",
- rte->eref->aliasname, attnum);
- }
- else if (rte->rtekind == RTE_JOIN)
- {
- /* Join RTE --- get type info from join RTE's alias variable */
- Node *aliasvar;
+ if (te->resdom->resjunk || te->resdom->resno != attnum)
+ continue;
+ *vartype = te->resdom->restype;
+ *vartypmod = te->resdom->restypmod;
+ return;
+ }
+ /* falling off end of list shouldn't happen... */
+ elog(ERROR, "Subquery %s does not have attribute %d",
+ rte->eref->aliasname, attnum);
+ }
+ break;
+ case RTE_FUNCTION:
+ {
+ /* Function RTE */
+ Oid funcrettype = exprType(rte->funcexpr);
+ Oid funcrelid = typeidTypeRelid(funcrettype);
+
+ if (OidIsValid(funcrelid))
+ {
+ /*
+ * Composite data type, i.e. a table's row type
+ * Same as ordinary relation RTE
+ */
+ HeapTuple tp;
+ Form_pg_attribute att_tup;
+
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(funcrelid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ /* this shouldn't happen... */
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "Relation %s does not have attribute %d",
+ get_rel_name(funcrelid), attnum);
+ att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ *vartype = att_tup->atttypid;
+ *vartypmod = att_tup->atttypmod;
+ ReleaseSysCache(tp);
+ }
+ else
+ {
+ /*
+ * Must be a base data type, i.e. scalar
+ */
+ *vartype = funcrettype;
+ *vartypmod = -1;
+ }
+ }
+ break;
+ case RTE_JOIN:
+ {
+ /* Join RTE --- get type info from join RTE's alias variable */
+ Node *aliasvar;
- Assert(attnum > 0 && attnum <= length(rte->joinaliasvars));
- aliasvar = (Node *) nth(attnum-1, rte->joinaliasvars);
- *vartype = exprType(aliasvar);
- *vartypmod = exprTypmod(aliasvar);
+ Assert(attnum > 0 && attnum <= length(rte->joinaliasvars));
+ aliasvar = (Node *) nth(attnum-1, rte->joinaliasvars);
+ *vartype = exprType(aliasvar);
+ *vartypmod = exprTypmod(aliasvar);
+ }
+ break;
+ default:
+ elog(ERROR, "get_rte_attribute_type: unsupported RTE kind %d",
+ (int) rte->rtekind);
}
- else
- elog(ERROR, "get_rte_attribute_type: unsupported RTE kind %d",
- (int) rte->rtekind);
}
/*