Header And Logo

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

Defines | Functions

parse_clause.c File Reference

#include "postgres.h"
#include "access/heapam.h"
#include "catalog/heap.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "rewrite/rewriteManip.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
Include dependency graph for parse_clause.c:

Go to the source code of this file.

Defines

#define makeDefaultNSItem(rte)   makeNamespaceItem(rte, true, true, false, true)

Functions

static void extractRemainingColumns (List *common_colnames, List *src_colnames, List *src_colvars, List **res_colnames, List **res_colvars)
static NodetransformJoinUsingClause (ParseState *pstate, RangeTblEntry *leftRTE, RangeTblEntry *rightRTE, List *leftVars, List *rightVars)
static NodetransformJoinOnClause (ParseState *pstate, JoinExpr *j, List *namespace)
static RangeTblEntrytransformTableEntry (ParseState *pstate, RangeVar *r)
static RangeTblEntrytransformCTEReference (ParseState *pstate, RangeVar *r, CommonTableExpr *cte, Index levelsup)
static RangeTblEntrytransformRangeSubselect (ParseState *pstate, RangeSubselect *r)
static RangeTblEntrytransformRangeFunction (ParseState *pstate, RangeFunction *r)
static NodetransformFromClauseItem (ParseState *pstate, Node *n, RangeTblEntry **top_rte, int *top_rti, List **namespace)
static NodebuildMergedJoinVar (ParseState *pstate, JoinType jointype, Var *l_colvar, Var *r_colvar)
static ParseNamespaceItemmakeNamespaceItem (RangeTblEntry *rte, bool rel_visible, bool cols_visible, bool lateral_only, bool lateral_ok)
static void setNamespaceColumnVisibility (List *namespace, bool cols_visible)
static void setNamespaceLateralState (List *namespace, bool lateral_only, bool lateral_ok)
static void checkExprIsVarFree (ParseState *pstate, Node *n, const char *constructName)
static TargetEntryfindTargetlistEntrySQL92 (ParseState *pstate, Node *node, List **tlist, ParseExprKind exprKind)
static TargetEntryfindTargetlistEntrySQL99 (ParseState *pstate, Node *node, List **tlist, ParseExprKind exprKind)
static int get_matching_location (int sortgroupref, List *sortgrouprefs, List *exprs)
static ListaddTargetToSortList (ParseState *pstate, TargetEntry *tle, List *sortlist, List *targetlist, SortBy *sortby, bool resolveUnknown)
static ListaddTargetToGroupList (ParseState *pstate, TargetEntry *tle, List *grouplist, List *targetlist, int location, bool resolveUnknown)
static WindowClausefindWindowClause (List *wclist, const char *name)
static NodetransformFrameOffset (ParseState *pstate, int frameOptions, Node *clause)
void transformFromClause (ParseState *pstate, List *frmList)
int setTargetTable (ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms)
bool interpretInhOption (InhOption inhOpt)
bool interpretOidsOption (List *defList, bool allowOids)
NodetransformWhereClause (ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
NodetransformLimitClause (ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
static void checkTargetlistEntrySQL92 (ParseState *pstate, TargetEntry *tle, ParseExprKind exprKind)
ListtransformGroupClause (ParseState *pstate, List *grouplist, List **targetlist, List *sortClause, ParseExprKind exprKind, bool useSQL99)
ListtransformSortClause (ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool resolveUnknown, bool useSQL99)
ListtransformWindowDefinitions (ParseState *pstate, List *windowdefs, List **targetlist)
ListtransformDistinctClause (ParseState *pstate, List **targetlist, List *sortClause, bool is_agg)
ListtransformDistinctOnClause (ParseState *pstate, List *distinctlist, List **targetlist, List *sortClause)
Index assignSortGroupRef (TargetEntry *tle, List *tlist)
bool targetIsInSortList (TargetEntry *tle, Oid sortop, List *sortList)

Define Documentation

#define makeDefaultNSItem (   rte  )     makeNamespaceItem(rte, true, true, false, true)

Definition at line 42 of file parse_clause.c.


Function Documentation

static List * addTargetToGroupList ( ParseState pstate,
TargetEntry tle,
List grouplist,
List targetlist,
int  location,
bool  resolveUnknown 
) [static]

Definition at line 2170 of file parse_clause.c.

References assignSortGroupRef(), cancel_parser_errposition_callback(), coerce_type(), SortGroupClause::eqop, TargetEntry::expr, exprType(), get_sort_group_operators(), SortGroupClause::hashable, InvalidOid, lappend(), makeNode, NULL, SortGroupClause::nulls_first, setup_parser_errposition_callback(), SortGroupClause::sortop, targetIsInSortList(), SortGroupClause::tleSortGroupRef, and UNKNOWNOID.

Referenced by transformDistinctClause(), transformDistinctOnClause(), and transformGroupClause().

{
    Oid         restype = exprType((Node *) tle->expr);

    /* if tlist item is an UNKNOWN literal, change it to TEXT */
    if (restype == UNKNOWNOID && resolveUnknown)
    {
        tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
                                         restype, TEXTOID, -1,
                                         COERCION_IMPLICIT,
                                         COERCE_IMPLICIT_CAST,
                                         -1);
        restype = TEXTOID;
    }

    /* avoid making duplicate grouplist entries */
    if (!targetIsInSortList(tle, InvalidOid, grouplist))
    {
        SortGroupClause *grpcl = makeNode(SortGroupClause);
        Oid         sortop;
        Oid         eqop;
        bool        hashable;
        ParseCallbackState pcbstate;

        setup_parser_errposition_callback(&pcbstate, pstate, location);

        /* determine the eqop and optional sortop */
        get_sort_group_operators(restype,
                                 false, true, false,
                                 &sortop, &eqop, NULL,
                                 &hashable);

        cancel_parser_errposition_callback(&pcbstate);

        grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
        grpcl->eqop = eqop;
        grpcl->sortop = sortop;
        grpcl->nulls_first = false;     /* OK with or without sortop */
        grpcl->hashable = hashable;

        grouplist = lappend(grouplist, grpcl);
    }

    return grouplist;
}

static List * addTargetToSortList ( ParseState pstate,
TargetEntry tle,
List sortlist,
List targetlist,
SortBy sortby,
bool  resolveUnknown 
) [static]

Definition at line 2021 of file parse_clause.c.

References Assert, assignSortGroupRef(), cancel_parser_errposition_callback(), coerce_type(), compatible_oper_opid(), elog, SortGroupClause::eqop, ereport, errcode(), errhint(), errmsg(), ERROR, TargetEntry::expr, exprLocation(), exprType(), get_equality_op_for_ordering_op(), get_sort_group_operators(), SortGroupClause::hashable, lappend(), llast, SortBy::location, makeNode, NIL, SortBy::node, NULL, SortGroupClause::nulls_first, OidIsValid, op_hashjoinable(), setup_parser_errposition_callback(), SORTBY_ASC, SORTBY_DEFAULT, SORTBY_DESC, SortBy::sortby_dir, SortBy::sortby_nulls, SORTBY_NULLS_DEFAULT, SORTBY_NULLS_FIRST, SORTBY_NULLS_LAST, SORTBY_USING, SortGroupClause::sortop, strVal, targetIsInSortList(), SortGroupClause::tleSortGroupRef, UNKNOWNOID, and SortBy::useOp.

Referenced by transformSortClause().

{
    Oid         restype = exprType((Node *) tle->expr);
    Oid         sortop;
    Oid         eqop;
    bool        hashable;
    bool        reverse;
    int         location;
    ParseCallbackState pcbstate;

    /* if tlist item is an UNKNOWN literal, change it to TEXT */
    if (restype == UNKNOWNOID && resolveUnknown)
    {
        tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
                                         restype, TEXTOID, -1,
                                         COERCION_IMPLICIT,
                                         COERCE_IMPLICIT_CAST,
                                         -1);
        restype = TEXTOID;
    }

    /*
     * Rather than clutter the API of get_sort_group_operators and the other
     * functions we're about to use, make use of error context callback to
     * mark any error reports with a parse position.  We point to the operator
     * location if present, else to the expression being sorted.  (NB: use the
     * original untransformed expression here; the TLE entry might well point
     * at a duplicate expression in the regular SELECT list.)
     */
    location = sortby->location;
    if (location < 0)
        location = exprLocation(sortby->node);
    setup_parser_errposition_callback(&pcbstate, pstate, location);

    /* determine the sortop, eqop, and directionality */
    switch (sortby->sortby_dir)
    {
        case SORTBY_DEFAULT:
        case SORTBY_ASC:
            get_sort_group_operators(restype,
                                     true, true, false,
                                     &sortop, &eqop, NULL,
                                     &hashable);
            reverse = false;
            break;
        case SORTBY_DESC:
            get_sort_group_operators(restype,
                                     false, true, true,
                                     NULL, &eqop, &sortop,
                                     &hashable);
            reverse = true;
            break;
        case SORTBY_USING:
            Assert(sortby->useOp != NIL);
            sortop = compatible_oper_opid(sortby->useOp,
                                          restype,
                                          restype,
                                          false);

            /*
             * Verify it's a valid ordering operator, fetch the corresponding
             * equality operator, and determine whether to consider it like
             * ASC or DESC.
             */
            eqop = get_equality_op_for_ordering_op(sortop, &reverse);
            if (!OidIsValid(eqop))
                ereport(ERROR,
                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                       errmsg("operator %s is not a valid ordering operator",
                              strVal(llast(sortby->useOp))),
                         errhint("Ordering operators must be \"<\" or \">\" members of btree operator families.")));

            /*
             * Also see if the equality operator is hashable.
             */
            hashable = op_hashjoinable(eqop, restype);
            break;
        default:
            elog(ERROR, "unrecognized sortby_dir: %d", sortby->sortby_dir);
            sortop = InvalidOid;    /* keep compiler quiet */
            eqop = InvalidOid;
            hashable = false;
            reverse = false;
            break;
    }

    cancel_parser_errposition_callback(&pcbstate);

    /* avoid making duplicate sortlist entries */
    if (!targetIsInSortList(tle, sortop, sortlist))
    {
        SortGroupClause *sortcl = makeNode(SortGroupClause);

        sortcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);

        sortcl->eqop = eqop;
        sortcl->sortop = sortop;
        sortcl->hashable = hashable;

        switch (sortby->sortby_nulls)
        {
            case SORTBY_NULLS_DEFAULT:
                /* NULLS FIRST is default for DESC; other way for ASC */
                sortcl->nulls_first = reverse;
                break;
            case SORTBY_NULLS_FIRST:
                sortcl->nulls_first = true;
                break;
            case SORTBY_NULLS_LAST:
                sortcl->nulls_first = false;
                break;
            default:
                elog(ERROR, "unrecognized sortby_nulls: %d",
                     sortby->sortby_nulls);
                break;
        }

        sortlist = lappend(sortlist, sortcl);
    }

    return sortlist;
}

Index assignSortGroupRef ( TargetEntry tle,
List tlist 
)

Definition at line 2226 of file parse_clause.c.

References lfirst, and TargetEntry::ressortgroupref.

Referenced by addTargetToGroupList(), addTargetToSortList(), build_minmax_path(), create_unique_plan(), and transformDistinctOnClause().

{
    Index       maxRef;
    ListCell   *l;

    if (tle->ressortgroupref)   /* already has one? */
        return tle->ressortgroupref;

    /* easiest way to pick an unused refnumber: max used + 1 */
    maxRef = 0;
    foreach(l, tlist)
    {
        Index       ref = ((TargetEntry *) lfirst(l))->ressortgroupref;

        if (ref > maxRef)
            maxRef = ref;
    }
    tle->ressortgroupref = maxRef + 1;
    return tle->ressortgroupref;
}

static Node * buildMergedJoinVar ( ParseState pstate,
JoinType  jointype,
Var l_colvar,
Var r_colvar 
) [static]

Definition at line 1014 of file parse_clause.c.

References CoalesceExpr::args, assign_expr_collations(), CoalesceExpr::coalescetype, COERCE_IMPLICIT_CAST, coerce_type(), COERCION_IMPLICIT, elog, ERROR, IsA, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, list_make2, CoalesceExpr::location, makeNode, makeRelabelType(), NULL, select_common_type(), Var::vartype, and Var::vartypmod.

Referenced by transformFromClauseItem().

{
    Oid         outcoltype;
    int32       outcoltypmod;
    Node       *l_node,
               *r_node,
               *res_node;

    /*
     * Choose output type if input types are dissimilar.
     */
    outcoltype = l_colvar->vartype;
    outcoltypmod = l_colvar->vartypmod;
    if (outcoltype != r_colvar->vartype)
    {
        outcoltype = select_common_type(pstate,
                                        list_make2(l_colvar, r_colvar),
                                        "JOIN/USING",
                                        NULL);
        outcoltypmod = -1;      /* ie, unknown */
    }
    else if (outcoltypmod != r_colvar->vartypmod)
    {
        /* same type, but not same typmod */
        outcoltypmod = -1;      /* ie, unknown */
    }

    /*
     * Insert coercion functions if needed.  Note that a difference in typmod
     * can only happen if input has typmod but outcoltypmod is -1. In that
     * case we insert a RelabelType to clearly mark that result's typmod is
     * not same as input.  We never need coerce_type_typmod.
     */
    if (l_colvar->vartype != outcoltype)
        l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
                             outcoltype, outcoltypmod,
                             COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
    else if (l_colvar->vartypmod != outcoltypmod)
        l_node = (Node *) makeRelabelType((Expr *) l_colvar,
                                          outcoltype, outcoltypmod,
                                          InvalidOid,   /* fixed below */
                                          COERCE_IMPLICIT_CAST);
    else
        l_node = (Node *) l_colvar;

    if (r_colvar->vartype != outcoltype)
        r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
                             outcoltype, outcoltypmod,
                             COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
    else if (r_colvar->vartypmod != outcoltypmod)
        r_node = (Node *) makeRelabelType((Expr *) r_colvar,
                                          outcoltype, outcoltypmod,
                                          InvalidOid,   /* fixed below */
                                          COERCE_IMPLICIT_CAST);
    else
        r_node = (Node *) r_colvar;

    /*
     * Choose what to emit
     */
    switch (jointype)
    {
        case JOIN_INNER:

            /*
             * We can use either var; prefer non-coerced one if available.
             */
            if (IsA(l_node, Var))
                res_node = l_node;
            else if (IsA(r_node, Var))
                res_node = r_node;
            else
                res_node = l_node;
            break;
        case JOIN_LEFT:
            /* Always use left var */
            res_node = l_node;
            break;
        case JOIN_RIGHT:
            /* Always use right var */
            res_node = r_node;
            break;
        case JOIN_FULL:
            {
                /*
                 * Here we must build a COALESCE expression to ensure that the
                 * join output is non-null if either input is.
                 */
                CoalesceExpr *c = makeNode(CoalesceExpr);

                c->coalescetype = outcoltype;
                /* coalescecollid will get set below */
                c->args = list_make2(l_node, r_node);
                c->location = -1;
                res_node = (Node *) c;
                break;
            }
        default:
            elog(ERROR, "unrecognized join type: %d", (int) jointype);
            res_node = NULL;    /* keep compiler quiet */
            break;
    }

    /*
     * Apply assign_expr_collations to fix up the collation info in the
     * coercion and CoalesceExpr nodes, if we made any.  This must be done now
     * so that the join node's alias vars show correct collation info.
     */
    assign_expr_collations(pstate, res_node);

    return res_node;
}

static void checkExprIsVarFree ( ParseState pstate,
Node n,
const char *  constructName 
) [static]

Definition at line 1249 of file parse_clause.c.

References contain_vars_of_level(), ereport, errcode(), errmsg(), ERROR, locate_var_of_level(), and parser_errposition().

Referenced by transformFrameOffset(), and transformLimitClause().

{
    if (contain_vars_of_level(n, 0))
    {
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
        /* translator: %s is name of a SQL construct, eg LIMIT */
                 errmsg("argument of %s must not contain variables",
                        constructName),
                 parser_errposition(pstate,
                                    locate_var_of_level(n, 0))));
    }
}

static void checkTargetlistEntrySQL92 ( ParseState pstate,
TargetEntry tle,
ParseExprKind  exprKind 
) [static]

Definition at line 1274 of file parse_clause.c.

References contain_aggs_of_level(), contain_windowfuncs(), elog, ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, EXPR_KIND_DISTINCT_ON, EXPR_KIND_GROUP_BY, EXPR_KIND_ORDER_BY, locate_agg_of_level(), locate_windowfunc(), ParseState::p_hasAggs, ParseState::p_hasWindowFuncs, ParseExprKindName(), and parser_errposition().

Referenced by findTargetlistEntrySQL92().

{
    switch (exprKind)
    {
        case EXPR_KIND_GROUP_BY:
            /* reject aggregates and window functions */
            if (pstate->p_hasAggs &&
                contain_aggs_of_level((Node *) tle->expr, 0))
                ereport(ERROR,
                        (errcode(ERRCODE_GROUPING_ERROR),
                         /* translator: %s is name of a SQL construct, eg GROUP BY */
                         errmsg("aggregate functions are not allowed in %s",
                                ParseExprKindName(exprKind)),
                         parser_errposition(pstate,
                                            locate_agg_of_level((Node *) tle->expr, 0))));
            if (pstate->p_hasWindowFuncs &&
                contain_windowfuncs((Node *) tle->expr))
                ereport(ERROR,
                        (errcode(ERRCODE_WINDOWING_ERROR),
                         /* translator: %s is name of a SQL construct, eg GROUP BY */
                         errmsg("window functions are not allowed in %s",
                                ParseExprKindName(exprKind)),
                         parser_errposition(pstate,
                                            locate_windowfunc((Node *) tle->expr))));
            break;
        case EXPR_KIND_ORDER_BY:
            /* no extra checks needed */
            break;
        case EXPR_KIND_DISTINCT_ON:
            /* no extra checks needed */
            break;
        default:
            elog(ERROR, "unexpected exprKind in checkTargetlistEntrySQL92");
            break;
    }
}

static void extractRemainingColumns ( List common_colnames,
List src_colnames,
List src_colvars,
List **  res_colnames,
List **  res_colvars 
) [static]

Definition at line 285 of file parse_clause.c.

References Assert, cnames, forboth, lappend(), lfirst, list_length(), and strVal.

Referenced by transformFromClauseItem().

{
    List       *new_colnames = NIL;
    List       *new_colvars = NIL;
    ListCell   *lnames,
               *lvars;

    Assert(list_length(src_colnames) == list_length(src_colvars));

    forboth(lnames, src_colnames, lvars, src_colvars)
    {
        char       *colname = strVal(lfirst(lnames));
        bool        match = false;
        ListCell   *cnames;

        foreach(cnames, common_colnames)
        {
            char       *ccolname = strVal(lfirst(cnames));

            if (strcmp(colname, ccolname) == 0)
            {
                match = true;
                break;
            }
        }

        if (!match)
        {
            new_colnames = lappend(new_colnames, lfirst(lnames));
            new_colvars = lappend(new_colvars, lfirst(lvars));
        }
    }

    *res_colnames = new_colnames;
    *res_colvars = new_colvars;
}

static TargetEntry * findTargetlistEntrySQL92 ( ParseState pstate,
Node node,
List **  tlist,
ParseExprKind  exprKind 
) [static]

Definition at line 1330 of file parse_clause.c.

References checkTargetlistEntrySQL92(), colNameToVar(), equal(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, EXPR_KIND_GROUP_BY, findTargetlistEntrySQL99(), intVal, IsA, lfirst, linitial, list_length(), name, NULL, ParseExprKindName(), parser_errposition(), TargetEntry::resjunk, TargetEntry::resname, strVal, and val.

Referenced by transformDistinctOnClause(), transformGroupClause(), and transformSortClause().

{
    ListCell   *tl;

    /*----------
     * Handle two special cases as mandated by the SQL92 spec:
     *
     * 1. Bare ColumnName (no qualifier or subscripts)
     *    For a bare identifier, we search for a matching column name
     *    in the existing target list.  Multiple matches are an error
     *    unless they refer to identical values; for example,
     *    we allow  SELECT a, a FROM table ORDER BY a
     *    but not   SELECT a AS b, b FROM table ORDER BY b
     *    If no match is found, we fall through and treat the identifier
     *    as an expression.
     *    For GROUP BY, it is incorrect to match the grouping item against
     *    targetlist entries: according to SQL92, an identifier in GROUP BY
     *    is a reference to a column name exposed by FROM, not to a target
     *    list column.  However, many implementations (including pre-7.0
     *    PostgreSQL) accept this anyway.  So for GROUP BY, we look first
     *    to see if the identifier matches any FROM column name, and only
     *    try for a targetlist name if it doesn't.  This ensures that we
     *    adhere to the spec in the case where the name could be both.
     *    DISTINCT ON isn't in the standard, so we can do what we like there;
     *    we choose to make it work like ORDER BY, on the rather flimsy
     *    grounds that ordinary DISTINCT works on targetlist entries.
     *
     * 2. IntegerConstant
     *    This means to use the n'th item in the existing target list.
     *    Note that it would make no sense to order/group/distinct by an
     *    actual constant, so this does not create a conflict with SQL99.
     *    GROUP BY column-number is not allowed by SQL92, but since
     *    the standard has no other behavior defined for this syntax,
     *    we may as well accept this common extension.
     *
     * Note that pre-existing resjunk targets must not be used in either case,
     * since the user didn't write them in his SELECT list.
     *
     * If neither special case applies, fall through to treat the item as
     * an expression per SQL99.
     *----------
     */
    if (IsA(node, ColumnRef) &&
        list_length(((ColumnRef *) node)->fields) == 1 &&
        IsA(linitial(((ColumnRef *) node)->fields), String))
    {
        char       *name = strVal(linitial(((ColumnRef *) node)->fields));
        int         location = ((ColumnRef *) node)->location;

        if (exprKind == EXPR_KIND_GROUP_BY)
        {
            /*
             * In GROUP BY, we must prefer a match against a FROM-clause
             * column to one against the targetlist.  Look to see if there is
             * a matching column.  If so, fall through to use SQL99 rules.
             * NOTE: if name could refer ambiguously to more than one column
             * name exposed by FROM, colNameToVar will ereport(ERROR). That's
             * just what we want here.
             *
             * Small tweak for 7.4.3: ignore matches in upper query levels.
             * This effectively changes the search order for bare names to (1)
             * local FROM variables, (2) local targetlist aliases, (3) outer
             * FROM variables, whereas before it was (1) (3) (2). SQL92 and
             * SQL99 do not allow GROUPing BY an outer reference, so this
             * breaks no cases that are legal per spec, and it seems a more
             * self-consistent behavior.
             */
            if (colNameToVar(pstate, name, true, location) != NULL)
                name = NULL;
        }

        if (name != NULL)
        {
            TargetEntry *target_result = NULL;

            foreach(tl, *tlist)
            {
                TargetEntry *tle = (TargetEntry *) lfirst(tl);

                if (!tle->resjunk &&
                    strcmp(tle->resname, name) == 0)
                {
                    if (target_result != NULL)
                    {
                        if (!equal(target_result->expr, tle->expr))
                            ereport(ERROR,
                                    (errcode(ERRCODE_AMBIGUOUS_COLUMN),

                            /*------
                              translator: first %s is name of a SQL construct, eg ORDER BY */
                                     errmsg("%s \"%s\" is ambiguous",
                                            ParseExprKindName(exprKind),
                                            name),
                                     parser_errposition(pstate, location)));
                    }
                    else
                        target_result = tle;
                    /* Stay in loop to check for ambiguity */
                }
            }
            if (target_result != NULL)
            {
                /* return the first match, after suitable validation */
                checkTargetlistEntrySQL92(pstate, target_result, exprKind);
                return target_result;
            }
        }
    }
    if (IsA(node, A_Const))
    {
        Value      *val = &((A_Const *) node)->val;
        int         location = ((A_Const *) node)->location;
        int         targetlist_pos = 0;
        int         target_pos;

        if (!IsA(val, Integer))
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
            /* translator: %s is name of a SQL construct, eg ORDER BY */
                     errmsg("non-integer constant in %s",
                            ParseExprKindName(exprKind)),
                     parser_errposition(pstate, location)));

        target_pos = intVal(val);
        foreach(tl, *tlist)
        {
            TargetEntry *tle = (TargetEntry *) lfirst(tl);

            if (!tle->resjunk)
            {
                if (++targetlist_pos == target_pos)
                {
                    /* return the unique match, after suitable validation */
                    checkTargetlistEntrySQL92(pstate, tle, exprKind);
                    return tle;
                }
            }
        }
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
        /* translator: %s is name of a SQL construct, eg ORDER BY */
                 errmsg("%s position %d is not in select list",
                        ParseExprKindName(exprKind), target_pos),
                 parser_errposition(pstate, location)));
    }

    /*
     * Otherwise, we have an expression, so process it per SQL99 rules.
     */
    return findTargetlistEntrySQL99(pstate, node, tlist, exprKind);
}

static TargetEntry * findTargetlistEntrySQL99 ( ParseState pstate,
Node node,
List **  tlist,
ParseExprKind  exprKind 
) [static]

Definition at line 1497 of file parse_clause.c.

References equal(), TargetEntry::expr, lappend(), lfirst, NULL, strip_implicit_coercions(), transformExpr(), and transformTargetEntry().

Referenced by findTargetlistEntrySQL92(), transformGroupClause(), and transformSortClause().

{
    TargetEntry *target_result;
    ListCell   *tl;
    Node       *expr;

    /*
     * Convert the untransformed node to a transformed expression, and search
     * for a match in the tlist.  NOTE: it doesn't really matter whether there
     * is more than one match.  Also, we are willing to match an existing
     * resjunk target here, though the SQL92 cases above must ignore resjunk
     * targets.
     */
    expr = transformExpr(pstate, node, exprKind);

    foreach(tl, *tlist)
    {
        TargetEntry *tle = (TargetEntry *) lfirst(tl);
        Node       *texpr;

        /*
         * Ignore any implicit cast on the existing tlist expression.
         *
         * This essentially allows the ORDER/GROUP/etc item to adopt the same
         * datatype previously selected for a textually-equivalent tlist item.
         * There can't be any implicit cast at top level in an ordinary SELECT
         * tlist at this stage, but the case does arise with ORDER BY in an
         * aggregate function.
         */
        texpr = strip_implicit_coercions((Node *) tle->expr);

        if (equal(expr, texpr))
            return tle;
    }

    /*
     * If no matches, construct a new target entry which is appended to the
     * end of the target list.  This target is given resjunk = TRUE so that it
     * will not be projected into the final tuple.
     */
    target_result = transformTargetEntry(pstate, node, expr, exprKind,
                                         NULL, true);

    *tlist = lappend(*tlist, target_result);

    return target_result;
}

static WindowClause * findWindowClause ( List wclist,
const char *  name 
) [static]

Definition at line 2294 of file parse_clause.c.

References lfirst, and WindowClause::name.

Referenced by transformWindowDefinitions().

{
    ListCell   *l;

    foreach(l, wclist)
    {
        WindowClause *wc = (WindowClause *) lfirst(l);

        if (wc->name && strcmp(wc->name, name) == 0)
            return wc;
    }

    return NULL;
}

static int get_matching_location ( int  sortgroupref,
List sortgrouprefs,
List exprs 
) [static]

Definition at line 1992 of file parse_clause.c.

References elog, ERROR, exprLocation(), forboth, lfirst, and lfirst_int.

Referenced by transformDistinctOnClause().

{
    ListCell   *lcs;
    ListCell   *lce;

    forboth(lcs, sortgrouprefs, lce, exprs)
    {
        if (lfirst_int(lcs) == sortgroupref)
            return exprLocation((Node *) lfirst(lce));
    }
    /* if no match, caller blew it */
    elog(ERROR, "get_matching_location: no matching sortgroupref");
    return -1;                  /* keep compiler quiet */
}

bool interpretInhOption ( InhOption  inhOpt  ) 

Definition at line 226 of file parse_clause.c.

References elog, ERROR, INH_DEFAULT, INH_NO, INH_YES, and SQL_inheritance.

Referenced by AlterTable(), ExecuteTruncate(), LockTableCommand(), renameatt(), RenameConstraint(), transformDeleteStmt(), transformTableEntry(), and transformUpdateStmt().

{
    switch (inhOpt)
    {
        case INH_NO:
            return false;
        case INH_YES:
            return true;
        case INH_DEFAULT:
            return SQL_inheritance;
    }
    elog(ERROR, "bogus InhOption value: %d", inhOpt);
    return false;               /* keep compiler quiet */
}

bool interpretOidsOption ( List defList,
bool  allowOids 
)

Definition at line 252 of file parse_clause.c.

References default_with_oids, defGetBoolean(), DefElem::defname, DefElem::defnamespace, ereport, errcode(), errmsg(), ERROR, lfirst, NULL, and pg_strcasecmp().

Referenced by DefineRelation(), GetIntoRelEFlags(), and transformCreateStmt().

{
    ListCell   *cell;

    /* Scan list to see if OIDS was included */
    foreach(cell, defList)
    {
        DefElem    *def = (DefElem *) lfirst(cell);

        if (def->defnamespace == NULL &&
            pg_strcasecmp(def->defname, "oids") == 0)
        {
            if (!allowOids)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("unrecognized parameter \"%s\"",
                                def->defname)));
            return defGetBoolean(def);
        }
    }

    /* Force no-OIDS result if caller disallows OIDS. */
    if (!allowOids)
        return false;

    /* OIDS option was not specified, so use default. */
    return default_with_oids;
}

static ParseNamespaceItem * makeNamespaceItem ( RangeTblEntry rte,
bool  rel_visible,
bool  cols_visible,
bool  lateral_only,
bool  lateral_ok 
) [static]

Definition at line 1133 of file parse_clause.c.

References ParseNamespaceItem::p_cols_visible, ParseNamespaceItem::p_lateral_ok, ParseNamespaceItem::p_lateral_only, ParseNamespaceItem::p_rel_visible, ParseNamespaceItem::p_rte, and palloc().

{
    ParseNamespaceItem *nsitem;

    nsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
    nsitem->p_rte = rte;
    nsitem->p_rel_visible = rel_visible;
    nsitem->p_cols_visible = cols_visible;
    nsitem->p_lateral_only = lateral_only;
    nsitem->p_lateral_ok = lateral_ok;
    return nsitem;
}

static void setNamespaceColumnVisibility ( List namespace,
bool  cols_visible 
) [static]

Definition at line 1152 of file parse_clause.c.

References lfirst, and ParseNamespaceItem::p_cols_visible.

Referenced by transformFromClauseItem().

{
    ListCell   *lc;

    foreach(lc, namespace)
    {
        ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(lc);

        nsitem->p_cols_visible = cols_visible;
    }
}

static void setNamespaceLateralState ( List namespace,
bool  lateral_only,
bool  lateral_ok 
) [static]

Definition at line 1169 of file parse_clause.c.

References lfirst, ParseNamespaceItem::p_lateral_ok, and ParseNamespaceItem::p_lateral_only.

Referenced by transformFromClause(), transformFromClauseItem(), and transformJoinOnClause().

{
    ListCell   *lc;

    foreach(lc, namespace)
    {
        ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(lc);

        nsitem->p_lateral_only = lateral_only;
        nsitem->p_lateral_ok = lateral_ok;
    }
}

int setTargetTable ( ParseState pstate,
RangeVar relation,
bool  inh,
bool  alsoSource,
AclMode  requiredPerms 
)

Definition at line 166 of file parse_clause.c.

References addRangeTableEntryForRelation(), addRTEtoQuery(), RangeVar::alias, Assert, heap_close, list_length(), NoLock, NULL, ParseState::p_rtable, ParseState::p_target_rangetblentry, ParseState::p_target_relation, parserOpenTable(), RangeTblEntry::requiredPerms, RowExclusiveLock, and rt_fetch.

Referenced by transformDeleteStmt(), transformInsertStmt(), and transformUpdateStmt().

{
    RangeTblEntry *rte;
    int         rtindex;

    /* Close old target; this could only happen for multi-action rules */
    if (pstate->p_target_relation != NULL)
        heap_close(pstate->p_target_relation, NoLock);

    /*
     * Open target rel and grab suitable lock (which we will hold till end of
     * transaction).
     *
     * free_parsestate() will eventually do the corresponding heap_close(),
     * but *not* release the lock.
     */
    pstate->p_target_relation = parserOpenTable(pstate, relation,
                                                RowExclusiveLock);

    /*
     * Now build an RTE.
     */
    rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
                                        relation->alias, inh, false);
    pstate->p_target_rangetblentry = rte;

    /* assume new rte is at end */
    rtindex = list_length(pstate->p_rtable);
    Assert(rte == rt_fetch(rtindex, pstate->p_rtable));

    /*
     * Override addRangeTableEntry's default ACL_SELECT permissions check, and
     * instead mark target table as requiring exactly the specified
     * permissions.
     *
     * If we find an explicit reference to the rel later during parse
     * analysis, we will add the ACL_SELECT bit back again; see
     * markVarForSelectPriv and its callers.
     */
    rte->requiredPerms = requiredPerms;

    /*
     * If UPDATE/DELETE, add table to joinlist and namespace.
     */
    if (alsoSource)
        addRTEtoQuery(pstate, rte, true, true, true);

    return rtindex;
}

bool targetIsInSortList ( TargetEntry tle,
Oid  sortop,
List sortList 
)

Definition at line 2267 of file parse_clause.c.

References get_commutator(), InvalidOid, lfirst, TargetEntry::ressortgroupref, SortGroupClause::sortop, and SortGroupClause::tleSortGroupRef.

Referenced by addTargetToGroupList(), addTargetToSortList(), examine_simple_variable(), qual_is_pushdown_safe(), transformDistinctOnClause(), and transformGroupClause().

{
    Index       ref = tle->ressortgroupref;
    ListCell   *l;

    /* no need to scan list if tle has no marker */
    if (ref == 0)
        return false;

    foreach(l, sortList)
    {
        SortGroupClause *scl = (SortGroupClause *) lfirst(l);

        if (scl->tleSortGroupRef == ref &&
            (sortop == InvalidOid ||
             sortop == scl->sortop ||
             sortop == get_commutator(scl->sortop)))
            return true;
    }
    return false;
}

static RangeTblEntry * transformCTEReference ( ParseState pstate,
RangeVar r,
CommonTableExpr cte,
Index  levelsup 
) [static]

Definition at line 436 of file parse_clause.c.

References addRangeTableEntryForCTE().

Referenced by transformFromClauseItem().

{
    RangeTblEntry *rte;

    rte = addRangeTableEntryForCTE(pstate, cte, levelsup, r, true);

    return rte;
}

List* transformDistinctClause ( ParseState pstate,
List **  targetlist,
List sortClause,
bool  is_agg 
)

Definition at line 1819 of file parse_clause.c.

References addTargetToGroupList(), copyObject(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprLocation(), get_sortgroupclause_tle(), lappend(), lfirst, parser_errposition(), and TargetEntry::resjunk.

Referenced by transformAggregateCall(), and transformSelectStmt().

{
    List       *result = NIL;
    ListCell   *slitem;
    ListCell   *tlitem;

    /*
     * The distinctClause should consist of all ORDER BY items followed by all
     * other non-resjunk targetlist items.  There must not be any resjunk
     * ORDER BY items --- that would imply that we are sorting by a value that
     * isn't necessarily unique within a DISTINCT group, so the results
     * wouldn't be well-defined.  This construction ensures we follow the rule
     * that sortClause and distinctClause match; in fact the sortClause will
     * always be a prefix of distinctClause.
     *
     * Note a corner case: the same TLE could be in the ORDER BY list multiple
     * times with different sortops.  We have to include it in the
     * distinctClause the same way to preserve the prefix property. The net
     * effect will be that the TLE value will be made unique according to both
     * sortops.
     */
    foreach(slitem, sortClause)
    {
        SortGroupClause *scl = (SortGroupClause *) lfirst(slitem);
        TargetEntry *tle = get_sortgroupclause_tle(scl, *targetlist);

        if (tle->resjunk)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                     is_agg ?
                     errmsg("in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list") :
                     errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list"),
                     parser_errposition(pstate,
                                        exprLocation((Node *) tle->expr))));
        result = lappend(result, copyObject(scl));
    }

    /*
     * Now add any remaining non-resjunk tlist items, using default sort/group
     * semantics for their data types.
     */
    foreach(tlitem, *targetlist)
    {
        TargetEntry *tle = (TargetEntry *) lfirst(tlitem);

        if (tle->resjunk)
            continue;           /* ignore junk */
        result = addTargetToGroupList(pstate, tle,
                                      result, *targetlist,
                                      exprLocation((Node *) tle->expr),
                                      true);
    }

    return result;
}

List* transformDistinctOnClause ( ParseState pstate,
List distinctlist,
List **  targetlist,
List sortClause 
)

Definition at line 1890 of file parse_clause.c.

References addTargetToGroupList(), assignSortGroupRef(), copyObject(), ereport, errcode(), errmsg(), ERROR, EXPR_KIND_DISTINCT_ON, exprLocation(), findTargetlistEntrySQL92(), forboth, get_matching_location(), get_sortgroupref_tle(), InvalidOid, lappend(), lappend_int(), lfirst, lfirst_int, list_member_int(), parser_errposition(), targetIsInSortList(), and SortGroupClause::tleSortGroupRef.

Referenced by transformSelectStmt().

{
    List       *result = NIL;
    List       *sortgrouprefs = NIL;
    bool        skipped_sortitem;
    ListCell   *lc;
    ListCell   *lc2;

    /*
     * Add all the DISTINCT ON expressions to the tlist (if not already
     * present, they are added as resjunk items).  Assign sortgroupref numbers
     * to them, and make a list of these numbers.  (NB: we rely below on the
     * sortgrouprefs list being one-for-one with the original distinctlist.
     * Also notice that we could have duplicate DISTINCT ON expressions and
     * hence duplicate entries in sortgrouprefs.)
     */
    foreach(lc, distinctlist)
    {
        Node       *dexpr = (Node *) lfirst(lc);
        int         sortgroupref;
        TargetEntry *tle;

        tle = findTargetlistEntrySQL92(pstate, dexpr, targetlist,
                                       EXPR_KIND_DISTINCT_ON);
        sortgroupref = assignSortGroupRef(tle, *targetlist);
        sortgrouprefs = lappend_int(sortgrouprefs, sortgroupref);
    }

    /*
     * If the user writes both DISTINCT ON and ORDER BY, adopt the sorting
     * semantics from ORDER BY items that match DISTINCT ON items, and also
     * adopt their column sort order.  We insist that the distinctClause and
     * sortClause match, so throw error if we find the need to add any more
     * distinctClause items after we've skipped an ORDER BY item that wasn't
     * in DISTINCT ON.
     */
    skipped_sortitem = false;
    foreach(lc, sortClause)
    {
        SortGroupClause *scl = (SortGroupClause *) lfirst(lc);

        if (list_member_int(sortgrouprefs, scl->tleSortGroupRef))
        {
            if (skipped_sortitem)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                         errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"),
                         parser_errposition(pstate,
                                  get_matching_location(scl->tleSortGroupRef,
                                                        sortgrouprefs,
                                                        distinctlist))));
            else
                result = lappend(result, copyObject(scl));
        }
        else
            skipped_sortitem = true;
    }

    /*
     * Now add any remaining DISTINCT ON items, using default sort/group
     * semantics for their data types.  (Note: this is pretty questionable; if
     * the ORDER BY list doesn't include all the DISTINCT ON items and more
     * besides, you certainly aren't using DISTINCT ON in the intended way,
     * and you probably aren't going to get consistent results.  It might be
     * better to throw an error or warning here.  But historically we've
     * allowed it, so keep doing so.)
     */
    forboth(lc, distinctlist, lc2, sortgrouprefs)
    {
        Node       *dexpr = (Node *) lfirst(lc);
        int         sortgroupref = lfirst_int(lc2);
        TargetEntry *tle = get_sortgroupref_tle(sortgroupref, *targetlist);

        if (targetIsInSortList(tle, InvalidOid, result))
            continue;           /* already in list (with some semantics) */
        if (skipped_sortitem)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
                     errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"),
                     parser_errposition(pstate, exprLocation(dexpr))));
        result = addTargetToGroupList(pstate, tle,
                                      result, *targetlist,
                                      exprLocation(dexpr),
                                      true);
    }

    return result;
}

static Node * transformFrameOffset ( ParseState pstate,
int  frameOptions,
Node clause 
) [static]

Definition at line 2314 of file parse_clause.c.

References Assert, checkExprIsVarFree(), coerce_to_specific_type(), elog, ERROR, EXPR_KIND_WINDOW_FRAME_RANGE, EXPR_KIND_WINDOW_FRAME_ROWS, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, INT8OID, NULL, and transformExpr().

Referenced by transformWindowDefinitions().

{
    const char *constructName = NULL;
    Node       *node;

    /* Quick exit if no offset expression */
    if (clause == NULL)
        return NULL;

    if (frameOptions & FRAMEOPTION_ROWS)
    {
        /* Transform the raw expression tree */
        node = transformExpr(pstate, clause, EXPR_KIND_WINDOW_FRAME_ROWS);

        /*
         * Like LIMIT clause, simply coerce to int8
         */
        constructName = "ROWS";
        node = coerce_to_specific_type(pstate, node, INT8OID, constructName);
    }
    else if (frameOptions & FRAMEOPTION_RANGE)
    {
        /* Transform the raw expression tree */
        node = transformExpr(pstate, clause, EXPR_KIND_WINDOW_FRAME_RANGE);

        /*
         * this needs a lot of thought to decide how to support in the context
         * of Postgres' extensible datatype framework
         */
        constructName = "RANGE";
        /* error was already thrown by gram.y, this is just a backstop */
        elog(ERROR, "window frame with value offset is not implemented");
    }
    else
    {
        Assert(false);
        node = NULL;
    }

    /* Disallow variables in frame offsets */
    checkExprIsVarFree(pstate, node, constructName);

    return node;
}

void transformFromClause ( ParseState pstate,
List frmList 
)

Definition at line 100 of file parse_clause.c.

References checkNameSpaceConflicts(), lappend(), lfirst, list_concat(), ParseState::p_joinlist, ParseState::p_namespace, setNamespaceLateralState(), and transformFromClauseItem().

Referenced by transformDeleteStmt(), transformSelectStmt(), and transformUpdateStmt().

{
    ListCell   *fl;

    /*
     * The grammar will have produced a list of RangeVars, RangeSubselects,
     * RangeFunctions, and/or JoinExprs. Transform each one (possibly adding
     * entries to the rtable), check for duplicate refnames, and then add it
     * to the joinlist and namespace.
     *
     * Note we must process the items left-to-right for proper handling of
     * LATERAL references.
     */
    foreach(fl, frmList)
    {
        Node       *n = lfirst(fl);
        RangeTblEntry *rte;
        int         rtindex;
        List       *namespace;

        n = transformFromClauseItem(pstate, n,
                                    &rte,
                                    &rtindex,
                                    &namespace);

        checkNameSpaceConflicts(pstate, pstate->p_namespace, namespace);

        /* Mark the new namespace items as visible only to LATERAL */
        setNamespaceLateralState(namespace, true, true);

        pstate->p_joinlist = lappend(pstate->p_joinlist, n);
        pstate->p_namespace = list_concat(pstate->p_namespace, namespace);
    }

    /*
     * We're done parsing the FROM list, so make all namespace items
     * unconditionally visible.  Note that this will also reset lateral_only
     * for any namespace items that were already present when we were called;
     * but those should have been that way already.
     */
    setNamespaceLateralState(pstate->p_namespace, false, true);
}

static Node * transformFromClauseItem ( ParseState pstate,
Node n,
RangeTblEntry **  top_rte,
int *  top_rti,
List **  namespace 
) [static]

Definition at line 611 of file parse_clause.c.

References addRangeTableEntryForJoin(), JoinExpr::alias, Alias::aliasname, Assert, buildMergedJoinVar(), checkNameSpaceConflicts(), Alias::colnames, elog, ereport, errcode(), errmsg(), ERROR, expandRTE(), extractRemainingColumns(), IsA, JoinExpr::isNatural, JOIN_INNER, JoinExpr::jointype, lappend(), JoinExpr::larg, lfirst, list_concat(), list_length(), list_make1, list_nth(), list_truncate(), makeNode, makeString(), NIL, nodeTag, NULL, ParseState::p_joinexprs, ParseState::p_namespace, ParseState::p_rtable, JoinExpr::quals, JoinExpr::rarg, RangeVar::relname, rt_fetch, JoinExpr::rtindex, RangeTblRef::rtindex, scanNameSpaceForCTE(), RangeVar::schemaname, setNamespaceColumnVisibility(), setNamespaceLateralState(), strVal, transformCTEReference(), transformJoinOnClause(), transformJoinUsingClause(), transformRangeFunction(), transformRangeSubselect(), transformTableEntry(), and JoinExpr::usingClause.

Referenced by transformFromClause().

{
    if (IsA(n, RangeVar))
    {
        /* Plain relation reference, or perhaps a CTE reference */
        RangeVar   *rv = (RangeVar *) n;
        RangeTblRef *rtr;
        RangeTblEntry *rte = NULL;
        int         rtindex;

        /* if it is an unqualified name, it might be a CTE reference */
        if (!rv->schemaname)
        {
            CommonTableExpr *cte;
            Index       levelsup;

            cte = scanNameSpaceForCTE(pstate, rv->relname, &levelsup);
            if (cte)
                rte = transformCTEReference(pstate, rv, cte, levelsup);
        }

        /* if not found as a CTE, must be a table reference */
        if (!rte)
            rte = transformTableEntry(pstate, rv);

        /* assume new rte is at end */
        rtindex = list_length(pstate->p_rtable);
        Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
        *top_rte = rte;
        *top_rti = rtindex;
        *namespace = list_make1(makeDefaultNSItem(rte));
        rtr = makeNode(RangeTblRef);
        rtr->rtindex = rtindex;
        return (Node *) rtr;
    }
    else if (IsA(n, RangeSubselect))
    {
        /* sub-SELECT is like a plain relation */
        RangeTblRef *rtr;
        RangeTblEntry *rte;
        int         rtindex;

        rte = transformRangeSubselect(pstate, (RangeSubselect *) n);
        /* assume new rte is at end */
        rtindex = list_length(pstate->p_rtable);
        Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
        *top_rte = rte;
        *top_rti = rtindex;
        *namespace = list_make1(makeDefaultNSItem(rte));
        rtr = makeNode(RangeTblRef);
        rtr->rtindex = rtindex;
        return (Node *) rtr;
    }
    else if (IsA(n, RangeFunction))
    {
        /* function is like a plain relation */
        RangeTblRef *rtr;
        RangeTblEntry *rte;
        int         rtindex;

        rte = transformRangeFunction(pstate, (RangeFunction *) n);
        /* assume new rte is at end */
        rtindex = list_length(pstate->p_rtable);
        Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
        *top_rte = rte;
        *top_rti = rtindex;
        *namespace = list_make1(makeDefaultNSItem(rte));
        rtr = makeNode(RangeTblRef);
        rtr->rtindex = rtindex;
        return (Node *) rtr;
    }
    else if (IsA(n, JoinExpr))
    {
        /* A newfangled join expression */
        JoinExpr   *j = (JoinExpr *) n;
        RangeTblEntry *l_rte;
        RangeTblEntry *r_rte;
        int         l_rtindex;
        int         r_rtindex;
        List       *l_namespace,
                   *r_namespace,
                   *my_namespace,
                   *l_colnames,
                   *r_colnames,
                   *res_colnames,
                   *l_colvars,
                   *r_colvars,
                   *res_colvars;
        bool        lateral_ok;
        int         sv_namespace_length;
        RangeTblEntry *rte;
        int         k;

        /*
         * Recursively process the left subtree, then the right.  We must do
         * it in this order for correct visibility of LATERAL references.
         */
        j->larg = transformFromClauseItem(pstate, j->larg,
                                          &l_rte,
                                          &l_rtindex,
                                          &l_namespace);

        /*
         * Make the left-side RTEs available for LATERAL access within the
         * right side, by temporarily adding them to the pstate's namespace
         * list.  Per SQL:2008, if the join type is not INNER or LEFT then
         * the left-side names must still be exposed, but it's an error to
         * reference them.  (Stupid design, but that's what it says.)  Hence,
         * we always push them into the namespace, but mark them as not
         * lateral_ok if the jointype is wrong.
         *
         * NB: this coding relies on the fact that list_concat is not
         * destructive to its second argument.
         */
        lateral_ok = (j->jointype == JOIN_INNER || j->jointype == JOIN_LEFT);
        setNamespaceLateralState(l_namespace, true, lateral_ok);

        checkNameSpaceConflicts(pstate, pstate->p_namespace, l_namespace);

        sv_namespace_length = list_length(pstate->p_namespace);
        pstate->p_namespace = list_concat(pstate->p_namespace, l_namespace);

        /* And now we can process the RHS */
        j->rarg = transformFromClauseItem(pstate, j->rarg,
                                          &r_rte,
                                          &r_rtindex,
                                          &r_namespace);

        /* Remove the left-side RTEs from the namespace list again */
        pstate->p_namespace = list_truncate(pstate->p_namespace,
                                            sv_namespace_length);

        /*
         * Check for conflicting refnames in left and right subtrees. Must do
         * this because higher levels will assume I hand back a self-
         * consistent namespace list.
         */
        checkNameSpaceConflicts(pstate, l_namespace, r_namespace);

        /*
         * Generate combined namespace info for possible use below.
         */
        my_namespace = list_concat(l_namespace, r_namespace);

        /*
         * Extract column name and var lists from both subtrees
         *
         * Note: expandRTE returns new lists, safe for me to modify
         */
        expandRTE(l_rte, l_rtindex, 0, -1, false,
                  &l_colnames, &l_colvars);
        expandRTE(r_rte, r_rtindex, 0, -1, false,
                  &r_colnames, &r_colvars);

        /*
         * Natural join does not explicitly specify columns; must generate
         * columns to join. Need to run through the list of columns from each
         * table or join result and match up the column names. Use the first
         * table, and check every column in the second table for a match.
         * (We'll check that the matches were unique later on.) The result of
         * this step is a list of column names just like an explicitly-written
         * USING list.
         */
        if (j->isNatural)
        {
            List       *rlist = NIL;
            ListCell   *lx,
                       *rx;

            Assert(j->usingClause == NIL);      /* shouldn't have USING() too */

            foreach(lx, l_colnames)
            {
                char       *l_colname = strVal(lfirst(lx));
                Value      *m_name = NULL;

                foreach(rx, r_colnames)
                {
                    char       *r_colname = strVal(lfirst(rx));

                    if (strcmp(l_colname, r_colname) == 0)
                    {
                        m_name = makeString(l_colname);
                        break;
                    }
                }

                /* matched a right column? then keep as join column... */
                if (m_name != NULL)
                    rlist = lappend(rlist, m_name);
            }

            j->usingClause = rlist;
        }

        /*
         * Now transform the join qualifications, if any.
         */
        res_colnames = NIL;
        res_colvars = NIL;

        if (j->usingClause)
        {
            /*
             * JOIN/USING (or NATURAL JOIN, as transformed above). Transform
             * the list into an explicit ON-condition, and generate a list of
             * merged result columns.
             */
            List       *ucols = j->usingClause;
            List       *l_usingvars = NIL;
            List       *r_usingvars = NIL;
            ListCell   *ucol;

            Assert(j->quals == NULL);   /* shouldn't have ON() too */

            foreach(ucol, ucols)
            {
                char       *u_colname = strVal(lfirst(ucol));
                ListCell   *col;
                int         ndx;
                int         l_index = -1;
                int         r_index = -1;
                Var        *l_colvar,
                           *r_colvar;

                /* Check for USING(foo,foo) */
                foreach(col, res_colnames)
                {
                    char       *res_colname = strVal(lfirst(col));

                    if (strcmp(res_colname, u_colname) == 0)
                        ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_COLUMN),
                                 errmsg("column name \"%s\" appears more than once in USING clause",
                                        u_colname)));
                }

                /* Find it in left input */
                ndx = 0;
                foreach(col, l_colnames)
                {
                    char       *l_colname = strVal(lfirst(col));

                    if (strcmp(l_colname, u_colname) == 0)
                    {
                        if (l_index >= 0)
                            ereport(ERROR,
                                    (errcode(ERRCODE_AMBIGUOUS_COLUMN),
                                     errmsg("common column name \"%s\" appears more than once in left table",
                                            u_colname)));
                        l_index = ndx;
                    }
                    ndx++;
                }
                if (l_index < 0)
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_COLUMN),
                             errmsg("column \"%s\" specified in USING clause does not exist in left table",
                                    u_colname)));

                /* Find it in right input */
                ndx = 0;
                foreach(col, r_colnames)
                {
                    char       *r_colname = strVal(lfirst(col));

                    if (strcmp(r_colname, u_colname) == 0)
                    {
                        if (r_index >= 0)
                            ereport(ERROR,
                                    (errcode(ERRCODE_AMBIGUOUS_COLUMN),
                                     errmsg("common column name \"%s\" appears more than once in right table",
                                            u_colname)));
                        r_index = ndx;
                    }
                    ndx++;
                }
                if (r_index < 0)
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_COLUMN),
                             errmsg("column \"%s\" specified in USING clause does not exist in right table",
                                    u_colname)));

                l_colvar = list_nth(l_colvars, l_index);
                l_usingvars = lappend(l_usingvars, l_colvar);
                r_colvar = list_nth(r_colvars, r_index);
                r_usingvars = lappend(r_usingvars, r_colvar);

                res_colnames = lappend(res_colnames, lfirst(ucol));
                res_colvars = lappend(res_colvars,
                                      buildMergedJoinVar(pstate,
                                                         j->jointype,
                                                         l_colvar,
                                                         r_colvar));
            }

            j->quals = transformJoinUsingClause(pstate,
                                                l_rte,
                                                r_rte,
                                                l_usingvars,
                                                r_usingvars);
        }
        else if (j->quals)
        {
            /* User-written ON-condition; transform it */
            j->quals = transformJoinOnClause(pstate, j, my_namespace);
        }
        else
        {
            /* CROSS JOIN: no quals */
        }

        /* Add remaining columns from each side to the output columns */
        extractRemainingColumns(res_colnames,
                                l_colnames, l_colvars,
                                &l_colnames, &l_colvars);
        extractRemainingColumns(res_colnames,
                                r_colnames, r_colvars,
                                &r_colnames, &r_colvars);
        res_colnames = list_concat(res_colnames, l_colnames);
        res_colvars = list_concat(res_colvars, l_colvars);
        res_colnames = list_concat(res_colnames, r_colnames);
        res_colvars = list_concat(res_colvars, r_colvars);

        /*
         * Check alias (AS clause), if any.
         */
        if (j->alias)
        {
            if (j->alias->colnames != NIL)
            {
                if (list_length(j->alias->colnames) > list_length(res_colnames))
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("column alias list for \"%s\" has too many entries",
                                    j->alias->aliasname)));
            }
        }

        /*
         * Now build an RTE for the result of the join
         */
        rte = addRangeTableEntryForJoin(pstate,
                                        res_colnames,
                                        j->jointype,
                                        res_colvars,
                                        j->alias,
                                        true);

        /* assume new rte is at end */
        j->rtindex = list_length(pstate->p_rtable);
        Assert(rte == rt_fetch(j->rtindex, pstate->p_rtable));

        *top_rte = rte;
        *top_rti = j->rtindex;

        /* make a matching link to the JoinExpr for later use */
        for (k = list_length(pstate->p_joinexprs) + 1; k < j->rtindex; k++)
            pstate->p_joinexprs = lappend(pstate->p_joinexprs, NULL);
        pstate->p_joinexprs = lappend(pstate->p_joinexprs, j);
        Assert(list_length(pstate->p_joinexprs) == j->rtindex);

        /*
         * Prepare returned namespace list.  If the JOIN has an alias then it
         * hides the contained RTEs completely; otherwise, the contained RTEs
         * are still visible as table names, but are not visible for
         * unqualified column-name access.
         *
         * Note: if there are nested alias-less JOINs, the lower-level ones
         * will remain in the list although they have neither p_rel_visible
         * nor p_cols_visible set.  We could delete such list items, but it's
         * unclear that it's worth expending cycles to do so.
         */
        if (j->alias != NULL)
            my_namespace = NIL;
        else
            setNamespaceColumnVisibility(my_namespace, false);

        /*
         * The join RTE itself is always made visible for unqualified column
         * names.  It's visible as a relation name only if it has an alias.
         */
        *namespace = lappend(my_namespace,
                             makeNamespaceItem(rte,
                                               (j->alias != NULL),
                                               true,
                                               false,
                                               true));

        return (Node *) j;
    }
    else
        elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n));
    return NULL;                /* can't get here, keep compiler quiet */
}

List* transformGroupClause ( ParseState pstate,
List grouplist,
List **  targetlist,
List sortClause,
ParseExprKind  exprKind,
bool  useSQL99 
)

Definition at line 1557 of file parse_clause.c.

References addTargetToGroupList(), copyObject(), exprLocation(), findTargetlistEntrySQL92(), findTargetlistEntrySQL99(), InvalidOid, lappend(), lfirst, TargetEntry::ressortgroupref, targetIsInSortList(), and SortGroupClause::tleSortGroupRef.

Referenced by transformSelectStmt(), and transformWindowDefinitions().

{
    List       *result = NIL;
    ListCell   *gl;

    foreach(gl, grouplist)
    {
        Node       *gexpr = (Node *) lfirst(gl);
        TargetEntry *tle;
        bool        found = false;

        if (useSQL99)
            tle = findTargetlistEntrySQL99(pstate, gexpr,
                                           targetlist, exprKind);
        else
            tle = findTargetlistEntrySQL92(pstate, gexpr,
                                           targetlist, exprKind);

        /* Eliminate duplicates (GROUP BY x, x) */
        if (targetIsInSortList(tle, InvalidOid, result))
            continue;

        /*
         * If the GROUP BY tlist entry also appears in ORDER BY, copy operator
         * info from the (first) matching ORDER BY item.  This means that if
         * you write something like "GROUP BY foo ORDER BY foo USING <<<", the
         * GROUP BY operation silently takes on the equality semantics implied
         * by the ORDER BY.  There are two reasons to do this: it improves the
         * odds that we can implement both GROUP BY and ORDER BY with a single
         * sort step, and it allows the user to choose the equality semantics
         * used by GROUP BY, should she be working with a datatype that has
         * more than one equality operator.
         */
        if (tle->ressortgroupref > 0)
        {
            ListCell   *sl;

            foreach(sl, sortClause)
            {
                SortGroupClause *sc = (SortGroupClause *) lfirst(sl);

                if (sc->tleSortGroupRef == tle->ressortgroupref)
                {
                    result = lappend(result, copyObject(sc));
                    found = true;
                    break;
                }
            }
        }

        /*
         * If no match in ORDER BY, just add it to the result using default
         * sort/group semantics.
         */
        if (!found)
            result = addTargetToGroupList(pstate, tle,
                                          result, *targetlist,
                                          exprLocation(gexpr),
                                          true);
    }

    return result;
}

static Node * transformJoinOnClause ( ParseState pstate,
JoinExpr j,
List namespace 
) [static]

Definition at line 390 of file parse_clause.c.

References EXPR_KIND_JOIN_ON, ParseState::p_namespace, JoinExpr::quals, setNamespaceLateralState(), and transformWhereClause().

Referenced by transformFromClauseItem().

{
    Node       *result;
    List       *save_namespace;

    /*
     * The namespace that the join expression should see is just the two
     * subtrees of the JOIN plus any outer references from upper pstate
     * levels.  Temporarily set this pstate's namespace accordingly.  (We need
     * not check for refname conflicts, because transformFromClauseItem()
     * already did.)  All namespace items are marked visible regardless of
     * LATERAL state.
     */
    setNamespaceLateralState(namespace, false, true);

    save_namespace = pstate->p_namespace;
    pstate->p_namespace = namespace;

    result = transformWhereClause(pstate, j->quals,
                                  EXPR_KIND_JOIN_ON, "JOIN/ON");

    pstate->p_namespace = save_namespace;

    return result;
}

static Node * transformJoinUsingClause ( ParseState pstate,
RangeTblEntry leftRTE,
RangeTblEntry rightRTE,
List leftVars,
List rightVars 
) [static]

Definition at line 330 of file parse_clause.c.

References AEXPR_AND, AEXPR_OP, coerce_to_boolean(), copyObject(), EXPR_KIND_JOIN_USING, forboth, lfirst, makeA_Expr(), makeSimpleA_Expr(), markVarForSelectPriv(), NIL, NULL, and transformExpr().

Referenced by transformFromClauseItem().

{
    Node       *result = NULL;
    ListCell   *lvars,
               *rvars;

    /*
     * We cheat a little bit here by building an untransformed operator tree
     * whose leaves are the already-transformed Vars.  This is OK because
     * transformExpr() won't complain about already-transformed subnodes.
     * However, this does mean that we have to mark the columns as requiring
     * SELECT privilege for ourselves; transformExpr() won't do it.
     */
    forboth(lvars, leftVars, rvars, rightVars)
    {
        Var        *lvar = (Var *) lfirst(lvars);
        Var        *rvar = (Var *) lfirst(rvars);
        A_Expr     *e;

        /* Require read access to the join variables */
        markVarForSelectPriv(pstate, lvar, leftRTE);
        markVarForSelectPriv(pstate, rvar, rightRTE);

        /* Now create the lvar = rvar join condition */
        e = makeSimpleA_Expr(AEXPR_OP, "=",
                             copyObject(lvar), copyObject(rvar),
                             -1);

        /* And combine into an AND clause, if multiple join columns */
        if (result == NULL)
            result = (Node *) e;
        else
        {
            A_Expr     *a;

            a = makeA_Expr(AEXPR_AND, NIL, result, (Node *) e, -1);
            result = (Node *) a;
        }
    }

    /*
     * Since the references are already Vars, and are certainly from the input
     * relations, we don't have to go through the same pushups that
     * transformJoinOnClause() does.  Just invoke transformExpr() to fix up
     * the operators, and we're done.
     */
    result = transformExpr(pstate, result, EXPR_KIND_JOIN_USING);

    result = coerce_to_boolean(pstate, result, "JOIN/USING");

    return result;
}

Node* transformLimitClause ( ParseState pstate,
Node clause,
ParseExprKind  exprKind,
const char *  constructName 
)

Definition at line 1218 of file parse_clause.c.

References checkExprIsVarFree(), coerce_to_specific_type(), INT8OID, NULL, and transformExpr().

Referenced by transformSelectStmt(), transformSetOperationStmt(), and transformValuesClause().

{
    Node       *qual;

    if (clause == NULL)
        return NULL;

    qual = transformExpr(pstate, clause, exprKind);

    qual = coerce_to_specific_type(pstate, qual, INT8OID, constructName);

    /* LIMIT can't refer to any variables of the current query */
    checkExprIsVarFree(pstate, qual, constructName);

    return qual;
}

static RangeTblEntry * transformRangeFunction ( ParseState pstate,
RangeFunction r 
) [static]

Definition at line 517 of file parse_clause.c.

References addRangeTableEntryForFunction(), Assert, assign_expr_collations(), BuildDescFromLists(), CheckAttributeNamesTypes(), RangeFunction::coldeflist, Alias::colnames, contain_vars_of_level(), RangeTblEntry::eref, EXPR_KIND_FROM_FUNCTION, FigureColname(), RangeFunction::funccallnode, RangeTblEntry::funccolcollations, RangeTblEntry::funccoltypes, RangeTblEntry::funccoltypmods, RangeFunction::lateral, ParseState::p_lateral_active, RELKIND_COMPOSITE_TYPE, and transformExpr().

Referenced by transformFromClauseItem().

{
    Node       *funcexpr;
    char       *funcname;
    bool        is_lateral;
    RangeTblEntry *rte;

    /*
     * Get function name for possible use as alias.  We use the same
     * transformation rules as for a SELECT output expression.  For a FuncCall
     * node, the result will be the function name, but it is possible for the
     * grammar to hand back other node types.
     */
    funcname = FigureColname(r->funccallnode);

    /*
     * We make lateral_only names of this level visible, whether or not the
     * function is explicitly marked LATERAL.  This is needed for SQL spec
     * compliance in the case of UNNEST(), and seems useful on convenience
     * grounds for all functions in FROM.
     *
     * (LATERAL can't nest within a single pstate level, so we don't need
     * save/restore logic here.)
     */
    Assert(!pstate->p_lateral_active);
    pstate->p_lateral_active = true;

    /*
     * Transform the raw expression.
     */
    funcexpr = transformExpr(pstate, r->funccallnode, EXPR_KIND_FROM_FUNCTION);

    pstate->p_lateral_active = false;

    /*
     * We must assign collations now so that we can fill funccolcollations.
     */
    assign_expr_collations(pstate, funcexpr);

    /*
     * Mark the RTE as LATERAL if the user said LATERAL explicitly, or if
     * there are any lateral cross-references in it.
     */
    is_lateral = r->lateral || contain_vars_of_level(funcexpr, 0);

    /*
     * OK, build an RTE for the function.
     */
    rte = addRangeTableEntryForFunction(pstate, funcname, funcexpr,
                                        r, is_lateral, true);

    /*
     * If a coldeflist was supplied, ensure it defines a legal set of names
     * (no duplicates) and datatypes (no pseudo-types, for instance).
     * addRangeTableEntryForFunction looked up the type names but didn't check
     * them further than that.
     */
    if (r->coldeflist)
    {
        TupleDesc   tupdesc;

        tupdesc = BuildDescFromLists(rte->eref->colnames,
                                     rte->funccoltypes,
                                     rte->funccoltypmods,
                                     rte->funccolcollations);
        CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE, false);
    }

    return rte;
}

static RangeTblEntry * transformRangeSubselect ( ParseState pstate,
RangeSubselect r 
) [static]

Definition at line 450 of file parse_clause.c.

References addRangeTableEntryForSubquery(), RangeSubselect::alias, Alias::aliasname, Assert, CMD_SELECT, Query::commandType, elog, ERROR, EXPR_KIND_NONE, IsA, isLockedRefname(), RangeSubselect::lateral, NULL, ParseState::p_expr_kind, ParseState::p_lateral_active, parse_sub_analyze(), RangeSubselect::subquery, and Query::utilityStmt.

Referenced by transformFromClauseItem().

{
    Query      *query;
    RangeTblEntry *rte;

    /*
     * We require user to supply an alias for a subselect, per SQL92. To relax
     * this, we'd have to be prepared to gin up a unique alias for an
     * unlabeled subselect.  (This is just elog, not ereport, because the
     * grammar should have enforced it already.  It'd probably be better to
     * report the error here, but we don't have a good error location here.)
     */
    if (r->alias == NULL)
        elog(ERROR, "subquery in FROM must have an alias");

    /*
     * Set p_expr_kind to show this parse level is recursing to a subselect.
     * We can't be nested within any expression, so don't need save-restore
     * logic here.
     */
    Assert(pstate->p_expr_kind == EXPR_KIND_NONE);
    pstate->p_expr_kind = EXPR_KIND_FROM_SUBSELECT;

    /*
     * If the subselect is LATERAL, make lateral_only names of this level
     * visible to it.  (LATERAL can't nest within a single pstate level, so we
     * don't need save/restore logic here.)
     */
    Assert(!pstate->p_lateral_active);
    pstate->p_lateral_active = r->lateral;

    /*
     * Analyze and transform the subquery.
     */
    query = parse_sub_analyze(r->subquery, pstate, NULL,
                              isLockedRefname(pstate, r->alias->aliasname));

    /* Restore state */
    pstate->p_lateral_active = false;
    pstate->p_expr_kind = EXPR_KIND_NONE;

    /*
     * Check that we got something reasonable.  Many of these conditions are
     * impossible given restrictions of the grammar, but check 'em anyway.
     */
    if (!IsA(query, Query) ||
        query->commandType != CMD_SELECT ||
        query->utilityStmt != NULL)
        elog(ERROR, "unexpected non-SELECT command in subquery in FROM");

    /*
     * OK, build an RTE for the subquery.
     */
    rte = addRangeTableEntryForSubquery(pstate,
                                        query,
                                        r->alias,
                                        r->lateral,
                                        true);

    return rte;
}

List* transformSortClause ( ParseState pstate,
List orderlist,
List **  targetlist,
ParseExprKind  exprKind,
bool  resolveUnknown,
bool  useSQL99 
)

Definition at line 1634 of file parse_clause.c.

References addTargetToSortList(), findTargetlistEntrySQL92(), findTargetlistEntrySQL99(), lfirst, and SortBy::node.

Referenced by transformAggregateCall(), transformSelectStmt(), transformSetOperationStmt(), transformValuesClause(), and transformWindowDefinitions().

{
    List       *sortlist = NIL;
    ListCell   *olitem;

    foreach(olitem, orderlist)
    {
        SortBy     *sortby = (SortBy *) lfirst(olitem);
        TargetEntry *tle;

        if (useSQL99)
            tle = findTargetlistEntrySQL99(pstate, sortby->node,
                                           targetlist, exprKind);
        else
            tle = findTargetlistEntrySQL92(pstate, sortby->node,
                                           targetlist, exprKind);

        sortlist = addTargetToSortList(pstate, tle,
                                       sortlist, *targetlist, sortby,
                                       resolveUnknown);
    }

    return sortlist;
}

static RangeTblEntry * transformTableEntry ( ParseState pstate,
RangeVar r 
) [static]

Definition at line 420 of file parse_clause.c.

References addRangeTableEntry(), RangeVar::alias, RangeVar::inhOpt, and interpretInhOption().

Referenced by transformFromClauseItem().

{
    RangeTblEntry *rte;

    /* We need only build a range table entry */
    rte = addRangeTableEntry(pstate, r, r->alias,
                             interpretInhOption(r->inhOpt), true);

    return rte;
}

Node* transformWhereClause ( ParseState pstate,
Node clause,
ParseExprKind  exprKind,
const char *  constructName 
)

Definition at line 1191 of file parse_clause.c.

References coerce_to_boolean(), NULL, and transformExpr().

Referenced by CreateTrigger(), transformDeleteStmt(), transformIndexStmt(), transformJoinOnClause(), transformRuleStmt(), transformSelectStmt(), and transformUpdateStmt().

{
    Node       *qual;

    if (clause == NULL)
        return NULL;

    qual = transformExpr(pstate, clause, exprKind);

    qual = coerce_to_boolean(pstate, qual, constructName);

    return qual;
}

List* transformWindowDefinitions ( ParseState pstate,
List windowdefs,
List **  targetlist 
)

Definition at line 1669 of file parse_clause.c.

References WindowClause::copiedOrder, copyObject(), WindowDef::endOffset, WindowClause::endOffset, ereport, errcode(), errmsg(), ERROR, EXPR_KIND_WINDOW_ORDER, EXPR_KIND_WINDOW_PARTITION, findWindowClause(), FRAMEOPTION_DEFAULTS, WindowDef::frameOptions, WindowClause::frameOptions, lappend(), lfirst, WindowDef::location, makeNode, WindowClause::name, WindowDef::name, NULL, WindowClause::orderClause, WindowDef::orderClause, parser_errposition(), WindowClause::partitionClause, WindowDef::partitionClause, WindowClause::refname, WindowDef::refname, WindowDef::startOffset, WindowClause::startOffset, transformFrameOffset(), transformGroupClause(), transformSortClause(), and WindowClause::winref.

Referenced by transformSelectStmt().

{
    List       *result = NIL;
    Index       winref = 0;
    ListCell   *lc;

    foreach(lc, windowdefs)
    {
        WindowDef  *windef = (WindowDef *) lfirst(lc);
        WindowClause *refwc = NULL;
        List       *partitionClause;
        List       *orderClause;
        WindowClause *wc;

        winref++;

        /*
         * Check for duplicate window names.
         */
        if (windef->name &&
            findWindowClause(result, windef->name) != NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_WINDOWING_ERROR),
                     errmsg("window \"%s\" is already defined", windef->name),
                     parser_errposition(pstate, windef->location)));

        /*
         * If it references a previous window, look that up.
         */
        if (windef->refname)
        {
            refwc = findWindowClause(result, windef->refname);
            if (refwc == NULL)
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_OBJECT),
                         errmsg("window \"%s\" does not exist",
                                windef->refname),
                         parser_errposition(pstate, windef->location)));
        }

        /*
         * Transform PARTITION and ORDER specs, if any.  These are treated
         * almost exactly like top-level GROUP BY and ORDER BY clauses,
         * including the special handling of nondefault operator semantics.
         */
        orderClause = transformSortClause(pstate,
                                          windef->orderClause,
                                          targetlist,
                                          EXPR_KIND_WINDOW_ORDER,
                                          true /* fix unknowns */ ,
                                          true /* force SQL99 rules */ );
        partitionClause = transformGroupClause(pstate,
                                               windef->partitionClause,
                                               targetlist,
                                               orderClause,
                                               EXPR_KIND_WINDOW_PARTITION,
                                               true /* force SQL99 rules */ );

        /*
         * And prepare the new WindowClause.
         */
        wc = makeNode(WindowClause);
        wc->name = windef->name;
        wc->refname = windef->refname;

        /*
         * Per spec, a windowdef that references a previous one copies the
         * previous partition clause (and mustn't specify its own).  It can
         * specify its own ordering clause. but only if the previous one had
         * none.  It always specifies its own frame clause, and the previous
         * one must not have a frame clause.  (Yeah, it's bizarre that each of
         * these cases works differently, but SQL:2008 says so; see 7.11
         * <window clause> syntax rule 10 and general rule 1.)
         */
        if (refwc)
        {
            if (partitionClause)
                ereport(ERROR,
                        (errcode(ERRCODE_WINDOWING_ERROR),
                errmsg("cannot override PARTITION BY clause of window \"%s\"",
                       windef->refname),
                         parser_errposition(pstate, windef->location)));
            wc->partitionClause = copyObject(refwc->partitionClause);
        }
        else
            wc->partitionClause = partitionClause;
        if (refwc)
        {
            if (orderClause && refwc->orderClause)
                ereport(ERROR,
                        (errcode(ERRCODE_WINDOWING_ERROR),
                   errmsg("cannot override ORDER BY clause of window \"%s\"",
                          windef->refname),
                         parser_errposition(pstate, windef->location)));
            if (orderClause)
            {
                wc->orderClause = orderClause;
                wc->copiedOrder = false;
            }
            else
            {
                wc->orderClause = copyObject(refwc->orderClause);
                wc->copiedOrder = true;
            }
        }
        else
        {
            wc->orderClause = orderClause;
            wc->copiedOrder = false;
        }
        if (refwc && refwc->frameOptions != FRAMEOPTION_DEFAULTS)
            ereport(ERROR,
                    (errcode(ERRCODE_WINDOWING_ERROR),
                     errmsg("cannot override frame clause of window \"%s\"",
                            windef->refname),
                     parser_errposition(pstate, windef->location)));
        wc->frameOptions = windef->frameOptions;
        /* Process frame offset expressions */
        wc->startOffset = transformFrameOffset(pstate, wc->frameOptions,
                                               windef->startOffset);
        wc->endOffset = transformFrameOffset(pstate, wc->frameOptions,
                                             windef->endOffset);
        wc->winref = winref;

        result = lappend(result, wc);
    }

    return result;
}