diff options
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r-- | src/backend/parser/parse_relation.c | 648 |
1 files changed, 357 insertions, 291 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 6dc33e2411c..d7c4bae8ccf 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -472,7 +472,8 @@ check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("invalid reference to FROM-clause entry for table \"%s\"", refname), - (rte == pstate->p_target_rangetblentry) ? + (pstate->p_target_nsitem != NULL && + rte == pstate->p_target_nsitem->p_rte) ? errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.", refname) : errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."), @@ -669,9 +670,6 @@ scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem, RangeTblEntry *rte = nsitem->p_rte; int attnum; Var *var; - Oid vartypeid; - int32 vartypmod; - Oid varcollid; /* * Scan the RTE's column names (or aliases) for a match. Complain if @@ -703,11 +701,39 @@ scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem, parser_errposition(pstate, location))); /* Found a valid match, so build a Var */ - get_rte_attribute_type(rte, attnum, - &vartypeid, &vartypmod, &varcollid); - var = makeVar(nsitem->p_rtindex, attnum, - vartypeid, vartypmod, varcollid, - sublevels_up); + if (attnum > InvalidAttrNumber) + { + /* Get attribute data from the ParseNamespaceColumn array */ + ParseNamespaceColumn *nscol = &nsitem->p_nscolumns[attnum - 1]; + + /* Complain if dropped column. See notes in scanRTEForColumn. */ + if (nscol->p_varno == 0) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + colname, + rte->eref->aliasname))); + + var = makeVar(nsitem->p_rtindex, + attnum, + nscol->p_vartype, + nscol->p_vartypmod, + nscol->p_varcollid, + sublevels_up); + } + else + { + /* System column, so use predetermined type data */ + const FormData_pg_attribute *sysatt; + + sysatt = SystemAttributeDefinition(attnum); + var = makeVar(nsitem->p_rtindex, + attnum, + sysatt->atttypid, + sysatt->atttypmod, + sysatt->attcollation, + sublevels_up); + } var->location = location; /* Require read access to the column */ @@ -753,11 +779,9 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, * don't bother to test for that case here. * * Should this somehow go wrong and we try to access a dropped column, - * we'll still catch it by virtue of the checks in - * get_rte_attribute_type(), which is called by scanNSItemForColumn(). - * That routine has to do a cache lookup anyway, so the check there is - * cheap. Callers interested in finding match with shortest distance need - * to defend against this directly, though. + * we'll still catch it by virtue of the check in scanNSItemForColumn(). + * Callers interested in finding match with shortest distance need to + * defend against this directly, though. */ foreach(c, rte->eref->colnames) { @@ -1201,6 +1225,121 @@ chooseScalarFunctionAlias(Node *funcexpr, char *funcname, } /* + * buildNSItemFromTupleDesc + * Build a ParseNamespaceItem, given a tupdesc describing the columns. + * + * rte: the new RangeTblEntry for the rel + * rtindex: its index in the rangetable list + * tupdesc: the physical column information + */ +static ParseNamespaceItem * +buildNSItemFromTupleDesc(RangeTblEntry *rte, Index rtindex, TupleDesc tupdesc) +{ + ParseNamespaceItem *nsitem; + ParseNamespaceColumn *nscolumns; + int maxattrs = tupdesc->natts; + int varattno; + + /* colnames must have the same number of entries as the nsitem */ + Assert(maxattrs == list_length(rte->eref->colnames)); + + /* extract per-column data from the tupdesc */ + nscolumns = (ParseNamespaceColumn *) + palloc0(maxattrs * sizeof(ParseNamespaceColumn)); + + for (varattno = 0; varattno < maxattrs; varattno++) + { + Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno); + + /* For a dropped column, just leave the entry as zeroes */ + if (attr->attisdropped) + continue; + + nscolumns[varattno].p_varno = rtindex; + nscolumns[varattno].p_varattno = varattno + 1; + nscolumns[varattno].p_vartype = attr->atttypid; + nscolumns[varattno].p_vartypmod = attr->atttypmod; + nscolumns[varattno].p_varcollid = attr->attcollation; + nscolumns[varattno].p_varnosyn = rtindex; + nscolumns[varattno].p_varattnosyn = varattno + 1; + } + + /* ... and build the nsitem */ + nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem)); + nsitem->p_rte = rte; + nsitem->p_rtindex = rtindex; + nsitem->p_nscolumns = nscolumns; + /* set default visibility flags; might get changed later */ + nsitem->p_rel_visible = true; + nsitem->p_cols_visible = true; + nsitem->p_lateral_only = false; + nsitem->p_lateral_ok = true; + + return nsitem; +} + +/* + * buildNSItemFromLists + * Build a ParseNamespaceItem, given column type information in lists. + * + * rte: the new RangeTblEntry for the rel + * rtindex: its index in the rangetable list + * coltypes: per-column datatype OIDs + * coltypmods: per-column type modifiers + * colcollation: per-column collation OIDs + */ +static ParseNamespaceItem * +buildNSItemFromLists(RangeTblEntry *rte, Index rtindex, + List *coltypes, List *coltypmods, List *colcollations) +{ + ParseNamespaceItem *nsitem; + ParseNamespaceColumn *nscolumns; + int maxattrs = list_length(coltypes); + int varattno; + ListCell *lct; + ListCell *lcm; + ListCell *lcc; + + /* colnames must have the same number of entries as the nsitem */ + Assert(maxattrs == list_length(rte->eref->colnames)); + + Assert(maxattrs == list_length(coltypmods)); + Assert(maxattrs == list_length(colcollations)); + + /* extract per-column data from the lists */ + nscolumns = (ParseNamespaceColumn *) + palloc0(maxattrs * sizeof(ParseNamespaceColumn)); + + varattno = 0; + forthree(lct, coltypes, + lcm, coltypmods, + lcc, colcollations) + { + nscolumns[varattno].p_varno = rtindex; + nscolumns[varattno].p_varattno = varattno + 1; + nscolumns[varattno].p_vartype = lfirst_oid(lct); + nscolumns[varattno].p_vartypmod = lfirst_int(lcm); + nscolumns[varattno].p_varcollid = lfirst_oid(lcc); + nscolumns[varattno].p_varnosyn = rtindex; + nscolumns[varattno].p_varattnosyn = varattno + 1; + varattno++; + } + + /* ... and build the nsitem */ + nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem)); + nsitem->p_rte = rte; + nsitem->p_rtindex = rtindex; + nsitem->p_nscolumns = nscolumns; + /* set default visibility flags; might get changed later */ + nsitem->p_rel_visible = true; + nsitem->p_cols_visible = true; + nsitem->p_lateral_only = false; + nsitem->p_lateral_ok = true; + + return nsitem; +} + +/* * Open a table during parse analysis * * This is essentially just the same as table_openrv(), except that it caters @@ -1255,11 +1394,15 @@ parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode) /* * Add an entry for a relation to the pstate's range table (p_rtable). + * Then, construct and return a ParseNamespaceItem for the new RTE. + * + * We do not link the ParseNamespaceItem into the pstate here; it's the + * caller's job to do that in the appropriate way. * * Note: formerly this checked for refname conflicts, but that's wrong. * Caller is responsible for checking for conflicts in the appropriate scope. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntry(ParseState *pstate, RangeVar *relation, Alias *alias, @@ -1270,6 +1413,7 @@ addRangeTableEntry(ParseState *pstate, char *refname = alias ? alias->aliasname : relation->relname; LOCKMODE lockmode; Relation rel; + ParseNamespaceItem *nsitem; Assert(pstate != NULL); @@ -1302,13 +1446,6 @@ addRangeTableEntry(ParseState *pstate, buildRelationAliases(rel->rd_att, alias, rte->eref); /* - * 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. - */ - table_close(rel, NoLock); - - /* * Set flags and access permissions. * * The initial default on access checks is always check-for-READ-access, @@ -1326,16 +1463,32 @@ addRangeTableEntry(ParseState *pstate, rte->extraUpdatedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + nsitem = buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable), + rel->rd_att); + + /* + * 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. + */ + table_close(rel, NoLock); + + return nsitem; } /* * Add an entry for a relation to the pstate's range table (p_rtable). + * Then, construct and return a ParseNamespaceItem for the new RTE. * * This is just like addRangeTableEntry() except that it makes an RTE * given an already-open relation instead of a RangeVar reference. @@ -1349,7 +1502,7 @@ addRangeTableEntry(ParseState *pstate, * would require importing storage/lock.h into parse_relation.h. Since * LOCKMODE is typedef'd as int anyway, that seems like overkill. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, @@ -1398,21 +1551,28 @@ addRangeTableEntryForRelation(ParseState *pstate, rte->extraUpdatedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable), + rel->rd_att); } /* * Add an entry for a subquery to the pstate's range table (p_rtable). + * Then, construct and return a ParseNamespaceItem for the new RTE. * - * This is just like addRangeTableEntry() except that it makes a subquery RTE. + * This is much like addRangeTableEntry() except that it makes a subquery RTE. * Note that an alias clause *must* be supplied. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntryForSubquery(ParseState *pstate, Query *subquery, Alias *alias, @@ -1423,6 +1583,9 @@ addRangeTableEntryForSubquery(ParseState *pstate, char *refname = alias->aliasname; Alias *eref; int numaliases; + List *coltypes, + *coltypmods, + *colcollations; int varattno; ListCell *tlistitem; @@ -1435,7 +1598,8 @@ addRangeTableEntryForSubquery(ParseState *pstate, eref = copyObject(alias); numaliases = list_length(eref->colnames); - /* fill in any unspecified alias columns */ + /* fill in any unspecified alias columns, and extract column type info */ + coltypes = coltypmods = colcollations = NIL; varattno = 0; foreach(tlistitem, subquery->targetList) { @@ -1452,6 +1616,12 @@ addRangeTableEntryForSubquery(ParseState *pstate, attrname = pstrdup(te->resname); eref->colnames = lappend(eref->colnames, makeString(attrname)); } + coltypes = lappend_oid(coltypes, + exprType((Node *) te->expr)); + coltypmods = lappend_int(coltypmods, + exprTypmod((Node *) te->expr)); + colcollations = lappend_oid(colcollations, + exprCollation((Node *) te->expr)); } if (varattno < numaliases) ereport(ERROR, @@ -1478,21 +1648,27 @@ addRangeTableEntryForSubquery(ParseState *pstate, rte->extraUpdatedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + return buildNSItemFromLists(rte, list_length(pstate->p_rtable), + coltypes, coltypmods, colcollations); } /* * Add an entry for a function (or functions) to the pstate's range table - * (p_rtable). + * (p_rtable). Then, construct and return a ParseNamespaceItem for the new RTE. * - * This is just like addRangeTableEntry() except that it makes a function RTE. + * This is much like addRangeTableEntry() except that it makes a function RTE. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntryForFunction(ParseState *pstate, List *funcnames, List *funcexprs, @@ -1742,20 +1918,27 @@ addRangeTableEntryForFunction(ParseState *pstate, rte->extraUpdatedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable), + tupdesc); } /* * Add an entry for a table function to the pstate's range table (p_rtable). + * Then, construct and return a ParseNamespaceItem for the new RTE. * * This is much like addRangeTableEntry() except that it makes a tablefunc RTE. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntryForTableFunc(ParseState *pstate, TableFunc *tf, Alias *alias, @@ -1806,20 +1989,28 @@ addRangeTableEntryForTableFunc(ParseState *pstate, rte->extraUpdatedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + return buildNSItemFromLists(rte, list_length(pstate->p_rtable), + rte->coltypes, rte->coltypmods, + rte->colcollations); } /* * Add an entry for a VALUES list to the pstate's range table (p_rtable). + * Then, construct and return a ParseNamespaceItem for the new RTE. * * This is much like addRangeTableEntry() except that it makes a values RTE. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntryForValues(ParseState *pstate, List *exprs, List *coltypes, @@ -1885,22 +2076,33 @@ addRangeTableEntryForValues(ParseState *pstate, rte->extraUpdatedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + return buildNSItemFromLists(rte, list_length(pstate->p_rtable), + rte->coltypes, rte->coltypmods, + rte->colcollations); } /* * Add an entry for a join to the pstate's range table (p_rtable). + * Then, construct and return a ParseNamespaceItem for the new RTE. * * This is much like addRangeTableEntry() except that it makes a join RTE. + * Also, it's more convenient for the caller to construct the + * ParseNamespaceColumn array, so we pass that in. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntryForJoin(ParseState *pstate, List *colnames, + ParseNamespaceColumn *nscolumns, JoinType jointype, List *aliasvars, Alias *alias, @@ -1909,6 +2111,7 @@ addRangeTableEntryForJoin(ParseState *pstate, RangeTblEntry *rte = makeNode(RangeTblEntry); Alias *eref; int numaliases; + ParseNamespaceItem *nsitem; Assert(pstate != NULL); @@ -1956,20 +2159,36 @@ addRangeTableEntryForJoin(ParseState *pstate, rte->extraUpdatedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem)); + nsitem->p_rte = rte; + nsitem->p_rtindex = list_length(pstate->p_rtable); + nsitem->p_nscolumns = nscolumns; + /* set default visibility flags; might get changed later */ + nsitem->p_rel_visible = true; + nsitem->p_cols_visible = true; + nsitem->p_lateral_only = false; + nsitem->p_lateral_ok = true; + + return nsitem; } /* * Add an entry for a CTE reference to the pstate's range table (p_rtable). + * Then, construct and return a ParseNamespaceItem for the new RTE. * * This is much like addRangeTableEntry() except that it makes a CTE RTE. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntryForCTE(ParseState *pstate, CommonTableExpr *cte, Index levelsup, @@ -2059,17 +2278,25 @@ addRangeTableEntryForCTE(ParseState *pstate, rte->extraUpdatedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + return buildNSItemFromLists(rte, list_length(pstate->p_rtable), + rte->coltypes, rte->coltypmods, + rte->colcollations); } /* * Add an entry for an ephemeral named relation reference to the pstate's * range table (p_rtable). + * Then, construct and return a ParseNamespaceItem for the new RTE. * * It is expected that the RangeVar, which up until now is only known to be an * ephemeral named relation, will (in conjunction with the QueryEnvironment in @@ -2079,7 +2306,7 @@ addRangeTableEntryForCTE(ParseState *pstate, * This is much like addRangeTableEntry() except that it makes an RTE for an * ephemeral named relation. */ -RangeTblEntry * +ParseNamespaceItem * addRangeTableEntryForENR(ParseState *pstate, RangeVar *rv, bool inFromCl) @@ -2164,12 +2391,18 @@ addRangeTableEntryForENR(ParseState *pstate, rte->selectedCols = NULL; /* - * Add completed RTE to pstate's range table list, but not to join list - * nor namespace --- caller must do that if appropriate. + * Add completed RTE to pstate's range table list, so that we know its + * index. But we don't add it to the join list --- caller must do that if + * appropriate. */ pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + /* + * Build a ParseNamespaceItem, but don't add it to the pstate's namespace + * list --- caller must do that if appropriate. + */ + return buildNSItemFromTupleDesc(rte, list_length(pstate->p_rtable), + tupdesc); } @@ -2221,49 +2454,26 @@ isLockedRefname(ParseState *pstate, const char *refname) } /* - * Add the given RTE as a top-level entry in the pstate's join list + * Add the given nsitem/RTE as a top-level entry in the pstate's join list * and/or namespace list. (We assume caller has checked for any - * namespace conflicts.) The RTE is always marked as unconditionally + * namespace conflicts.) The nsitem is always marked as unconditionally * visible, that is, not LATERAL-only. - * - * Note: some callers know that they can find the new ParseNamespaceItem - * at the end of the pstate->p_namespace list. This is a bit ugly but not - * worth complicating this function's signature for. */ void -addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, - bool addToJoinList, - bool addToRelNameSpace, bool addToVarNameSpace) +addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, + bool addToJoinList, + bool addToRelNameSpace, bool addToVarNameSpace) { - int rtindex; - - /* - * Most callers have just added the RTE to the rangetable, so it's likely - * to be the last entry. Hence, it's a good idea to search the rangetable - * back-to-front. - */ - for (rtindex = list_length(pstate->p_rtable); rtindex > 0; rtindex--) - { - if (rte == rt_fetch(rtindex, pstate->p_rtable)) - break; - } - if (rtindex <= 0) - elog(ERROR, "RTE not found (internal error)"); - if (addToJoinList) { RangeTblRef *rtr = makeNode(RangeTblRef); - rtr->rtindex = rtindex; + rtr->rtindex = nsitem->p_rtindex; pstate->p_joinlist = lappend(pstate->p_joinlist, rtr); } if (addToRelNameSpace || addToVarNameSpace) { - ParseNamespaceItem *nsitem; - - nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem)); - nsitem->p_rte = rte; - nsitem->p_rtindex = rtindex; + /* Set the new nsitem's visibility flags correctly */ nsitem->p_rel_visible = addToRelNameSpace; nsitem->p_cols_visible = addToVarNameSpace; nsitem->p_lateral_only = false; @@ -2721,6 +2931,61 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset, } /* + * expandNSItemVars + * Produce a list of Vars, and optionally a list of column names, + * for the non-dropped columns of the nsitem. + * + * The emitted Vars are marked with the given sublevels_up and location. + * + * If colnames isn't NULL, a list of String items for the columns is stored + * there; note that it's just a subset of the RTE's eref list, and hence + * the list elements mustn't be modified. + */ +List * +expandNSItemVars(ParseNamespaceItem *nsitem, + int sublevels_up, int location, + List **colnames) +{ + List *result = NIL; + int colindex; + ListCell *lc; + + if (colnames) + *colnames = NIL; + colindex = 0; + foreach(lc, nsitem->p_rte->eref->colnames) + { + Value *colnameval = (Value *) lfirst(lc); + const char *colname = strVal(colnameval); + ParseNamespaceColumn *nscol = nsitem->p_nscolumns + colindex; + + if (colname[0]) + { + Var *var; + + Assert(nscol->p_varno > 0); + var = makeVar(nsitem->p_rtindex, + colindex + 1, + nscol->p_vartype, + nscol->p_vartypmod, + nscol->p_varcollid, + sublevels_up); + var->location = location; + result = lappend(result, var); + if (colnames) + *colnames = lappend(*colnames, colnameval); + } + else + { + /* dropped column, ignore */ + Assert(nscol->p_varno == 0); + } + colindex++; + } + return result; +} + +/* * expandNSItemAttrs - * Workhorse for "*" expansion: produce a list of targetentries * for the attributes of the nsitem @@ -2739,8 +3004,7 @@ expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem, *var; List *te_list = NIL; - expandRTE(rte, nsitem->p_rtindex, sublevels_up, location, false, - &names, &vars); + vars = expandNSItemVars(nsitem, sublevels_up, location, &names); /* * Require read access to the table. This is normally redundant with the @@ -2816,204 +3080,6 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum) } /* - * get_rte_attribute_type - * Get attribute type/typmod/collation information from a RangeTblEntry - */ -void -get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, - Oid *vartype, int32 *vartypmod, Oid *varcollid) -{ - switch (rte->rtekind) - { - case RTE_RELATION: - { - /* Plain relation RTE --- get the attribute's type info */ - HeapTuple tp; - Form_pg_attribute att_tup; - - tp = SearchSysCache2(ATTNUM, - ObjectIdGetDatum(rte->relid), - Int16GetDatum(attnum)); - if (!HeapTupleIsValid(tp)) /* shouldn't happen */ - elog(ERROR, "cache lookup failed for attribute %d of relation %u", - attnum, rte->relid); - att_tup = (Form_pg_attribute) GETSTRUCT(tp); - - /* - * If dropped column, pretend it ain't there. See notes in - * scanRTEForColumn. - */ - if (att_tup->attisdropped) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - NameStr(att_tup->attname), - get_rel_name(rte->relid)))); - *vartype = att_tup->atttypid; - *vartypmod = att_tup->atttypmod; - *varcollid = att_tup->attcollation; - ReleaseSysCache(tp); - } - break; - case RTE_SUBQUERY: - { - /* Subselect RTE --- get type info from subselect's tlist */ - TargetEntry *te = get_tle_by_resno(rte->subquery->targetList, - attnum); - - if (te == NULL || te->resjunk) - elog(ERROR, "subquery %s does not have attribute %d", - rte->eref->aliasname, attnum); - *vartype = exprType((Node *) te->expr); - *vartypmod = exprTypmod((Node *) te->expr); - *varcollid = exprCollation((Node *) te->expr); - } - break; - case RTE_FUNCTION: - { - /* Function RTE */ - ListCell *lc; - int atts_done = 0; - - /* Identify which function covers the requested column */ - foreach(lc, rte->functions) - { - RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); - - if (attnum > atts_done && - attnum <= atts_done + rtfunc->funccolcount) - { - TypeFuncClass functypclass; - Oid funcrettype; - TupleDesc tupdesc; - - attnum -= atts_done; /* now relative to this func */ - functypclass = get_expr_result_type(rtfunc->funcexpr, - &funcrettype, - &tupdesc); - - if (functypclass == TYPEFUNC_COMPOSITE || - functypclass == TYPEFUNC_COMPOSITE_DOMAIN) - { - /* Composite data type, e.g. a table's row type */ - Form_pg_attribute att_tup; - - Assert(tupdesc); - Assert(attnum <= tupdesc->natts); - att_tup = TupleDescAttr(tupdesc, attnum - 1); - - /* - * If dropped column, pretend it ain't there. See - * notes in scanRTEForColumn. - */ - if (att_tup->attisdropped) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - NameStr(att_tup->attname), - rte->eref->aliasname))); - *vartype = att_tup->atttypid; - *vartypmod = att_tup->atttypmod; - *varcollid = att_tup->attcollation; - } - else if (functypclass == TYPEFUNC_SCALAR) - { - /* Base data type, i.e. scalar */ - *vartype = funcrettype; - *vartypmod = -1; - *varcollid = exprCollation(rtfunc->funcexpr); - } - else if (functypclass == TYPEFUNC_RECORD) - { - *vartype = list_nth_oid(rtfunc->funccoltypes, - attnum - 1); - *vartypmod = list_nth_int(rtfunc->funccoltypmods, - attnum - 1); - *varcollid = list_nth_oid(rtfunc->funccolcollations, - attnum - 1); - } - else - { - /* - * addRangeTableEntryForFunction should've caught - * this - */ - elog(ERROR, "function in FROM has unsupported return type"); - } - return; - } - atts_done += rtfunc->funccolcount; - } - - /* If we get here, must be looking for the ordinality column */ - if (rte->funcordinality && attnum == atts_done + 1) - { - *vartype = INT8OID; - *vartypmod = -1; - *varcollid = InvalidOid; - return; - } - - /* this probably can't happen ... */ - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column %d of relation \"%s\" does not exist", - attnum, - rte->eref->aliasname))); - } - break; - case RTE_JOIN: - { - /* - * Join RTE --- get type info from join RTE's alias variable - */ - Node *aliasvar; - - Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars)); - aliasvar = (Node *) list_nth(rte->joinaliasvars, attnum - 1); - Assert(aliasvar != NULL); - *vartype = exprType(aliasvar); - *vartypmod = exprTypmod(aliasvar); - *varcollid = exprCollation(aliasvar); - } - break; - case RTE_TABLEFUNC: - case RTE_VALUES: - case RTE_CTE: - case RTE_NAMEDTUPLESTORE: - { - /* - * tablefunc, VALUES, CTE, or ENR RTE --- get type info from - * lists in the RTE - */ - Assert(attnum > 0 && attnum <= list_length(rte->coltypes)); - *vartype = list_nth_oid(rte->coltypes, attnum - 1); - *vartypmod = list_nth_int(rte->coltypmods, attnum - 1); - *varcollid = list_nth_oid(rte->colcollations, attnum - 1); - - /* For ENR, better check for dropped column */ - if (!OidIsValid(*vartype)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column %d of relation \"%s\" does not exist", - attnum, - rte->eref->aliasname))); - } - break; - case RTE_RESULT: - /* this probably can't happen ... */ - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column %d of relation \"%s\" does not exist", - attnum, - rte->eref->aliasname))); - break; - default: - elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); - } -} - -/* * get_rte_attribute_is_dropped * Check whether attempted attribute ref is to a dropped column */ |