#include "postgres.h"
#include <ctype.h>
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Go to the source code of this file.
Functions | |
static RangeTblEntry * | scanNameSpaceForRefname (ParseState *pstate, const char *refname, int location) |
static RangeTblEntry * | scanNameSpaceForRelid (ParseState *pstate, Oid relid, int location) |
static void | markRTEForSelectPriv (ParseState *pstate, RangeTblEntry *rte, int rtindex, AttrNumber col) |
static void | expandRelation (Oid relid, Alias *eref, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars) |
static void | expandTupleDesc (TupleDesc tupdesc, Alias *eref, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars) |
static int | specialAttNum (const char *attname) |
static bool | isQueryUsingTempRelation_walker (Node *node, void *context) |
RangeTblEntry * | refnameRangeTblEntry (ParseState *pstate, const char *schemaname, const char *refname, int location, int *sublevels_up) |
CommonTableExpr * | scanNameSpaceForCTE (ParseState *pstate, const char *refname, Index *ctelevelsup) |
static bool | isFutureCTE (ParseState *pstate, const char *refname) |
static RangeTblEntry * | searchRangeTableForRel (ParseState *pstate, RangeVar *relation) |
void | checkNameSpaceConflicts (ParseState *pstate, List *namespace1, List *namespace2) |
int | RTERangeTablePosn (ParseState *pstate, RangeTblEntry *rte, int *sublevels_up) |
RangeTblEntry * | GetRTEByRangeTablePosn (ParseState *pstate, int varno, int sublevels_up) |
CommonTableExpr * | GetCTEForRTE (ParseState *pstate, RangeTblEntry *rte, int rtelevelsup) |
Node * | scanRTEForColumn (ParseState *pstate, RangeTblEntry *rte, char *colname, int location) |
Node * | colNameToVar (ParseState *pstate, char *colname, bool localonly, int location) |
static RangeTblEntry * | searchRangeTableForCol (ParseState *pstate, char *colname, int location) |
void | markVarForSelectPriv (ParseState *pstate, Var *var, RangeTblEntry *rte) |
static void | buildRelationAliases (TupleDesc tupdesc, Alias *alias, Alias *eref) |
static void | buildScalarFunctionAlias (Node *funcexpr, char *funcname, Alias *alias, Alias *eref) |
Relation | parserOpenTable (ParseState *pstate, const RangeVar *relation, int lockmode) |
RangeTblEntry * | addRangeTableEntry (ParseState *pstate, RangeVar *relation, Alias *alias, bool inh, bool inFromCl) |
RangeTblEntry * | addRangeTableEntryForRelation (ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl) |
RangeTblEntry * | addRangeTableEntryForSubquery (ParseState *pstate, Query *subquery, Alias *alias, bool lateral, bool inFromCl) |
RangeTblEntry * | addRangeTableEntryForFunction (ParseState *pstate, char *funcname, Node *funcexpr, RangeFunction *rangefunc, bool lateral, bool inFromCl) |
RangeTblEntry * | addRangeTableEntryForValues (ParseState *pstate, List *exprs, List *collations, Alias *alias, bool lateral, bool inFromCl) |
RangeTblEntry * | addRangeTableEntryForJoin (ParseState *pstate, List *colnames, JoinType jointype, List *aliasvars, Alias *alias, bool inFromCl) |
RangeTblEntry * | addRangeTableEntryForCTE (ParseState *pstate, CommonTableExpr *cte, Index levelsup, RangeVar *rv, bool inFromCl) |
bool | isLockedRefname (ParseState *pstate, const char *refname) |
void | addRTEtoQuery (ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace) |
void | expandRTE (RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars) |
List * | expandRelAttrs (ParseState *pstate, RangeTblEntry *rte, int rtindex, int sublevels_up, int location) |
char * | get_rte_attribute_name (RangeTblEntry *rte, AttrNumber attnum) |
void | get_rte_attribute_type (RangeTblEntry *rte, AttrNumber attnum, Oid *vartype, int32 *vartypmod, Oid *varcollid) |
bool | get_rte_attribute_is_dropped (RangeTblEntry *rte, AttrNumber attnum) |
TargetEntry * | get_tle_by_resno (List *tlist, AttrNumber resno) |
RowMarkClause * | get_parse_rowmark (Query *qry, Index rtindex) |
int | attnameAttNum (Relation rd, const char *attname, bool sysColOK) |
Name | attnumAttName (Relation rd, int attid) |
Oid | attnumTypeId (Relation rd, int attid) |
Oid | attnumCollationId (Relation rd, int attid) |
void | errorMissingRTE (ParseState *pstate, RangeVar *relation) |
void | errorMissingColumn (ParseState *pstate, char *relname, char *colname, int location) |
bool | isQueryUsingTempRelation (Query *query) |
RangeTblEntry* addRangeTableEntry | ( | ParseState * | pstate, | |
RangeVar * | relation, | |||
Alias * | alias, | |||
bool | inh, | |||
bool | inFromCl | |||
) |
Definition at line 976 of file parse_relation.c.
References RangeTblEntry::alias, Alias::aliasname, buildRelationAliases(), RangeTblEntry::checkAsUser, RangeTblEntry::eref, heap_close, RangeTblEntry::inFromCl, RangeTblEntry::inh, isLockedRefname(), lappend(), RangeTblEntry::lateral, makeAlias(), makeNode, RangeTblEntry::modifiedCols, NIL, NoLock, NULL, ParseState::p_rtable, parserOpenTable(), RelationData::rd_att, RelationData::rd_rel, RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, RangeVar::relname, RangeTblEntry::requiredPerms, RowShareLock, RangeTblEntry::rtekind, and RangeTblEntry::selectedCols.
Referenced by transformIndexStmt(), and transformTableEntry().
{ RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias ? alias->aliasname : relation->relname; LOCKMODE lockmode; Relation rel; rte->rtekind = RTE_RELATION; rte->alias = alias; /* * Get the rel's OID. This access also ensures that we have an up-to-date * relcache entry for the rel. Since this is typically the first access * to a rel in a statement, be careful to get the right access level * depending on whether we're doing SELECT FOR UPDATE/SHARE. */ lockmode = isLockedRefname(pstate, refname) ? RowShareLock : AccessShareLock; rel = parserOpenTable(pstate, relation, lockmode); rte->relid = RelationGetRelid(rel); rte->relkind = rel->rd_rel->relkind; /* * Build the list of effective column names using user-supplied aliases * and/or actual column names. */ rte->eref = makeAlias(refname, NIL); 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. */ heap_close(rel, NoLock); /* * Set flags and access permissions. * * The initial default on access checks is always check-for-READ-access, * which is the right thing for all except target tables. */ rte->lateral = false; rte->inh = inh; rte->inFromCl = inFromCl; rte->requiredPerms = ACL_SELECT; rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ rte->selectedCols = NULL; rte->modifiedCols = NULL; /* * 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; }
RangeTblEntry* addRangeTableEntryForCTE | ( | ParseState * | pstate, | |
CommonTableExpr * | cte, | |||
Index | levelsup, | |||
RangeVar * | rv, | |||
bool | inFromCl | |||
) |
Definition at line 1454 of file parse_relation.c.
References RangeTblEntry::alias, RangeVar::alias, Alias::aliasname, Assert, RangeTblEntry::checkAsUser, CMD_SELECT, Alias::colnames, Query::commandType, copyObject(), CommonTableExpr::ctecolcollations, RangeTblEntry::ctecolcollations, CommonTableExpr::ctecolnames, CommonTableExpr::ctecoltypes, RangeTblEntry::ctecoltypes, CommonTableExpr::ctecoltypmods, RangeTblEntry::ctecoltypmods, RangeTblEntry::ctelevelsup, RangeTblEntry::ctename, CommonTableExpr::ctename, CommonTableExpr::ctequery, CommonTableExpr::cterecursive, CommonTableExpr::cterefcount, RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, RangeTblEntry::inFromCl, RangeTblEntry::inh, IsA, lappend(), RangeTblEntry::lateral, lfirst, list_length(), RangeVar::location, makeAlias(), makeNode, RangeTblEntry::modifiedCols, NIL, NULL, ParseState::p_rtable, parser_errposition(), RangeTblEntry::requiredPerms, Query::returningList, RangeTblEntry::rtekind, RangeTblEntry::selectedCols, and RangeTblEntry::self_reference.
Referenced by transformCTEReference().
{ RangeTblEntry *rte = makeNode(RangeTblEntry); Alias *alias = rv->alias; char *refname = alias ? alias->aliasname : cte->ctename; Alias *eref; int numaliases; int varattno; ListCell *lc; rte->rtekind = RTE_CTE; rte->ctename = cte->ctename; rte->ctelevelsup = levelsup; /* Self-reference if and only if CTE's parse analysis isn't completed */ rte->self_reference = !IsA(cte->ctequery, Query); Assert(cte->cterecursive || !rte->self_reference); /* Bump the CTE's refcount if this isn't a self-reference */ if (!rte->self_reference) cte->cterefcount++; /* * We throw error if the CTE is INSERT/UPDATE/DELETE without RETURNING. * This won't get checked in case of a self-reference, but that's OK * because data-modifying CTEs aren't allowed to be recursive anyhow. */ if (IsA(cte->ctequery, Query)) { Query *ctequery = (Query *) cte->ctequery; if (ctequery->commandType != CMD_SELECT && ctequery->returningList == NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("WITH query \"%s\" does not have a RETURNING clause", cte->ctename), parser_errposition(pstate, rv->location))); } rte->ctecoltypes = cte->ctecoltypes; rte->ctecoltypmods = cte->ctecoltypmods; rte->ctecolcollations = cte->ctecolcollations; rte->alias = alias; if (alias) eref = copyObject(alias); else eref = makeAlias(refname, NIL); numaliases = list_length(eref->colnames); /* fill in any unspecified alias columns */ varattno = 0; foreach(lc, cte->ctecolnames) { varattno++; if (varattno > numaliases) eref->colnames = lappend(eref->colnames, lfirst(lc)); } if (varattno < numaliases) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("table \"%s\" has %d columns available but %d columns specified", refname, varattno, numaliases))); rte->eref = eref; /* * Set flags and access permissions. * * Subqueries are never checked for access rights. */ rte->lateral = false; rte->inh = false; /* never true for subqueries */ rte->inFromCl = inFromCl; rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; rte->selectedCols = NULL; rte->modifiedCols = NULL; /* * 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; }
RangeTblEntry* addRangeTableEntryForFunction | ( | ParseState * | pstate, | |
char * | funcname, | |||
Node * | funcexpr, | |||
RangeFunction * | rangefunc, | |||
bool | lateral, | |||
bool | inFromCl | |||
) |
Definition at line 1177 of file parse_relation.c.
References RangeTblEntry::alias, RangeFunction::alias, Alias::aliasname, Assert, buildRelationAliases(), buildScalarFunctionAlias(), RangeTblEntry::checkAsUser, RangeFunction::coldeflist, ColumnDef::colname, Alias::colnames, RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, exprLocation(), format_type_be(), RangeTblEntry::funccolcollations, RangeTblEntry::funccoltypes, RangeTblEntry::funccoltypmods, RangeTblEntry::funcexpr, get_expr_result_type(), GetColumnDefCollation(), RangeTblEntry::inFromCl, RangeTblEntry::inh, lappend(), lappend_int(), lappend_oid(), RangeTblEntry::lateral, lfirst, TypeName::location, makeAlias(), makeNode, makeString(), RangeTblEntry::modifiedCols, NIL, NULL, ParseState::p_rtable, parser_errposition(), pstrdup(), RangeTblEntry::relid, RangeTblEntry::requiredPerms, RangeTblEntry::rtekind, RangeTblEntry::selectedCols, TypeName::setof, RangeTblEntry::subquery, TYPEFUNC_COMPOSITE, TYPEFUNC_RECORD, TYPEFUNC_SCALAR, ColumnDef::typeName, and typenameTypeIdAndMod().
Referenced by transformRangeFunction().
{ RangeTblEntry *rte = makeNode(RangeTblEntry); TypeFuncClass functypclass; Oid funcrettype; TupleDesc tupdesc; Alias *alias = rangefunc->alias; List *coldeflist = rangefunc->coldeflist; Alias *eref; rte->rtekind = RTE_FUNCTION; rte->relid = InvalidOid; rte->subquery = NULL; rte->funcexpr = funcexpr; rte->funccoltypes = NIL; rte->funccoltypmods = NIL; rte->funccolcollations = NIL; rte->alias = alias; eref = makeAlias(alias ? alias->aliasname : funcname, NIL); rte->eref = eref; /* * Now determine if the function returns a simple or composite type. */ functypclass = get_expr_result_type(funcexpr, &funcrettype, &tupdesc); /* * A coldeflist is required if the function returns RECORD and hasn't got * a predetermined record type, and is prohibited otherwise. */ if (coldeflist != NIL) { if (functypclass != TYPEFUNC_RECORD) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("a column definition list is only allowed for functions returning \"record\""), parser_errposition(pstate, exprLocation(funcexpr)))); } else { if (functypclass == TYPEFUNC_RECORD) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("a column definition list is required for functions returning \"record\""), parser_errposition(pstate, exprLocation(funcexpr)))); } if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ Assert(tupdesc); /* Build the column alias list */ buildRelationAliases(tupdesc, alias, eref); } else if (functypclass == TYPEFUNC_SCALAR) { /* Base data type, i.e. scalar */ buildScalarFunctionAlias(funcexpr, funcname, alias, eref); } else if (functypclass == TYPEFUNC_RECORD) { ListCell *col; /* * Use the column definition list to form the alias list and * funccoltypes/funccoltypmods/funccolcollations lists. */ foreach(col, coldeflist) { ColumnDef *n = (ColumnDef *) lfirst(col); char *attrname; Oid attrtype; int32 attrtypmod; Oid attrcollation; attrname = pstrdup(n->colname); if (n->typeName->setof) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" cannot be declared SETOF", attrname), parser_errposition(pstate, n->typeName->location))); typenameTypeIdAndMod(pstate, n->typeName, &attrtype, &attrtypmod); attrcollation = GetColumnDefCollation(pstate, n, attrtype); eref->colnames = lappend(eref->colnames, makeString(attrname)); rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype); rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod); rte->funccolcollations = lappend_oid(rte->funccolcollations, attrcollation); } } else ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("function \"%s\" in FROM has unsupported return type %s", funcname, format_type_be(funcrettype)), parser_errposition(pstate, exprLocation(funcexpr)))); /* * Set flags and access permissions. * * Functions are never checked for access rights (at least, not by the RTE * permissions mechanism). */ rte->lateral = lateral; rte->inh = false; /* never true for functions */ rte->inFromCl = inFromCl; rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; rte->selectedCols = NULL; rte->modifiedCols = NULL; /* * 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; }
RangeTblEntry* addRangeTableEntryForJoin | ( | ParseState * | pstate, | |
List * | colnames, | |||
JoinType | jointype, | |||
List * | aliasvars, | |||
Alias * | alias, | |||
bool | inFromCl | |||
) |
Definition at line 1386 of file parse_relation.c.
References RangeTblEntry::alias, RangeTblEntry::checkAsUser, Alias::colnames, copyObject(), RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, RangeTblEntry::inFromCl, RangeTblEntry::inh, RangeTblEntry::joinaliasvars, RangeTblEntry::jointype, lappend(), RangeTblEntry::lateral, list_concat(), list_copy_tail(), list_length(), makeAlias(), makeNode, MaxAttrNumber, RangeTblEntry::modifiedCols, NIL, NULL, ParseState::p_rtable, RangeTblEntry::relid, RangeTblEntry::requiredPerms, RangeTblEntry::rtekind, RangeTblEntry::selectedCols, and RangeTblEntry::subquery.
Referenced by transformFromClauseItem(), and transformSetOperationStmt().
{ RangeTblEntry *rte = makeNode(RangeTblEntry); Alias *eref; int numaliases; /* * Fail if join has too many columns --- we must be able to reference any * of the columns with an AttrNumber. */ if (list_length(aliasvars) > MaxAttrNumber) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("joins can have at most %d columns", MaxAttrNumber))); rte->rtekind = RTE_JOIN; rte->relid = InvalidOid; rte->subquery = NULL; rte->jointype = jointype; rte->joinaliasvars = aliasvars; rte->alias = alias; eref = alias ? (Alias *) copyObject(alias) : makeAlias("unnamed_join", NIL); numaliases = list_length(eref->colnames); /* fill in any unspecified alias columns */ if (numaliases < list_length(colnames)) eref->colnames = list_concat(eref->colnames, list_copy_tail(colnames, numaliases)); rte->eref = eref; /* * Set flags and access permissions. * * Joins are never checked for access rights. */ rte->lateral = false; rte->inh = false; /* never true for joins */ rte->inFromCl = inFromCl; rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; rte->selectedCols = NULL; rte->modifiedCols = NULL; /* * 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; }
RangeTblEntry* addRangeTableEntryForRelation | ( | ParseState * | pstate, | |
Relation | rel, | |||
Alias * | alias, | |||
bool | inh, | |||
bool | inFromCl | |||
) |
Definition at line 1047 of file parse_relation.c.
References RangeTblEntry::alias, Alias::aliasname, buildRelationAliases(), RangeTblEntry::checkAsUser, RangeTblEntry::eref, RangeTblEntry::inFromCl, RangeTblEntry::inh, lappend(), RangeTblEntry::lateral, makeAlias(), makeNode, RangeTblEntry::modifiedCols, NIL, NULL, ParseState::p_rtable, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::requiredPerms, RangeTblEntry::rtekind, and RangeTblEntry::selectedCols.
Referenced by AddRelationNewConstraints(), ATPrepAlterColumnType(), CreateTrigger(), setTargetTable(), transformRuleStmt(), and UpdateRangeTableOfViewParse().
{ RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias ? alias->aliasname : RelationGetRelationName(rel); rte->rtekind = RTE_RELATION; rte->alias = alias; rte->relid = RelationGetRelid(rel); rte->relkind = rel->rd_rel->relkind; /* * Build the list of effective column names using user-supplied aliases * and/or actual column names. */ rte->eref = makeAlias(refname, NIL); buildRelationAliases(rel->rd_att, alias, rte->eref); /* * Set flags and access permissions. * * The initial default on access checks is always check-for-READ-access, * which is the right thing for all except target tables. */ rte->lateral = false; rte->inh = inh; rte->inFromCl = inFromCl; rte->requiredPerms = ACL_SELECT; rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ rte->selectedCols = NULL; rte->modifiedCols = NULL; /* * 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; }
RangeTblEntry* addRangeTableEntryForSubquery | ( | ParseState * | pstate, | |
Query * | subquery, | |||
Alias * | alias, | |||
bool | lateral, | |||
bool | inFromCl | |||
) |
Definition at line 1100 of file parse_relation.c.
References RangeTblEntry::alias, Alias::aliasname, Assert, RangeTblEntry::checkAsUser, Alias::colnames, copyObject(), RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, RangeTblEntry::inFromCl, RangeTblEntry::inh, lappend(), RangeTblEntry::lateral, lfirst, list_length(), makeNode, makeString(), RangeTblEntry::modifiedCols, NULL, ParseState::p_rtable, pstrdup(), RangeTblEntry::relid, RangeTblEntry::requiredPerms, TargetEntry::resjunk, TargetEntry::resname, TargetEntry::resno, RangeTblEntry::rtekind, RangeTblEntry::selectedCols, RangeTblEntry::subquery, and Query::targetList.
Referenced by convert_ANY_sublink_to_join(), transformInsertStmt(), transformRangeSubselect(), and transformSetOperationTree().
{ RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias->aliasname; Alias *eref; int numaliases; int varattno; ListCell *tlistitem; rte->rtekind = RTE_SUBQUERY; rte->relid = InvalidOid; rte->subquery = subquery; rte->alias = alias; eref = copyObject(alias); numaliases = list_length(eref->colnames); /* fill in any unspecified alias columns */ varattno = 0; foreach(tlistitem, subquery->targetList) { TargetEntry *te = (TargetEntry *) lfirst(tlistitem); if (te->resjunk) continue; varattno++; Assert(varattno == te->resno); if (varattno > numaliases) { char *attrname; attrname = pstrdup(te->resname); eref->colnames = lappend(eref->colnames, makeString(attrname)); } } if (varattno < numaliases) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("table \"%s\" has %d columns available but %d columns specified", refname, varattno, numaliases))); rte->eref = eref; /* * Set flags and access permissions. * * Subqueries are never checked for access rights. */ rte->lateral = lateral; rte->inh = false; /* never true for subqueries */ rte->inFromCl = inFromCl; rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; rte->selectedCols = NULL; rte->modifiedCols = NULL; /* * 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; }
RangeTblEntry* addRangeTableEntryForValues | ( | ParseState * | pstate, | |
List * | exprs, | |||
List * | collations, | |||
Alias * | alias, | |||
bool | lateral, | |||
bool | inFromCl | |||
) |
Definition at line 1314 of file parse_relation.c.
References RangeTblEntry::alias, Alias::aliasname, RangeTblEntry::checkAsUser, Alias::colnames, copyObject(), RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, RangeTblEntry::inFromCl, RangeTblEntry::inh, lappend(), RangeTblEntry::lateral, linitial, list_length(), makeAlias(), makeNode, makeString(), RangeTblEntry::modifiedCols, NIL, NULL, ParseState::p_rtable, pstrdup(), RangeTblEntry::relid, RangeTblEntry::requiredPerms, RangeTblEntry::rtekind, RangeTblEntry::selectedCols, snprintf(), RangeTblEntry::subquery, RangeTblEntry::values_collations, and RangeTblEntry::values_lists.
Referenced by transformValuesClause().
{ RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias ? alias->aliasname : pstrdup("*VALUES*"); Alias *eref; int numaliases; int numcolumns; rte->rtekind = RTE_VALUES; rte->relid = InvalidOid; rte->subquery = NULL; rte->values_lists = exprs; rte->values_collations = collations; rte->alias = alias; eref = alias ? copyObject(alias) : makeAlias(refname, NIL); /* fill in any unspecified alias columns */ numcolumns = list_length((List *) linitial(exprs)); numaliases = list_length(eref->colnames); while (numaliases < numcolumns) { char attrname[64]; numaliases++; snprintf(attrname, sizeof(attrname), "column%d", numaliases); eref->colnames = lappend(eref->colnames, makeString(pstrdup(attrname))); } if (numcolumns < numaliases) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("VALUES lists \"%s\" have %d columns available but %d columns specified", refname, numcolumns, numaliases))); rte->eref = eref; /* * Set flags and access permissions. * * Subqueries are never checked for access rights. */ rte->lateral = lateral; rte->inh = false; /* never true for values RTEs */ rte->inFromCl = inFromCl; rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; rte->selectedCols = NULL; rte->modifiedCols = NULL; /* * 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; }
void addRTEtoQuery | ( | ParseState * | pstate, | |
RangeTblEntry * | rte, | |||
bool | addToJoinList, | |||
bool | addToRelNameSpace, | |||
bool | addToVarNameSpace | |||
) |
Definition at line 1603 of file parse_relation.c.
References lappend(), makeNode, NULL, ParseNamespaceItem::p_cols_visible, ParseState::p_joinlist, ParseNamespaceItem::p_lateral_ok, ParseNamespaceItem::p_lateral_only, ParseState::p_namespace, ParseNamespaceItem::p_rel_visible, ParseNamespaceItem::p_rte, palloc(), RTERangeTablePosn(), and RangeTblRef::rtindex.
Referenced by AddRelationNewConstraints(), ATPrepAlterColumnType(), CreateTrigger(), setTargetTable(), transformIndexStmt(), transformRuleStmt(), transformSetOperationStmt(), and transformValuesClause().
{ if (addToJoinList) { int rtindex = RTERangeTablePosn(pstate, rte, NULL); RangeTblRef *rtr = makeNode(RangeTblRef); rtr->rtindex = 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_rel_visible = addToRelNameSpace; nsitem->p_cols_visible = addToVarNameSpace; nsitem->p_lateral_only = false; nsitem->p_lateral_ok = true; pstate->p_namespace = lappend(pstate->p_namespace, nsitem); } }
Definition at line 2415 of file parse_relation.c.
References tupleDesc::attrs, i, InvalidAttrNumber, namestrcmp(), ObjectIdAttributeNumber, RelationData::rd_att, RelationData::rd_rel, and specialAttNum().
Referenced by checkInsertTargets(), CreateTrigger(), do_analyze_rel(), and transformUpdateStmt().
{ int i; for (i = 0; i < rd->rd_rel->relnatts; i++) { Form_pg_attribute att = rd->rd_att->attrs[i]; if (namestrcmp(&(att->attname), attname) == 0 && !att->attisdropped) return i + 1; } if (sysColOK) { if ((i = specialAttNum(attname)) != InvalidAttrNumber) { if (i != ObjectIdAttributeNumber || rd->rd_rel->relhasoids) return i; } } /* on failure */ return InvalidAttrNumber; }
Definition at line 2470 of file parse_relation.c.
References tupleDesc::attrs, elog, ERROR, tupleDesc::natts, RelationData::rd_att, RelationData::rd_rel, and SystemAttributeDefinition().
Referenced by transformFkeyGetPrimaryKey().
{ if (attid <= 0) { Form_pg_attribute sysatt; sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids); return &sysatt->attname; } if (attid > rd->rd_att->natts) elog(ERROR, "invalid attribute number %d", attid); return &rd->rd_att->attrs[attid - 1]->attname; }
Definition at line 2512 of file parse_relation.c.
References tupleDesc::attrs, elog, ERROR, tupleDesc::natts, and RelationData::rd_att.
Definition at line 2492 of file parse_relation.c.
References tupleDesc::attrs, elog, ERROR, tupleDesc::natts, RelationData::rd_att, RelationData::rd_rel, and SystemAttributeDefinition().
Referenced by transformAssignedExpr(), and transformFkeyGetPrimaryKey().
{ if (attid <= 0) { Form_pg_attribute sysatt; sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids); return sysatt->atttypid; } if (attid > rd->rd_att->natts) elog(ERROR, "invalid attribute number %d", attid); return rd->rd_att->attrs[attid - 1]->atttypid; }
Definition at line 800 of file parse_relation.c.
References Alias::aliasname, Assert, tupleDesc::attrs, Alias::colnames, ereport, errcode(), errmsg(), ERROR, lappend(), lfirst, list_head(), list_length(), lnext, makeString(), NameStr, tupleDesc::natts, NIL, and pstrdup().
Referenced by addRangeTableEntry(), addRangeTableEntryForFunction(), and addRangeTableEntryForRelation().
{ int maxattrs = tupdesc->natts; ListCell *aliaslc; int numaliases; int varattno; int numdropped = 0; Assert(eref->colnames == NIL); if (alias) { aliaslc = list_head(alias->colnames); numaliases = list_length(alias->colnames); /* We'll rebuild the alias colname list */ alias->colnames = NIL; } else { aliaslc = NULL; numaliases = 0; } for (varattno = 0; varattno < maxattrs; varattno++) { Form_pg_attribute attr = tupdesc->attrs[varattno]; Value *attrname; if (attr->attisdropped) { /* Always insert an empty string for a dropped column */ attrname = makeString(pstrdup("")); if (aliaslc) alias->colnames = lappend(alias->colnames, attrname); numdropped++; } else if (aliaslc) { /* Use the next user-supplied alias */ attrname = (Value *) lfirst(aliaslc); aliaslc = lnext(aliaslc); alias->colnames = lappend(alias->colnames, attrname); } else { attrname = makeString(pstrdup(NameStr(attr->attname))); /* we're done with the alias if any */ } eref->colnames = lappend(eref->colnames, attrname); } /* Too many user-supplied aliases? */ if (aliaslc) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("table \"%s\" has %d columns available but %d columns specified", eref->aliasname, maxattrs - numdropped, numaliases))); }
static void buildScalarFunctionAlias | ( | Node * | funcexpr, | |
char * | funcname, | |||
Alias * | alias, | |||
Alias * | eref | |||
) | [static] |
Definition at line 873 of file parse_relation.c.
References Alias::aliasname, Assert, Alias::colnames, copyObject(), ereport, errcode(), errmsg(), ERROR, get_func_result_name(), IsA, list_length(), list_make1, makeString(), and NIL.
Referenced by addRangeTableEntryForFunction().
{ char *pname; Assert(eref->colnames == NIL); /* Use user-specified column alias if there is one. */ if (alias && alias->colnames != NIL) { if (list_length(alias->colnames) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("too many column aliases specified for function %s", funcname))); eref->colnames = copyObject(alias->colnames); return; } /* * If the expression is a simple function call, and the function has a * single OUT parameter that is named, use the parameter's name. */ if (funcexpr && IsA(funcexpr, FuncExpr)) { pname = get_func_result_name(((FuncExpr *) funcexpr)->funcid); if (pname) { eref->colnames = list_make1(makeString(pname)); return; } } /* * Otherwise use the previously-determined alias (not necessarily the * function name!) */ eref->colnames = list_make1(makeString(eref->aliasname)); }
void checkNameSpaceConflicts | ( | ParseState * | pstate, | |
List * | namespace1, | |||
List * | namespace2 | |||
) |
Definition at line 365 of file parse_relation.c.
References RangeTblEntry::alias, Alias::aliasname, RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, lfirst, NULL, ParseNamespaceItem::p_rel_visible, ParseNamespaceItem::p_rte, RangeTblEntry::relid, RTE_RELATION, and RangeTblEntry::rtekind.
Referenced by transformFromClause(), and transformFromClauseItem().
{ ListCell *l1; foreach(l1, namespace1) { ParseNamespaceItem *nsitem1 = (ParseNamespaceItem *) lfirst(l1); RangeTblEntry *rte1 = nsitem1->p_rte; const char *aliasname1 = rte1->eref->aliasname; ListCell *l2; if (!nsitem1->p_rel_visible) continue; foreach(l2, namespace2) { ParseNamespaceItem *nsitem2 = (ParseNamespaceItem *) lfirst(l2); RangeTblEntry *rte2 = nsitem2->p_rte; if (!nsitem2->p_rel_visible) continue; if (strcmp(rte2->eref->aliasname, aliasname1) != 0) continue; /* definitely no conflict */ if (rte1->rtekind == RTE_RELATION && rte1->alias == NULL && rte2->rtekind == RTE_RELATION && rte2->alias == NULL && rte1->relid != rte2->relid) continue; /* no conflict per SQL rule */ ereport(ERROR, (errcode(ERRCODE_DUPLICATE_ALIAS), errmsg("table name \"%s\" specified more than once", aliasname1))); } } }
Node* colNameToVar | ( | ParseState * | pstate, | |
char * | colname, | |||
bool | localonly, | |||
int | location | |||
) |
Definition at line 580 of file parse_relation.c.
References Alias::aliasname, RangeTblEntry::eref, ereport, errcode(), errdetail(), errmsg(), ERROR, lfirst, NULL, ParseNamespaceItem::p_cols_visible, ParseState::p_lateral_active, ParseNamespaceItem::p_lateral_ok, ParseNamespaceItem::p_lateral_only, ParseState::p_namespace, ParseNamespaceItem::p_rte, ParseState::parentParseState, parser_errposition(), and scanRTEForColumn().
Referenced by findTargetlistEntrySQL92(), and transformColumnRef().
{ Node *result = NULL; ParseState *orig_pstate = pstate; while (pstate != NULL) { ListCell *l; foreach(l, pstate->p_namespace) { ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l); RangeTblEntry *rte = nsitem->p_rte; Node *newresult; /* Ignore table-only items */ if (!nsitem->p_cols_visible) continue; /* If not inside LATERAL, ignore lateral-only items */ if (nsitem->p_lateral_only && !pstate->p_lateral_active) continue; /* use orig_pstate here to get the right sublevels_up */ newresult = scanRTEForColumn(orig_pstate, rte, colname, location); if (newresult) { if (result) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_COLUMN), errmsg("column reference \"%s\" is ambiguous", colname), parser_errposition(orig_pstate, location))); /* SQL:2008 demands this be an error, not an invisible item */ if (nsitem->p_lateral_only && !nsitem->p_lateral_ok) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("invalid reference to FROM-clause entry for table \"%s\"", rte->eref->aliasname), errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."), parser_errposition(orig_pstate, location))); result = newresult; } } if (result != NULL || localonly) break; /* found, or don't want to look at parent */ pstate = pstate->parentParseState; } return result; }
void errorMissingColumn | ( | ParseState * | pstate, | |
char * | relname, | |||
char * | colname, | |||
int | location | |||
) |
Definition at line 2587 of file parse_relation.c.
References Alias::aliasname, RangeTblEntry::eref, ereport, errcode(), errhint(), errmsg(), ERROR, parser_errposition(), and searchRangeTableForCol().
Referenced by transformColumnRef().
{ RangeTblEntry *rte; /* * If relname was given, just play dumb and report it. (In practice, a * bad qualification name should end up at errorMissingRTE, not here, so * no need to work hard on this case.) */ if (relname) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column %s.%s does not exist", relname, colname), parser_errposition(pstate, location))); /* * Otherwise, search the entire rtable looking for possible matches. If * we find one, emit a hint about it. * * TODO: improve this code (and also errorMissingRTE) to mention using * LATERAL if appropriate. */ rte = searchRangeTableForCol(pstate, colname, location); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" does not exist", colname), rte ? errhint("There is a column named \"%s\" in table \"%s\", but it cannot be referenced from this part of the query.", colname, rte->eref->aliasname) : 0, parser_errposition(pstate, location))); }
void errorMissingRTE | ( | ParseState * | pstate, | |
RangeVar * | relation | |||
) |
Definition at line 2531 of file parse_relation.c.
References RangeTblEntry::alias, Alias::aliasname, RangeTblEntry::eref, ereport, errcode(), errhint(), errmsg(), ERROR, RangeVar::location, NULL, parser_errposition(), refnameRangeTblEntry(), RangeVar::relname, and searchRangeTableForRel().
Referenced by ExpandColumnRefStar(), and transformColumnRef().
{ RangeTblEntry *rte; int sublevels_up; const char *badAlias = NULL; /* * Check to see if there are any potential matches in the query's * rangetable. (Note: cases involving a bad schema name in the RangeVar * will throw error immediately here. That seems OK.) */ rte = searchRangeTableForRel(pstate, relation); /* * If we found a match that has an alias and the alias is visible in the * namespace, then the problem is probably use of the relation's real name * instead of its alias, ie "SELECT foo.* FROM foo f". This mistake is * common enough to justify a specific hint. * * If we found a match that doesn't meet those criteria, assume the * problem is illegal use of a relation outside its scope, as in the * MySQL-ism "SELECT ... FROM a, b LEFT JOIN c ON (a.x = c.y)". */ if (rte && rte->alias && strcmp(rte->eref->aliasname, relation->relname) != 0 && refnameRangeTblEntry(pstate, NULL, rte->eref->aliasname, relation->location, &sublevels_up) == rte) badAlias = rte->eref->aliasname; if (rte) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("invalid reference to FROM-clause entry for table \"%s\"", relation->relname), (badAlias ? errhint("Perhaps you meant to reference the table alias \"%s\".", badAlias) : errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.", rte->eref->aliasname)), parser_errposition(pstate, relation->location))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("missing FROM-clause entry for table \"%s\"", relation->relname), parser_errposition(pstate, relation->location))); }
static void expandRelation | ( | Oid | relid, | |
Alias * | eref, | |||
int | rtindex, | |||
int | sublevels_up, | |||
int | location, | |||
bool | include_dropped, | |||
List ** | colnames, | |||
List ** | colvars | |||
) | [static] |
Definition at line 1933 of file parse_relation.c.
References AccessShareLock, expandTupleDesc(), RelationData::rd_att, relation_close(), and relation_open().
Referenced by expandRTE().
{ Relation rel; /* Get the tupledesc and turn it over to expandTupleDesc */ rel = relation_open(relid, AccessShareLock); expandTupleDesc(rel->rd_att, eref, rtindex, sublevels_up, location, include_dropped, colnames, colvars); relation_close(rel, AccessShareLock); }
List* expandRelAttrs | ( | ParseState * | pstate, | |
RangeTblEntry * | rte, | |||
int | rtindex, | |||
int | sublevels_up, | |||
int | location | |||
) |
Definition at line 2020 of file parse_relation.c.
References Assert, expandRTE(), forboth, label, lappend(), lfirst, makeTargetEntry(), markVarForSelectPriv(), name, NULL, ParseState::p_next_resno, RangeTblEntry::requiredPerms, and strVal.
Referenced by ExpandAllTables(), ExpandSingleTable(), and transformValuesClause().
{ List *names, *vars; ListCell *name, *var; List *te_list = NIL; expandRTE(rte, rtindex, sublevels_up, location, false, &names, &vars); /* * Require read access to the table. This is normally redundant with the * markVarForSelectPriv calls below, but not if the table has zero * columns. */ rte->requiredPerms |= ACL_SELECT; forboth(name, names, var, vars) { char *label = strVal(lfirst(name)); Var *varnode = (Var *) lfirst(var); TargetEntry *te; te = makeTargetEntry((Expr *) varnode, (AttrNumber) pstate->p_next_resno++, label, false); te_list = lappend(te_list, te); /* Require read access to each column */ markVarForSelectPriv(pstate, varnode, rte); } Assert(name == NULL && var == NULL); /* lists not the same length? */ return te_list; }
void expandRTE | ( | RangeTblEntry * | rte, | |
int | rtindex, | |||
int | sublevels_up, | |||
int | location, | |||
bool | include_dropped, | |||
List ** | colnames, | |||
List ** | colvars | |||
) |
Definition at line 1647 of file parse_relation.c.
References Assert, Alias::colnames, copyObject(), RangeTblEntry::ctecolcollations, RangeTblEntry::ctecoltypes, RangeTblEntry::ctecoltypmods, elog, RangeTblEntry::eref, ERROR, expandRelation(), expandTupleDesc(), TargetEntry::expr, exprCollation(), exprType(), exprTypmod(), forboth, forthree, RangeTblEntry::funccolcollations, RangeTblEntry::funccoltypes, RangeTblEntry::funccoltypmods, RangeTblEntry::funcexpr, get_expr_result_type(), IsA, RangeTblEntry::joinaliasvars, label, lappend(), lfirst, lfirst_int, lfirst_oid, linitial, list_head(), list_length(), lnext, Var::location, makeString(), makeVar(), pstrdup(), RangeTblEntry::relid, TargetEntry::resjunk, TargetEntry::resno, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, strVal, RangeTblEntry::subquery, Query::targetList, TYPEFUNC_COMPOSITE, TYPEFUNC_RECORD, TYPEFUNC_SCALAR, RangeTblEntry::values_collations, and RangeTblEntry::values_lists.
Referenced by build_physical_tlist(), coerce_record_to_complex(), expandRecordVariable(), expandRelAttrs(), ExpandSingleTable(), pullup_replace_vars_callback(), ReplaceVarsFromTargetList_callback(), and transformFromClauseItem().
{ int varattno; if (colnames) *colnames = NIL; if (colvars) *colvars = NIL; switch (rte->rtekind) { case RTE_RELATION: /* Ordinary relation RTE */ expandRelation(rte->relid, rte->eref, rtindex, sublevels_up, location, include_dropped, colnames, colvars); break; case RTE_SUBQUERY: { /* Subquery RTE */ ListCell *aliasp_item = list_head(rte->eref->colnames); ListCell *tlistitem; varattno = 0; foreach(tlistitem, rte->subquery->targetList) { TargetEntry *te = (TargetEntry *) lfirst(tlistitem); if (te->resjunk) continue; varattno++; Assert(varattno == te->resno); if (colnames) { /* Assume there is one alias per target item */ char *label = strVal(lfirst(aliasp_item)); *colnames = lappend(*colnames, makeString(pstrdup(label))); aliasp_item = lnext(aliasp_item); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, varattno, exprType((Node *) te->expr), exprTypmod((Node *) te->expr), exprCollation((Node *) te->expr), sublevels_up); varnode->location = location; *colvars = lappend(*colvars, varnode); } } } break; case RTE_FUNCTION: { /* Function RTE */ TypeFuncClass functypclass; Oid funcrettype; TupleDesc tupdesc; functypclass = get_expr_result_type(rte->funcexpr, &funcrettype, &tupdesc); if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ Assert(tupdesc); expandTupleDesc(tupdesc, rte->eref, rtindex, sublevels_up, location, include_dropped, colnames, colvars); } else if (functypclass == TYPEFUNC_SCALAR) { /* Base data type, i.e. scalar */ if (colnames) *colnames = lappend(*colnames, linitial(rte->eref->colnames)); if (colvars) { Var *varnode; varnode = makeVar(rtindex, 1, funcrettype, -1, exprCollation(rte->funcexpr), sublevels_up); varnode->location = location; *colvars = lappend(*colvars, varnode); } } else if (functypclass == TYPEFUNC_RECORD) { if (colnames) *colnames = copyObject(rte->eref->colnames); if (colvars) { ListCell *l1; ListCell *l2; ListCell *l3; int attnum = 0; forthree(l1, rte->funccoltypes, l2, rte->funccoltypmods, l3, rte->funccolcollations) { Oid attrtype = lfirst_oid(l1); int32 attrtypmod = lfirst_int(l2); Oid attrcollation = lfirst_oid(l3); Var *varnode; attnum++; varnode = makeVar(rtindex, attnum, attrtype, attrtypmod, attrcollation, sublevels_up); varnode->location = location; *colvars = lappend(*colvars, varnode); } } } else { /* addRangeTableEntryForFunction should've caught this */ elog(ERROR, "function in FROM has unsupported return type"); } } break; case RTE_VALUES: { /* Values RTE */ ListCell *aliasp_item = list_head(rte->eref->colnames); ListCell *lcv; ListCell *lcc; varattno = 0; forboth(lcv, (List *) linitial(rte->values_lists), lcc, rte->values_collations) { Node *col = (Node *) lfirst(lcv); Oid colcollation = lfirst_oid(lcc); varattno++; if (colnames) { /* Assume there is one alias per column */ char *label = strVal(lfirst(aliasp_item)); *colnames = lappend(*colnames, makeString(pstrdup(label))); aliasp_item = lnext(aliasp_item); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, varattno, exprType(col), exprTypmod(col), colcollation, sublevels_up); varnode->location = location; *colvars = lappend(*colvars, varnode); } } } break; case RTE_JOIN: { /* Join RTE */ ListCell *colname; ListCell *aliasvar; Assert(list_length(rte->eref->colnames) == list_length(rte->joinaliasvars)); varattno = 0; forboth(colname, rte->eref->colnames, aliasvar, rte->joinaliasvars) { Node *avar = (Node *) lfirst(aliasvar); varattno++; /* * During ordinary parsing, there will never be any * deleted columns in the join; but we have to check since * this routine is also used by the rewriter, and joins * found in stored rules might have join columns for * since-deleted columns. This will be signaled by a NULL * Const in the alias-vars list. */ if (IsA(avar, Const)) { if (include_dropped) { if (colnames) *colnames = lappend(*colnames, makeString(pstrdup(""))); if (colvars) *colvars = lappend(*colvars, copyObject(avar)); } continue; } if (colnames) { char *label = strVal(lfirst(colname)); *colnames = lappend(*colnames, makeString(pstrdup(label))); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, varattno, exprType(avar), exprTypmod(avar), exprCollation(avar), sublevels_up); varnode->location = location; *colvars = lappend(*colvars, varnode); } } } break; case RTE_CTE: { ListCell *aliasp_item = list_head(rte->eref->colnames); ListCell *lct; ListCell *lcm; ListCell *lcc; varattno = 0; forthree(lct, rte->ctecoltypes, lcm, rte->ctecoltypmods, lcc, rte->ctecolcollations) { Oid coltype = lfirst_oid(lct); int32 coltypmod = lfirst_int(lcm); Oid colcoll = lfirst_oid(lcc); varattno++; if (colnames) { /* Assume there is one alias per output column */ char *label = strVal(lfirst(aliasp_item)); *colnames = lappend(*colnames, makeString(pstrdup(label))); aliasp_item = lnext(aliasp_item); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, varattno, coltype, coltypmod, colcoll, sublevels_up); *colvars = lappend(*colvars, varnode); } } } break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); } }
static void expandTupleDesc | ( | TupleDesc | tupdesc, | |
Alias * | eref, | |||
int | rtindex, | |||
int | sublevels_up, | |||
int | location, | |||
bool | include_dropped, | |||
List ** | colnames, | |||
List ** | colvars | |||
) | [static] |
Definition at line 1951 of file parse_relation.c.
References tupleDesc::attrs, Alias::colnames, INT4OID, InvalidOid, label, lappend(), list_length(), list_nth(), Var::location, makeNullConst(), makeString(), makeVar(), NameStr, tupleDesc::natts, pstrdup(), and strVal.
Referenced by expandRelation(), and expandRTE().
{ int maxattrs = tupdesc->natts; int numaliases = list_length(eref->colnames); int varattno; for (varattno = 0; varattno < maxattrs; varattno++) { Form_pg_attribute attr = tupdesc->attrs[varattno]; if (attr->attisdropped) { if (include_dropped) { if (colnames) *colnames = lappend(*colnames, makeString(pstrdup(""))); if (colvars) { /* * can't use atttypid here, but it doesn't really matter * what type the Const claims to be. */ *colvars = lappend(*colvars, makeNullConst(INT4OID, -1, InvalidOid)); } } continue; } if (colnames) { char *label; if (varattno < numaliases) label = strVal(list_nth(eref->colnames, varattno)); else label = NameStr(attr->attname); *colnames = lappend(*colnames, makeString(pstrdup(label))); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, attr->attnum, attr->atttypid, attr->atttypmod, attr->attcollation, sublevels_up); varnode->location = location; *colvars = lappend(*colvars, varnode); } } }
RowMarkClause* get_parse_rowmark | ( | Query * | qry, | |
Index | rtindex | |||
) |
Definition at line 2391 of file parse_relation.c.
References lfirst, Query::rowMarks, and RowMarkClause::rti.
Referenced by AcquireRewriteLocks(), applyLockingClause(), ApplyRetrieveRule(), create_indexscan_plan(), fireRIRrules(), postgresGetForeignPlan(), and ScanQueryForLocks().
{ ListCell *l; foreach(l, qry->rowMarks) { RowMarkClause *rc = (RowMarkClause *) lfirst(l); if (rc->rti == rtindex) return rc; } return NULL; }
bool get_rte_attribute_is_dropped | ( | RangeTblEntry * | rte, | |
AttrNumber | attnum | |||
) |
Definition at line 2269 of file parse_relation.c.
References ATTNUM, elog, ERROR, exprType(), RangeTblEntry::funcexpr, GETSTRUCT, HeapTupleIsValid, Int16GetDatum, IsA, RangeTblEntry::joinaliasvars, list_length(), list_nth(), ObjectIdGetDatum, OidIsValid, ReleaseSysCache(), RangeTblEntry::relid, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, SearchSysCache2, and typeidTypeRelid().
Referenced by AcquireRewriteLocks().
{ bool result; switch (rte->rtekind) { case RTE_RELATION: { /* * Plain relation RTE --- get the attribute's catalog entry */ 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); result = att_tup->attisdropped; ReleaseSysCache(tp); } break; case RTE_SUBQUERY: case RTE_VALUES: case RTE_CTE: /* Subselect, Values, CTE RTEs never have dropped columns */ result = false; break; case RTE_JOIN: { /* * A join RTE would not have dropped columns when constructed, * but one in a stored rule might contain columns that were * dropped from the underlying tables, if said columns are * nowhere explicitly referenced in the rule. This will be * signaled to us by a NULL Const in the joinaliasvars list. */ Var *aliasvar; if (attnum <= 0 || attnum > list_length(rte->joinaliasvars)) elog(ERROR, "invalid varattno %d", attnum); aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1); result = IsA(aliasvar, Const); } 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 = SearchSysCache2(ATTNUM, ObjectIdGetDatum(funcrelid), Int16GetDatum(attnum)); if (!HeapTupleIsValid(tp)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, funcrelid); att_tup = (Form_pg_attribute) GETSTRUCT(tp); result = att_tup->attisdropped; ReleaseSysCache(tp); } else { /* * Must be a base data type, i.e. scalar */ result = false; } } break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); result = false; /* keep compiler quiet */ } return result; }
char* get_rte_attribute_name | ( | RangeTblEntry * | rte, | |
AttrNumber | attnum | |||
) |
Definition at line 2072 of file parse_relation.c.
References RangeTblEntry::alias, Alias::aliasname, Alias::colnames, elog, RangeTblEntry::eref, ERROR, get_relid_attribute_name(), InvalidAttrNumber, list_length(), list_nth(), RangeTblEntry::relid, RTE_RELATION, RangeTblEntry::rtekind, and strVal.
Referenced by check_ungrouped_columns_walker(), get_name_for_var_field(), get_variable(), and print_expr().
{ if (attnum == InvalidAttrNumber) return "*"; /* * If there is a user-written column alias, use it. */ if (rte->alias && attnum > 0 && attnum <= list_length(rte->alias->colnames)) return strVal(list_nth(rte->alias->colnames, attnum - 1)); /* * If the RTE is a relation, go to the system catalogs not the * eref->colnames list. This is a little slower but it will give the * right answer if the column has been renamed since the eref list was * built (which can easily happen for rules). */ if (rte->rtekind == RTE_RELATION) return get_relid_attribute_name(rte->relid, attnum); /* * Otherwise use the column name from eref. There should always be one. */ if (attnum > 0 && attnum <= list_length(rte->eref->colnames)) return strVal(list_nth(rte->eref->colnames, attnum - 1)); /* else caller gave us a bogus attnum */ elog(ERROR, "invalid attnum %d for rangetable entry %s", attnum, rte->eref->aliasname); return NULL; /* keep compiler quiet */ }
void get_rte_attribute_type | ( | RangeTblEntry * | rte, | |
AttrNumber | attnum, | |||
Oid * | vartype, | |||
int32 * | vartypmod, | |||
Oid * | varcollid | |||
) |
Definition at line 2110 of file parse_relation.c.
References Alias::aliasname, Assert, ATTNUM, tupleDesc::attrs, RangeTblEntry::ctecolcollations, RangeTblEntry::ctecoltypes, RangeTblEntry::ctecoltypmods, elog, RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprCollation(), exprType(), exprTypmod(), RangeTblEntry::funccolcollations, RangeTblEntry::funccoltypes, RangeTblEntry::funccoltypmods, RangeTblEntry::funcexpr, get_expr_result_type(), get_rel_name(), get_tle_by_resno(), GETSTRUCT, HeapTupleIsValid, Int16GetDatum, RangeTblEntry::joinaliasvars, linitial, list_length(), list_nth(), list_nth_int(), list_nth_oid(), NameStr, tupleDesc::natts, NULL, ObjectIdGetDatum, ReleaseSysCache(), RangeTblEntry::relid, TargetEntry::resjunk, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, SearchSysCache2, RangeTblEntry::subquery, Query::targetList, TYPEFUNC_COMPOSITE, TYPEFUNC_RECORD, TYPEFUNC_SCALAR, RangeTblEntry::values_collations, and RangeTblEntry::values_lists.
Referenced by make_var().
{ 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 */ TypeFuncClass functypclass; Oid funcrettype; TupleDesc tupdesc; functypclass = get_expr_result_type(rte->funcexpr, &funcrettype, &tupdesc); if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ Form_pg_attribute att_tup; Assert(tupdesc); /* this is probably a can't-happen case */ if (attnum < 1 || attnum > tupdesc->natts) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column %d of relation \"%s\" does not exist", attnum, rte->eref->aliasname))); att_tup = tupdesc->attrs[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(rte->funcexpr); } else if (functypclass == TYPEFUNC_RECORD) { *vartype = list_nth_oid(rte->funccoltypes, attnum - 1); *vartypmod = list_nth_int(rte->funccoltypmods, attnum - 1); *varcollid = list_nth_oid(rte->funccolcollations, attnum - 1); } else { /* addRangeTableEntryForFunction should've caught this */ elog(ERROR, "function in FROM has unsupported return type"); } } break; case RTE_VALUES: { /* Values RTE --- get type info from first sublist */ /* collation is stored separately, though */ List *collist = (List *) linitial(rte->values_lists); Node *col; if (attnum < 1 || attnum > list_length(collist)) elog(ERROR, "values list %s does not have attribute %d", rte->eref->aliasname, attnum); col = (Node *) list_nth(collist, attnum - 1); *vartype = exprType(col); *vartypmod = exprTypmod(col); *varcollid = list_nth_oid(rte->values_collations, attnum - 1); } 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); *vartype = exprType(aliasvar); *vartypmod = exprTypmod(aliasvar); *varcollid = exprCollation(aliasvar); } break; case RTE_CTE: { /* CTE RTE --- get type info from lists in the RTE */ Assert(attnum > 0 && attnum <= list_length(rte->ctecoltypes)); *vartype = list_nth_oid(rte->ctecoltypes, attnum - 1); *vartypmod = list_nth_int(rte->ctecoltypmods, attnum - 1); *varcollid = list_nth_oid(rte->ctecolcollations, attnum - 1); } break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); } }
TargetEntry* get_tle_by_resno | ( | List * | tlist, | |
AttrNumber | resno | |||
) |
Definition at line 2371 of file parse_relation.c.
References lfirst, and TargetEntry::resno.
Referenced by adjust_view_column_set(), count_rowexpr_columns(), create_unique_plan(), currtid_for_view(), examine_simple_variable(), expandRecordVariable(), get_name_for_var_field(), get_rte_attribute_type(), get_variable(), make_sort_from_groupcols(), markTargetListOrigin(), prepare_sort_from_pathkeys(), pullup_replace_vars_callback(), qual_is_pushdown_safe(), ReplaceVarsFromTargetList_callback(), rewriteTargetView(), and show_sort_keys_common().
{ ListCell *l; foreach(l, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(l); if (tle->resno == resno) return tle; } return NULL; }
CommonTableExpr* GetCTEForRTE | ( | ParseState * | pstate, | |
RangeTblEntry * | rte, | |||
int | rtelevelsup | |||
) |
Definition at line 462 of file parse_relation.c.
References Assert, RangeTblEntry::ctelevelsup, CommonTableExpr::ctename, RangeTblEntry::ctename, elog, ERROR, lfirst, ParseState::p_ctenamespace, ParseState::parentParseState, RTE_CTE, RangeTblEntry::rtekind, and RTERangeTablePosn().
Referenced by expandRecordVariable(), and markTargetListOrigin().
{ Index levelsup; ListCell *lc; /* Determine RTE's levelsup if caller didn't know it */ if (rtelevelsup < 0) (void) RTERangeTablePosn(pstate, rte, &rtelevelsup); Assert(rte->rtekind == RTE_CTE); levelsup = rte->ctelevelsup + rtelevelsup; while (levelsup-- > 0) { pstate = pstate->parentParseState; if (!pstate) /* shouldn't happen */ elog(ERROR, "bad levelsup for CTE \"%s\"", rte->ctename); } foreach(lc, pstate->p_ctenamespace) { CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc); if (strcmp(cte->ctename, rte->ctename) == 0) return cte; } /* shouldn't happen */ elog(ERROR, "could not find CTE \"%s\"", rte->ctename); return NULL; /* keep compiler quiet */ }
RangeTblEntry* GetRTEByRangeTablePosn | ( | ParseState * | pstate, | |
int | varno, | |||
int | sublevels_up | |||
) |
Definition at line 441 of file parse_relation.c.
References Assert, list_length(), NULL, ParseState::p_rtable, ParseState::parentParseState, and rt_fetch.
Referenced by coerce_record_to_complex(), count_rowexpr_columns(), expandRecordVariable(), ExpandRowReference(), markTargetListOrigin(), ParseComplexProjection(), and unknown_attribute().
{ while (sublevels_up-- > 0) { pstate = pstate->parentParseState; Assert(pstate != NULL); } Assert(varno > 0 && varno <= list_length(pstate->p_rtable)); return rt_fetch(varno, pstate->p_rtable); }
static bool isFutureCTE | ( | ParseState * | pstate, | |
const char * | refname | |||
) | [static] |
Definition at line 264 of file parse_relation.c.
References CommonTableExpr::ctename, lfirst, ParseState::p_future_ctes, and ParseState::parentParseState.
Referenced by parserOpenTable().
{ for (; pstate != NULL; pstate = pstate->parentParseState) { ListCell *lc; foreach(lc, pstate->p_future_ctes) { CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc); if (strcmp(cte->ctename, refname) == 0) return true; } } return false; }
bool isLockedRefname | ( | ParseState * | pstate, | |
const char * | refname | |||
) |
Definition at line 1559 of file parse_relation.c.
References lfirst, LockingClause::lockedRels, NIL, ParseState::p_locked_from_parent, ParseState::p_locking_clause, and RangeVar::relname.
Referenced by addRangeTableEntry(), and transformRangeSubselect().
{ ListCell *l; /* * If we are in a subquery specified as locked FOR UPDATE/SHARE from * parent level, then act as though there's a generic FOR UPDATE here. */ if (pstate->p_locked_from_parent) return true; foreach(l, pstate->p_locking_clause) { LockingClause *lc = (LockingClause *) lfirst(l); if (lc->lockedRels == NIL) { /* all tables used in query */ return true; } else { /* just the named tables */ ListCell *l2; foreach(l2, lc->lockedRels) { RangeVar *thisrel = (RangeVar *) lfirst(l2); if (strcmp(refname, thisrel->relname) == 0) return true; } } } return false; }
Definition at line 2626 of file parse_relation.c.
References isQueryUsingTempRelation_walker(), and NULL.
Referenced by DefineView(), and transformCreateTableAsStmt().
{ return isQueryUsingTempRelation_walker((Node *) query, NULL); }
Definition at line 2632 of file parse_relation.c.
References AccessShareLock, expression_tree_walker(), heap_close, heap_open(), IsA, lfirst, NULL, QTW_IGNORE_JOINALIASES, query_tree_walker(), RelationData::rd_rel, RangeTblEntry::relid, RELPERSISTENCE_TEMP, Query::rtable, RTE_RELATION, and RangeTblEntry::rtekind.
Referenced by isQueryUsingTempRelation().
{ if (node == NULL) return false; if (IsA(node, Query)) { Query *query = (Query *) node; ListCell *rtable; foreach(rtable, query->rtable) { RangeTblEntry *rte = lfirst(rtable); if (rte->rtekind == RTE_RELATION) { Relation rel = heap_open(rte->relid, AccessShareLock); char relpersistence = rel->rd_rel->relpersistence; heap_close(rel, AccessShareLock); if (relpersistence == RELPERSISTENCE_TEMP) return true; } } return query_tree_walker(query, isQueryUsingTempRelation_walker, context, QTW_IGNORE_JOINALIASES); } return expression_tree_walker(node, isQueryUsingTempRelation_walker, context); }
static void markRTEForSelectPriv | ( | ParseState * | pstate, | |
RangeTblEntry * | rte, | |||
int | rtindex, | |||
AttrNumber | col | |||
) | [static] |
Definition at line 680 of file parse_relation.c.
References Assert, bms_add_member(), elog, ERROR, FirstLowInvalidHeapAttributeNumber, InvalidAttrNumber, IsA, RangeTblEntry::joinaliasvars, JoinExpr::larg, list_length(), list_nth(), markVarForSelectPriv(), nodeTag, NULL, ParseState::p_joinexprs, ParseState::p_rtable, JoinExpr::rarg, RangeTblEntry::requiredPerms, rt_fetch, RTE_JOIN, RTE_RELATION, RangeTblEntry::rtekind, and RangeTblEntry::selectedCols.
Referenced by markVarForSelectPriv().
{ if (rte == NULL) rte = rt_fetch(rtindex, pstate->p_rtable); if (rte->rtekind == RTE_RELATION) { /* Make sure the rel as a whole is marked for SELECT access */ rte->requiredPerms |= ACL_SELECT; /* Must offset the attnum to fit in a bitmapset */ rte->selectedCols = bms_add_member(rte->selectedCols, col - FirstLowInvalidHeapAttributeNumber); } else if (rte->rtekind == RTE_JOIN) { if (col == InvalidAttrNumber) { /* * A whole-row reference to a join has to be treated as whole-row * references to the two inputs. */ JoinExpr *j; if (rtindex > 0 && rtindex <= list_length(pstate->p_joinexprs)) j = (JoinExpr *) list_nth(pstate->p_joinexprs, rtindex - 1); else j = NULL; if (j == NULL) elog(ERROR, "could not find JoinExpr for whole-row reference"); Assert(IsA(j, JoinExpr)); /* Note: we can't see FromExpr here */ if (IsA(j->larg, RangeTblRef)) { int varno = ((RangeTblRef *) j->larg)->rtindex; markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); } else if (IsA(j->larg, JoinExpr)) { int varno = ((JoinExpr *) j->larg)->rtindex; markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(j->larg)); if (IsA(j->rarg, RangeTblRef)) { int varno = ((RangeTblRef *) j->rarg)->rtindex; markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); } else if (IsA(j->rarg, JoinExpr)) { int varno = ((JoinExpr *) j->rarg)->rtindex; markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(j->rarg)); } else { /* * Regular join attribute, look at the alias-variable list. * * The aliasvar could be either a Var or a COALESCE expression, * but in the latter case we should already have marked the two * referent variables as being selected, due to their use in the * JOIN clause. So we need only be concerned with the simple Var * case. */ Var *aliasvar; Assert(col > 0 && col <= list_length(rte->joinaliasvars)); aliasvar = (Var *) list_nth(rte->joinaliasvars, col - 1); if (IsA(aliasvar, Var)) markVarForSelectPriv(pstate, aliasvar, NULL); } } /* other RTE types don't require privilege marking */ }
void markVarForSelectPriv | ( | ParseState * | pstate, | |
Var * | var, | |||
RangeTblEntry * | rte | |||
) |
Definition at line 774 of file parse_relation.c.
References Assert, IsA, markRTEForSelectPriv(), ParseState::parentParseState, Var::varattno, Var::varlevelsup, and Var::varno.
Referenced by expandRelAttrs(), ExpandSingleTable(), markRTEForSelectPriv(), scanRTEForColumn(), transformJoinUsingClause(), and transformWholeRowRef().
{ Index lv; Assert(IsA(var, Var)); /* Find the appropriate pstate if it's an uplevel Var */ for (lv = 0; lv < var->varlevelsup; lv++) pstate = pstate->parentParseState; markRTEForSelectPriv(pstate, rte, var->varno, var->varattno); }
Relation parserOpenTable | ( | ParseState * | pstate, | |
const RangeVar * | relation, | |||
int | lockmode | |||
) |
Definition at line 925 of file parse_relation.c.
References cancel_parser_errposition_callback(), ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, heap_openrv_extended(), isFutureCTE(), RangeVar::location, NULL, RangeVar::relname, RangeVar::schemaname, and setup_parser_errposition_callback().
Referenced by addRangeTableEntry(), and setTargetTable().
{ Relation rel; ParseCallbackState pcbstate; setup_parser_errposition_callback(&pcbstate, pstate, relation->location); rel = heap_openrv_extended(relation, lockmode, true); if (rel == NULL) { if (relation->schemaname) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s.%s\" does not exist", relation->schemaname, relation->relname))); else { /* * An unqualified name might have been meant as a reference to * some not-yet-in-scope CTE. The bare "does not exist" message * has proven remarkably unhelpful for figuring out such problems, * so we take pains to offer a specific hint. */ if (isFutureCTE(pstate, relation->relname)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", relation->relname), errdetail("There is a WITH item named \"%s\", but it cannot be referenced from this part of the query.", relation->relname), errhint("Use WITH RECURSIVE, or re-order the WITH items to remove forward references."))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", relation->relname))); } } cancel_parser_errposition_callback(&pcbstate); return rel; }
RangeTblEntry* refnameRangeTblEntry | ( | ParseState * | pstate, | |
const char * | schemaname, | |||
const char * | refname, | |||
int | location, | |||
int * | sublevels_up | |||
) |
Definition at line 76 of file parse_relation.c.
References get_relname_relid(), LookupNamespaceNoError(), NULL, OidIsValid, ParseState::parentParseState, scanNameSpaceForRefname(), and scanNameSpaceForRelid().
Referenced by errorMissingRTE(), ExpandColumnRefStar(), and transformColumnRef().
{ Oid relId = InvalidOid; if (sublevels_up) *sublevels_up = 0; if (schemaname != NULL) { Oid namespaceId; /* * We can use LookupNamespaceNoError() here because we are only * interested in finding existing RTEs. Checking USAGE permission on * the schema is unnecessary since it would have already been checked * when the RTE was made. Furthermore, we want to report "RTE not * found", not "no permissions for schema", if the name happens to * match a schema name the user hasn't got access to. */ namespaceId = LookupNamespaceNoError(schemaname); if (!OidIsValid(namespaceId)) return NULL; relId = get_relname_relid(refname, namespaceId); if (!OidIsValid(relId)) return NULL; } while (pstate != NULL) { RangeTblEntry *result; if (OidIsValid(relId)) result = scanNameSpaceForRelid(pstate, relId, location); else result = scanNameSpaceForRefname(pstate, refname, location); if (result) return result; if (sublevels_up) (*sublevels_up)++; else break; pstate = pstate->parentParseState; } return NULL; }
int RTERangeTablePosn | ( | ParseState * | pstate, | |
RangeTblEntry * | rte, | |||
int * | sublevels_up | |||
) |
Definition at line 408 of file parse_relation.c.
References elog, ERROR, lfirst, NULL, ParseState::p_rtable, and ParseState::parentParseState.
Referenced by addRTEtoQuery(), ExpandAllTables(), ExpandSingleTable(), GetCTEForRTE(), make_var(), transformCurrentOfExpr(), and transformWholeRowRef().
{ int index; ListCell *l; if (sublevels_up) *sublevels_up = 0; while (pstate != NULL) { index = 1; foreach(l, pstate->p_rtable) { if (rte == (RangeTblEntry *) lfirst(l)) return index; index++; } pstate = pstate->parentParseState; if (sublevels_up) (*sublevels_up)++; else break; } elog(ERROR, "RTE not found (internal error)"); return 0; /* keep compiler quiet */ }
CommonTableExpr* scanNameSpaceForCTE | ( | ParseState * | pstate, | |
const char * | refname, | |||
Index * | ctelevelsup | |||
) |
Definition at line 233 of file parse_relation.c.
References CommonTableExpr::ctename, lfirst, ParseState::p_ctenamespace, and ParseState::parentParseState.
Referenced by searchRangeTableForRel(), and transformFromClauseItem().
{ Index levelsup; for (levelsup = 0; pstate != NULL; pstate = pstate->parentParseState, levelsup++) { ListCell *lc; foreach(lc, pstate->p_ctenamespace) { CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc); if (strcmp(cte->ctename, refname) == 0) { *ctelevelsup = levelsup; return cte; } } } return NULL; }
static RangeTblEntry * scanNameSpaceForRefname | ( | ParseState * | pstate, | |
const char * | refname, | |||
int | location | |||
) | [static] |
Definition at line 135 of file parse_relation.c.
References Alias::aliasname, RangeTblEntry::eref, ereport, errcode(), errdetail(), errmsg(), ERROR, lfirst, ParseState::p_lateral_active, ParseNamespaceItem::p_lateral_ok, ParseNamespaceItem::p_lateral_only, ParseState::p_namespace, ParseNamespaceItem::p_rel_visible, ParseNamespaceItem::p_rte, and parser_errposition().
Referenced by refnameRangeTblEntry().
{ RangeTblEntry *result = NULL; ListCell *l; foreach(l, pstate->p_namespace) { ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l); RangeTblEntry *rte = nsitem->p_rte; /* Ignore columns-only items */ if (!nsitem->p_rel_visible) continue; /* If not inside LATERAL, ignore lateral-only items */ if (nsitem->p_lateral_only && !pstate->p_lateral_active) continue; if (strcmp(rte->eref->aliasname, refname) == 0) { if (result) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_ALIAS), errmsg("table reference \"%s\" is ambiguous", refname), parser_errposition(pstate, location))); /* SQL:2008 demands this be an error, not an invisible item */ if (nsitem->p_lateral_only && !nsitem->p_lateral_ok) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("invalid reference to FROM-clause entry for table \"%s\"", refname), errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."), parser_errposition(pstate, location))); result = rte; } } return result; }
static RangeTblEntry * scanNameSpaceForRelid | ( | ParseState * | pstate, | |
Oid | relid, | |||
int | location | |||
) | [static] |
Definition at line 184 of file parse_relation.c.
References RangeTblEntry::alias, Alias::aliasname, RangeTblEntry::eref, ereport, errcode(), errdetail(), errmsg(), ERROR, lfirst, NULL, ParseState::p_lateral_active, ParseNamespaceItem::p_lateral_ok, ParseNamespaceItem::p_lateral_only, ParseState::p_namespace, ParseNamespaceItem::p_rel_visible, ParseNamespaceItem::p_rte, parser_errposition(), RangeTblEntry::relid, RTE_RELATION, and RangeTblEntry::rtekind.
Referenced by refnameRangeTblEntry().
{ RangeTblEntry *result = NULL; ListCell *l; foreach(l, pstate->p_namespace) { ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l); RangeTblEntry *rte = nsitem->p_rte; /* Ignore columns-only items */ if (!nsitem->p_rel_visible) continue; /* If not inside LATERAL, ignore lateral-only items */ if (nsitem->p_lateral_only && !pstate->p_lateral_active) continue; /* yes, the test for alias == NULL should be there... */ if (rte->rtekind == RTE_RELATION && rte->relid == relid && rte->alias == NULL) { if (result) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_ALIAS), errmsg("table reference %u is ambiguous", relid), parser_errposition(pstate, location))); /* SQL:2008 demands this be an error, not an invisible item */ if (nsitem->p_lateral_only && !nsitem->p_lateral_ok) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("invalid reference to FROM-clause entry for table \"%s\"", rte->eref->aliasname), errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."), parser_errposition(pstate, location))); result = rte; } } return result; }
Node* scanRTEForColumn | ( | ParseState * | pstate, | |
RangeTblEntry * | rte, | |||
char * | colname, | |||
int | location | |||
) |
Definition at line 501 of file parse_relation.c.
References ATTNUM, Alias::colnames, RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, Int16GetDatum, InvalidAttrNumber, lfirst, make_var(), markVarForSelectPriv(), ObjectIdGetDatum, parser_errposition(), RangeTblEntry::relid, RTE_RELATION, RangeTblEntry::rtekind, SearchSysCacheExists2, specialAttNum(), and strVal.
Referenced by colNameToVar(), ParseComplexProjection(), searchRangeTableForCol(), and transformColumnRef().
{ Node *result = NULL; int attnum = 0; Var *var; ListCell *c; /* * Scan the user column names (or aliases) for a match. Complain if * multiple matches. * * Note: eref->colnames may include entries for dropped columns, but those * will be empty strings that cannot match any legal SQL identifier, so we * 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 make_var(). That routine * has to do a cache lookup anyway, so the check there is cheap. */ foreach(c, rte->eref->colnames) { attnum++; if (strcmp(strVal(lfirst(c)), colname) == 0) { if (result) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_COLUMN), errmsg("column reference \"%s\" is ambiguous", colname), parser_errposition(pstate, location))); var = make_var(pstate, rte, attnum, location); /* Require read access to the column */ markVarForSelectPriv(pstate, var, rte); result = (Node *) var; } } /* * If we have a unique match, return it. Note that this allows a user * alias to override a system column name (such as OID) without error. */ if (result) return result; /* * If the RTE represents a real table, consider system column names. */ if (rte->rtekind == RTE_RELATION) { /* quick check to see if name could be a system column */ attnum = specialAttNum(colname); if (attnum != InvalidAttrNumber) { /* now check to see if column actually is defined */ if (SearchSysCacheExists2(ATTNUM, ObjectIdGetDatum(rte->relid), Int16GetDatum(attnum))) { var = make_var(pstate, rte, attnum, location); /* Require read access to the column */ markVarForSelectPriv(pstate, var, rte); result = (Node *) var; } } } return result; }
static RangeTblEntry* searchRangeTableForCol | ( | ParseState * | pstate, | |
char * | colname, | |||
int | location | |||
) | [static] |
Definition at line 648 of file parse_relation.c.
References lfirst, NULL, ParseState::p_rtable, ParseState::parentParseState, and scanRTEForColumn().
Referenced by errorMissingColumn().
{ ParseState *orig_pstate = pstate; while (pstate != NULL) { ListCell *l; foreach(l, pstate->p_rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); if (scanRTEForColumn(orig_pstate, rte, colname, location)) return rte; } pstate = pstate->parentParseState; } return NULL; }
static RangeTblEntry* searchRangeTableForRel | ( | ParseState * | pstate, | |
RangeVar * | relation | |||
) | [static] |
Definition at line 297 of file parse_relation.c.
References Alias::aliasname, RangeTblEntry::ctelevelsup, RangeTblEntry::ctename, RangeTblEntry::eref, lfirst, NoLock, NULL, OidIsValid, ParseState::p_rtable, ParseState::parentParseState, RangeVarGetRelid, RangeTblEntry::relid, RangeVar::relname, RTE_CTE, RTE_RELATION, RangeTblEntry::rtekind, scanNameSpaceForCTE(), and RangeVar::schemaname.
Referenced by errorMissingRTE().
{ const char *refname = relation->relname; Oid relId = InvalidOid; CommonTableExpr *cte = NULL; Index ctelevelsup = 0; Index levelsup; /* * If it's an unqualified name, check for possible CTE matches. A CTE * hides any real relation matches. If no CTE, look for a matching * relation. * * NB: It's not critical that RangeVarGetRelid return the correct answer * here in the face of concurrent DDL. If it doesn't, the worst case * scenario is a less-clear error message. Also, the tables involved in * the query are already locked, which reduces the number of cases in * which surprising behavior can occur. So we do the name lookup * unlocked. */ if (!relation->schemaname) cte = scanNameSpaceForCTE(pstate, refname, &ctelevelsup); if (!cte) relId = RangeVarGetRelid(relation, NoLock, true); /* Now look for RTEs matching either the relation/CTE or the alias */ for (levelsup = 0; pstate != NULL; pstate = pstate->parentParseState, levelsup++) { ListCell *l; foreach(l, pstate->p_rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); if (rte->rtekind == RTE_RELATION && OidIsValid(relId) && rte->relid == relId) return rte; if (rte->rtekind == RTE_CTE && cte != NULL && rte->ctelevelsup + levelsup == ctelevelsup && strcmp(rte->ctename, refname) == 0) return rte; if (strcmp(rte->eref->aliasname, refname) == 0) return rte; } } return NULL; }
static int specialAttNum | ( | const char * | attname | ) | [static] |
Definition at line 2450 of file parse_relation.c.
References NULL, and SystemAttributeByName().
Referenced by attnameAttNum(), and scanRTEForColumn().
{ Form_pg_attribute sysatt; sysatt = SystemAttributeByName(attname, true /* "oid" will be accepted */ ); if (sysatt != NULL) return sysatt->attnum; return InvalidAttrNumber; }