Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

parse_relation.c File Reference

#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"
Include dependency graph for parse_relation.c:

Go to the source code of this file.

Functions

static RangeTblEntryscanNameSpaceForRefname (ParseState *pstate, const char *refname, int location)
static RangeTblEntryscanNameSpaceForRelid (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)
RangeTblEntryrefnameRangeTblEntry (ParseState *pstate, const char *schemaname, const char *refname, int location, int *sublevels_up)
CommonTableExprscanNameSpaceForCTE (ParseState *pstate, const char *refname, Index *ctelevelsup)
static bool isFutureCTE (ParseState *pstate, const char *refname)
static RangeTblEntrysearchRangeTableForRel (ParseState *pstate, RangeVar *relation)
void checkNameSpaceConflicts (ParseState *pstate, List *namespace1, List *namespace2)
int RTERangeTablePosn (ParseState *pstate, RangeTblEntry *rte, int *sublevels_up)
RangeTblEntryGetRTEByRangeTablePosn (ParseState *pstate, int varno, int sublevels_up)
CommonTableExprGetCTEForRTE (ParseState *pstate, RangeTblEntry *rte, int rtelevelsup)
NodescanRTEForColumn (ParseState *pstate, RangeTblEntry *rte, char *colname, int location)
NodecolNameToVar (ParseState *pstate, char *colname, bool localonly, int location)
static RangeTblEntrysearchRangeTableForCol (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)
RangeTblEntryaddRangeTableEntry (ParseState *pstate, RangeVar *relation, Alias *alias, bool inh, bool inFromCl)
RangeTblEntryaddRangeTableEntryForRelation (ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl)
RangeTblEntryaddRangeTableEntryForSubquery (ParseState *pstate, Query *subquery, Alias *alias, bool lateral, bool inFromCl)
RangeTblEntryaddRangeTableEntryForFunction (ParseState *pstate, char *funcname, Node *funcexpr, RangeFunction *rangefunc, bool lateral, bool inFromCl)
RangeTblEntryaddRangeTableEntryForValues (ParseState *pstate, List *exprs, List *collations, Alias *alias, bool lateral, bool inFromCl)
RangeTblEntryaddRangeTableEntryForJoin (ParseState *pstate, List *colnames, JoinType jointype, List *aliasvars, Alias *alias, bool inFromCl)
RangeTblEntryaddRangeTableEntryForCTE (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)
ListexpandRelAttrs (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)
TargetEntryget_tle_by_resno (List *tlist, AttrNumber resno)
RowMarkClauseget_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)

Function Documentation

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 
)
int attnameAttNum ( Relation  rd,
const char *  attname,
bool  sysColOK 
)

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;
}

Name attnumAttName ( Relation  rd,
int  attid 
)

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;
}

Oid attnumCollationId ( Relation  rd,
int  attid 
)

Definition at line 2512 of file parse_relation.c.

References tupleDesc::attrs, elog, ERROR, tupleDesc::natts, and RelationData::rd_att.

{
    if (attid <= 0)
    {
        /* All system attributes are of noncollatable types. */
        return InvalidOid;
    }
    if (attid > rd->rd_att->natts)
        elog(ERROR, "invalid attribute number %d", attid);
    return rd->rd_att->attrs[attid - 1]->attcollation;
}

Oid attnumTypeId ( Relation  rd,
int  attid 
)

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;
}

static void buildRelationAliases ( TupleDesc  tupdesc,
Alias alias,
Alias eref 
) [static]

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 
)
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;
}

bool isQueryUsingTempRelation ( Query query  ) 

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);
}

static bool isQueryUsingTempRelation_walker ( Node node,
void *  context 
) [static]

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;
}