Header And Logo

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

Functions

prep.h File Reference

#include "nodes/plannodes.h"
#include "nodes/relation.h"
Include dependency graph for prep.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void pull_up_sublinks (PlannerInfo *root)
void inline_set_returning_functions (PlannerInfo *root)
Nodepull_up_subqueries (PlannerInfo *root, Node *jtnode)
void flatten_simple_union_all (PlannerInfo *root)
void reduce_outer_joins (PlannerInfo *root)
Relids get_relids_in_jointree (Node *jtnode, bool include_joins)
Relids get_relids_for_join (PlannerInfo *root, int joinrelid)
Nodenegate_clause (Node *node)
Exprcanonicalize_qual (Expr *qual)
Listpreprocess_targetlist (PlannerInfo *root, List *tlist)
PlanRowMarkget_plan_rowmark (List *rowmarks, Index rtindex)
Planplan_set_operations (PlannerInfo *root, double tuple_fraction, List **sortClauses)
void expand_inherited_tables (PlannerInfo *root)
Nodeadjust_appendrel_attrs (PlannerInfo *root, Node *node, AppendRelInfo *appinfo)

Function Documentation

Node* adjust_appendrel_attrs ( PlannerInfo root,
Node node,
AppendRelInfo appinfo 
)

Definition at line 1590 of file prepunion.c.

References adjust_appendrel_attrs_mutator(), adjust_inherited_tlist(), adjust_appendrel_attrs_context::appinfo, AppendRelInfo::child_relid, CMD_UPDATE, Query::commandType, IsA, AppendRelInfo::parent_relid, QTW_IGNORE_RC_SUBQUERIES, query_tree_mutator(), Query::resultRelation, adjust_appendrel_attrs_context::root, and Query::targetList.

Referenced by add_child_rel_equivalences(), generate_join_implied_equalities_broken(), inheritance_planner(), and set_append_rel_size().

{
    Node       *result;
    adjust_appendrel_attrs_context context;

    context.root = root;
    context.appinfo = appinfo;

    /*
     * Must be prepared to start with a Query or a bare expression tree.
     */
    if (node && IsA(node, Query))
    {
        Query      *newnode;

        newnode = query_tree_mutator((Query *) node,
                                     adjust_appendrel_attrs_mutator,
                                     (void *) &context,
                                     QTW_IGNORE_RC_SUBQUERIES);
        if (newnode->resultRelation == appinfo->parent_relid)
        {
            newnode->resultRelation = appinfo->child_relid;
            /* Fix tlist resnos too, if it's inherited UPDATE */
            if (newnode->commandType == CMD_UPDATE)
                newnode->targetList =
                    adjust_inherited_tlist(newnode->targetList,
                                           appinfo);
        }
        result = (Node *) newnode;
    }
    else
        result = adjust_appendrel_attrs_mutator(node, &context);

    return result;
}

Expr* canonicalize_qual ( Expr qual  ) 

Definition at line 285 of file prepqual.c.

References find_duplicate_ors(), and NULL.

Referenced by convert_EXISTS_to_ANY(), get_relation_constraints(), preprocess_expression(), and RelationGetIndexPredicate().

{
    Expr       *newqual;

    /* Quick exit for empty qual */
    if (qual == NULL)
        return NULL;

    /*
     * Pull up redundant subclauses in OR-of-AND trees.  We do this only
     * within the top-level AND/OR structure; there's no point in looking
     * deeper.
     */
    newqual = find_duplicate_ors(qual);

    return newqual;
}

void expand_inherited_tables ( PlannerInfo root  ) 

Definition at line 1191 of file prepunion.c.

References expand_inherited_rtentry(), lfirst, list_head(), list_length(), lnext, PlannerInfo::parse, and Query::rtable.

Referenced by subquery_planner().

{
    Index       nrtes;
    Index       rti;
    ListCell   *rl;

    /*
     * expand_inherited_rtentry may add RTEs to parse->rtable; there is no
     * need to scan them since they can't have inh=true.  So just scan as far
     * as the original end of the rtable list.
     */
    nrtes = list_length(root->parse->rtable);
    rl = list_head(root->parse->rtable);
    for (rti = 1; rti <= nrtes; rti++)
    {
        RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);

        expand_inherited_rtentry(root, rte, rti);
        rl = lnext(rl);
    }
}

void flatten_simple_union_all ( PlannerInfo root  ) 

Definition at line 1779 of file prepjointree.c.

References Assert, copyObject(), FromExpr::fromlist, PlannerInfo::hasRecursion, RangeTblEntry::inh, is_simple_union_all_recurse(), IsA, Query::jointree, lappend(), list_length(), list_make1, makeNode, NIL, PlannerInfo::parse, parse(), pull_up_union_leaf_queries(), rt_fetch, Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblRef::rtindex, and Query::setOperations.

Referenced by subquery_planner().

{
    Query      *parse = root->parse;
    SetOperationStmt *topop;
    Node       *leftmostjtnode;
    int         leftmostRTI;
    RangeTblEntry *leftmostRTE;
    int         childRTI;
    RangeTblEntry *childRTE;
    RangeTblRef *rtr;

    /* Shouldn't be called unless query has setops */
    topop = (SetOperationStmt *) parse->setOperations;
    Assert(topop && IsA(topop, SetOperationStmt));

    /* Can't optimize away a recursive UNION */
    if (root->hasRecursion)
        return;

    /*
     * Recursively check the tree of set operations.  If not all UNION ALL
     * with identical column types, punt.
     */
    if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
        return;

    /*
     * Locate the leftmost leaf query in the setops tree.  The upper query's
     * Vars all refer to this RTE (see transformSetOperationStmt).
     */
    leftmostjtnode = topop->larg;
    while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
        leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
    Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
    leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
    leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
    Assert(leftmostRTE->rtekind == RTE_SUBQUERY);

    /*
     * Make a copy of the leftmost RTE and add it to the rtable.  This copy
     * will represent the leftmost leaf query in its capacity as a member of
     * the appendrel.  The original will represent the appendrel as a whole.
     * (We must do things this way because the upper query's Vars have to be
     * seen as referring to the whole appendrel.)
     */
    childRTE = copyObject(leftmostRTE);
    parse->rtable = lappend(parse->rtable, childRTE);
    childRTI = list_length(parse->rtable);

    /* Modify the setops tree to reference the child copy */
    ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;

    /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
    leftmostRTE->inh = true;

    /*
     * Form a RangeTblRef for the appendrel, and insert it into FROM.  The top
     * Query of a setops tree should have had an empty FromClause initially.
     */
    rtr = makeNode(RangeTblRef);
    rtr->rtindex = leftmostRTI;
    Assert(parse->jointree->fromlist == NIL);
    parse->jointree->fromlist = list_make1(rtr);

    /*
     * Now pretend the query has no setops.  We must do this before trying to
     * do subquery pullup, because of Assert in pull_up_simple_subquery.
     */
    parse->setOperations = NULL;

    /*
     * Build AppendRelInfo information, and apply pull_up_subqueries to the
     * leaf queries of the UNION ALL.  (We must do that now because they
     * weren't previously referenced by the jointree, and so were missed by
     * the main invocation of pull_up_subqueries.)
     */
    pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
}

PlanRowMark* get_plan_rowmark ( List rowmarks,
Index  rtindex 
)

Definition at line 373 of file preptlist.c.

References lfirst, and PlanRowMark::rti.

Referenced by AcquireExecutorLocks(), and expand_inherited_rtentry().

{
    ListCell   *l;

    foreach(l, rowmarks)
    {
        PlanRowMark *rc = (PlanRowMark *) lfirst(l);

        if (rc->rti == rtindex)
            return rc;
    }
    return NULL;
}

Relids get_relids_for_join ( PlannerInfo root,
int  joinrelid 
)

Definition at line 2446 of file prepjointree.c.

References elog, ERROR, find_jointree_node_for_rel(), get_relids_in_jointree(), Query::jointree, and PlannerInfo::parse.

Referenced by alias_relid_set().

{
    Node       *jtnode;

    jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree,
                                        joinrelid);
    if (!jtnode)
        elog(ERROR, "could not find join node %d", joinrelid);
    return get_relids_in_jointree(jtnode, false);
}

Relids get_relids_in_jointree ( Node jtnode,
bool  include_joins 
)

Definition at line 2402 of file prepjointree.c.

References bms_add_member(), bms_join(), bms_make_singleton(), elog, ERROR, FromExpr::fromlist, get_relids_in_jointree(), IsA, JoinExpr::larg, lfirst, nodeTag, NULL, JoinExpr::rarg, and JoinExpr::rtindex.

Referenced by distribute_qual_to_rels(), get_relids_for_join(), get_relids_in_jointree(), is_simple_subquery(), and pull_up_simple_subquery().

{
    Relids      result = NULL;

    if (jtnode == NULL)
        return result;
    if (IsA(jtnode, RangeTblRef))
    {
        int         varno = ((RangeTblRef *) jtnode)->rtindex;

        result = bms_make_singleton(varno);
    }
    else if (IsA(jtnode, FromExpr))
    {
        FromExpr   *f = (FromExpr *) jtnode;
        ListCell   *l;

        foreach(l, f->fromlist)
        {
            result = bms_join(result,
                              get_relids_in_jointree(lfirst(l),
                                                     include_joins));
        }
    }
    else if (IsA(jtnode, JoinExpr))
    {
        JoinExpr   *j = (JoinExpr *) jtnode;

        result = get_relids_in_jointree(j->larg, include_joins);
        result = bms_join(result,
                          get_relids_in_jointree(j->rarg, include_joins));
        if (include_joins && j->rtindex)
            result = bms_add_member(result, j->rtindex);
    }
    else
        elog(ERROR, "unrecognized node type: %d",
             (int) nodeTag(jtnode));
    return result;
}

void inline_set_returning_functions ( PlannerInfo root  ) 

Definition at line 560 of file prepjointree.c.

References RangeTblEntry::funccolcollations, RangeTblEntry::funccoltypes, RangeTblEntry::funccoltypmods, RangeTblEntry::funcexpr, inline_set_returning_function(), lfirst, PlannerInfo::parse, Query::rtable, RTE_FUNCTION, RangeTblEntry::rtekind, and RangeTblEntry::subquery.

Referenced by pull_up_simple_subquery(), and subquery_planner().

{
    ListCell   *rt;

    foreach(rt, root->parse->rtable)
    {
        RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);

        if (rte->rtekind == RTE_FUNCTION)
        {
            Query      *funcquery;

            /* Check safety of expansion, and expand if possible */
            funcquery = inline_set_returning_function(root, rte);
            if (funcquery)
            {
                /* Successful expansion, replace the rtable entry */
                rte->rtekind = RTE_SUBQUERY;
                rte->subquery = funcquery;
                rte->funcexpr = NULL;
                rte->funccoltypes = NIL;
                rte->funccoltypmods = NIL;
                rte->funccolcollations = NIL;
            }
        }
    }
}

Node* negate_clause ( Node node  ) 

Definition at line 74 of file prepqual.c.

References AND_EXPR, BooleanTest::arg, NullTest::arg, NullTest::argisrow, BoolExpr::args, ScalarArrayOpExpr::args, OpExpr::args, BoolExpr::boolop, BooleanTest::booltesttype, Const::constisnull, Const::constvalue, DatumGetBool, elog, ERROR, get_negator(), ScalarArrayOpExpr::inputcollid, OpExpr::inputcollid, IS_FALSE, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, lappend(), lfirst, linitial, ScalarArrayOpExpr::location, OpExpr::location, make_andclause(), make_notclause(), make_orclause(), makeBoolConst(), makeNode, negate_clause(), nodeTag, NOT_EXPR, NULL, NullTest::nulltesttype, OpExpr::opcollid, ScalarArrayOpExpr::opfuncid, OpExpr::opfuncid, ScalarArrayOpExpr::opno, OpExpr::opno, OpExpr::opresulttype, OpExpr::opretset, OR_EXPR, T_BooleanTest, T_BoolExpr, T_Const, T_NullTest, T_OpExpr, T_ScalarArrayOpExpr, and ScalarArrayOpExpr::useOr.

Referenced by eval_const_expressions_mutator(), negate_clause(), and simplify_boolean_equality().

{
    if (node == NULL)           /* should not happen */
        elog(ERROR, "can't negate an empty subexpression");
    switch (nodeTag(node))
    {
        case T_Const:
            {
                Const      *c = (Const *) node;

                /* NOT NULL is still NULL */
                if (c->constisnull)
                    return makeBoolConst(false, true);
                /* otherwise pretty easy */
                return makeBoolConst(!DatumGetBool(c->constvalue), false);
            }
            break;
        case T_OpExpr:
            {
                /*
                 * Negate operator if possible: (NOT (< A B)) => (>= A B)
                 */
                OpExpr     *opexpr = (OpExpr *) node;
                Oid         negator = get_negator(opexpr->opno);

                if (negator)
                {
                    OpExpr     *newopexpr = makeNode(OpExpr);

                    newopexpr->opno = negator;
                    newopexpr->opfuncid = InvalidOid;
                    newopexpr->opresulttype = opexpr->opresulttype;
                    newopexpr->opretset = opexpr->opretset;
                    newopexpr->opcollid = opexpr->opcollid;
                    newopexpr->inputcollid = opexpr->inputcollid;
                    newopexpr->args = opexpr->args;
                    newopexpr->location = opexpr->location;
                    return (Node *) newopexpr;
                }
            }
            break;
        case T_ScalarArrayOpExpr:
            {
                /*
                 * Negate a ScalarArrayOpExpr if its operator has a negator;
                 * for example x = ANY (list) becomes x <> ALL (list)
                 */
                ScalarArrayOpExpr *saopexpr = (ScalarArrayOpExpr *) node;
                Oid         negator = get_negator(saopexpr->opno);

                if (negator)
                {
                    ScalarArrayOpExpr *newopexpr = makeNode(ScalarArrayOpExpr);

                    newopexpr->opno = negator;
                    newopexpr->opfuncid = InvalidOid;
                    newopexpr->useOr = !saopexpr->useOr;
                    newopexpr->inputcollid = saopexpr->inputcollid;
                    newopexpr->args = saopexpr->args;
                    newopexpr->location = saopexpr->location;
                    return (Node *) newopexpr;
                }
            }
            break;
        case T_BoolExpr:
            {
                BoolExpr   *expr = (BoolExpr *) node;

                switch (expr->boolop)
                {
                        /*--------------------
                         * Apply DeMorgan's Laws:
                         *      (NOT (AND A B)) => (OR (NOT A) (NOT B))
                         *      (NOT (OR A B))  => (AND (NOT A) (NOT B))
                         * i.e., swap AND for OR and negate each subclause.
                         *
                         * If the input is already AND/OR flat and has no NOT
                         * directly above AND or OR, this transformation preserves
                         * those properties.  For example, if no direct child of
                         * the given AND clause is an AND or a NOT-above-OR, then
                         * the recursive calls of negate_clause() can't return any
                         * OR clauses.  So we needn't call pull_ors() before
                         * building a new OR clause.  Similarly for the OR case.
                         *--------------------
                         */
                    case AND_EXPR:
                        {
                            List       *nargs = NIL;
                            ListCell   *lc;

                            foreach(lc, expr->args)
                            {
                                nargs = lappend(nargs,
                                                negate_clause(lfirst(lc)));
                            }
                            return (Node *) make_orclause(nargs);
                        }
                        break;
                    case OR_EXPR:
                        {
                            List       *nargs = NIL;
                            ListCell   *lc;

                            foreach(lc, expr->args)
                            {
                                nargs = lappend(nargs,
                                                negate_clause(lfirst(lc)));
                            }
                            return (Node *) make_andclause(nargs);
                        }
                        break;
                    case NOT_EXPR:

                        /*
                         * NOT underneath NOT: they cancel.  We assume the
                         * input is already simplified, so no need to recurse.
                         */
                        return (Node *) linitial(expr->args);
                    default:
                        elog(ERROR, "unrecognized boolop: %d",
                             (int) expr->boolop);
                        break;
                }
            }
            break;
        case T_NullTest:
            {
                NullTest   *expr = (NullTest *) node;

                /*
                 * In the rowtype case, the two flavors of NullTest are *not*
                 * logical inverses, so we can't simplify.  But it does work
                 * for scalar datatypes.
                 */
                if (!expr->argisrow)
                {
                    NullTest   *newexpr = makeNode(NullTest);

                    newexpr->arg = expr->arg;
                    newexpr->nulltesttype = (expr->nulltesttype == IS_NULL ?
                                             IS_NOT_NULL : IS_NULL);
                    newexpr->argisrow = expr->argisrow;
                    return (Node *) newexpr;
                }
            }
            break;
        case T_BooleanTest:
            {
                BooleanTest *expr = (BooleanTest *) node;
                BooleanTest *newexpr = makeNode(BooleanTest);

                newexpr->arg = expr->arg;
                switch (expr->booltesttype)
                {
                    case IS_TRUE:
                        newexpr->booltesttype = IS_NOT_TRUE;
                        break;
                    case IS_NOT_TRUE:
                        newexpr->booltesttype = IS_TRUE;
                        break;
                    case IS_FALSE:
                        newexpr->booltesttype = IS_NOT_FALSE;
                        break;
                    case IS_NOT_FALSE:
                        newexpr->booltesttype = IS_FALSE;
                        break;
                    case IS_UNKNOWN:
                        newexpr->booltesttype = IS_NOT_UNKNOWN;
                        break;
                    case IS_NOT_UNKNOWN:
                        newexpr->booltesttype = IS_UNKNOWN;
                        break;
                    default:
                        elog(ERROR, "unrecognized booltesttype: %d",
                             (int) expr->booltesttype);
                        break;
                }
                return (Node *) newexpr;
            }
            break;
        default:
            /* else fall through */
            break;
    }

    /*
     * Otherwise we don't know how to simplify this, so just tack on an
     * explicit NOT node.
     */
    return (Node *) make_notclause((Expr *) node);
}

Plan* plan_set_operations ( PlannerInfo root,
double  tuple_fraction,
List **  sortClauses 
)

Definition at line 135 of file prepunion.c.

References Assert, Query::distinctClause, FromExpr::fromlist, generate_recursion_plan(), Query::groupClause, PlannerInfo::hasRecursion, Query::havingQual, IsA, Query::jointree, SetOperationStmt::larg, NIL, NULL, PlannerInfo::parse, parse(), FromExpr::quals, recurse_set_operations(), Query::setOperations, setup_simple_rel_arrays(), PlannerInfo::simple_rte_array, RangeTblEntry::subquery, and Query::windowClause.

Referenced by grouping_planner().

{
    Query      *parse = root->parse;
    SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
    Node       *node;
    RangeTblEntry *leftmostRTE;
    Query      *leftmostQuery;

    Assert(topop && IsA(topop, SetOperationStmt));

    /* check for unsupported stuff */
    Assert(parse->jointree->fromlist == NIL);
    Assert(parse->jointree->quals == NULL);
    Assert(parse->groupClause == NIL);
    Assert(parse->havingQual == NULL);
    Assert(parse->windowClause == NIL);
    Assert(parse->distinctClause == NIL);

    /*
     * We'll need to build RelOptInfos for each of the leaf subqueries, which
     * are RTE_SUBQUERY rangetable entries in this Query.  Prepare the index
     * arrays for that.
     */
    setup_simple_rel_arrays(root);

    /*
     * Find the leftmost component Query.  We need to use its column names for
     * all generated tlists (else SELECT INTO won't work right).
     */
    node = topop->larg;
    while (node && IsA(node, SetOperationStmt))
        node = ((SetOperationStmt *) node)->larg;
    Assert(node && IsA(node, RangeTblRef));
    leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
    leftmostQuery = leftmostRTE->subquery;
    Assert(leftmostQuery != NULL);

    /*
     * If the topmost node is a recursive union, it needs special processing.
     */
    if (root->hasRecursion)
        return generate_recursion_plan(topop, root, tuple_fraction,
                                       leftmostQuery->targetList,
                                       sortClauses);

    /*
     * Recurse on setOperations tree to generate plans for set ops. The final
     * output plan should have just the column types shown as the output from
     * the top-level node, plus possibly resjunk working columns (we can rely
     * on upper-level nodes to deal with that).
     */
    return recurse_set_operations((Node *) topop, root, tuple_fraction,
                                  topop->colTypes, topop->colCollations,
                                  true, -1,
                                  leftmostQuery->targetList,
                                  sortClauses, NULL);
}

List* preprocess_targetlist ( PlannerInfo root,
List tlist 
)

Definition at line 50 of file preptlist.c.

References CMD_INSERT, CMD_UPDATE, Query::commandType, elog, ERROR, expand_targetlist(), InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), PlanRowMark::markType, NULL, OIDOID, PlannerInfo::parse, parse(), PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, RangeTblEntry::relid, Query::resultRelation, Query::returningList, ROW_MARK_COPY, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, rt_fetch, Query::rtable, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf(), RangeTblEntry::subquery, TableOidAttributeNumber, TIDOID, tlist_member(), and Var::varno.

Referenced by grouping_planner(), and inheritance_planner().

{
    Query      *parse = root->parse;
    int         result_relation = parse->resultRelation;
    List       *range_table = parse->rtable;
    CmdType     command_type = parse->commandType;
    ListCell   *lc;

    /*
     * Sanity check: if there is a result relation, it'd better be a real
     * relation not a subquery.  Else parser or rewriter messed up.
     */
    if (result_relation)
    {
        RangeTblEntry *rte = rt_fetch(result_relation, range_table);

        if (rte->subquery != NULL || rte->relid == InvalidOid)
            elog(ERROR, "subquery cannot be result relation");
    }

    /*
     * for heap_form_tuple to work, the targetlist must match the exact order
     * of the attributes. We also need to fill in any missing attributes. -ay
     * 10/94
     */
    if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
        tlist = expand_targetlist(tlist, command_type,
                                  result_relation, range_table);

    /*
     * Add necessary junk columns for rowmarked rels.  These values are needed
     * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
     * rechecking.  See comments for PlanRowMark in plannodes.h.
     */
    foreach(lc, root->rowMarks)
    {
        PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
        Var        *var;
        char        resname[32];
        TargetEntry *tle;

        /* child rels use the same junk attrs as their parents */
        if (rc->rti != rc->prti)
            continue;

        if (rc->markType != ROW_MARK_COPY)
        {
            /* It's a regular table, so fetch its TID */
            var = makeVar(rc->rti,
                          SelfItemPointerAttributeNumber,
                          TIDOID,
                          -1,
                          InvalidOid,
                          0);
            snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
            tle = makeTargetEntry((Expr *) var,
                                  list_length(tlist) + 1,
                                  pstrdup(resname),
                                  true);
            tlist = lappend(tlist, tle);

            /* if parent of inheritance tree, need the tableoid too */
            if (rc->isParent)
            {
                var = makeVar(rc->rti,
                              TableOidAttributeNumber,
                              OIDOID,
                              -1,
                              InvalidOid,
                              0);
                snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
                tle = makeTargetEntry((Expr *) var,
                                      list_length(tlist) + 1,
                                      pstrdup(resname),
                                      true);
                tlist = lappend(tlist, tle);
            }
        }
        else
        {
            /* Not a table, so we need the whole row as a junk var */
            var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
                                  rc->rti,
                                  0,
                                  false);
            snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
            tle = makeTargetEntry((Expr *) var,
                                  list_length(tlist) + 1,
                                  pstrdup(resname),
                                  true);
            tlist = lappend(tlist, tle);
        }
    }

    /*
     * If the query has a RETURNING list, add resjunk entries for any Vars
     * used in RETURNING that belong to other relations.  We need to do this
     * to make these Vars available for the RETURNING calculation.  Vars that
     * belong to the result rel don't need to be added, because they will be
     * made to refer to the actual heap tuple.
     */
    if (parse->returningList && list_length(parse->rtable) > 1)
    {
        List       *vars;
        ListCell   *l;

        vars = pull_var_clause((Node *) parse->returningList,
                               PVC_RECURSE_AGGREGATES,
                               PVC_INCLUDE_PLACEHOLDERS);
        foreach(l, vars)
        {
            Var        *var = (Var *) lfirst(l);
            TargetEntry *tle;

            if (IsA(var, Var) &&
                var->varno == result_relation)
                continue;       /* don't need it */

            if (tlist_member((Node *) var, tlist))
                continue;       /* already got it */

            tle = makeTargetEntry((Expr *) var,
                                  list_length(tlist) + 1,
                                  NULL,
                                  true);

            tlist = lappend(tlist, tle);
        }
        list_free(vars);
    }

    return tlist;
}

void pull_up_sublinks ( PlannerInfo root  ) 

Definition at line 137 of file prepjointree.c.

References IsA, Query::jointree, list_make1, makeFromExpr(), NULL, PlannerInfo::parse, and pull_up_sublinks_jointree_recurse().

Referenced by pull_up_simple_subquery(), and subquery_planner().

{
    Node       *jtnode;
    Relids      relids;

    /* Begin recursion through the jointree */
    jtnode = pull_up_sublinks_jointree_recurse(root,
                                               (Node *) root->parse->jointree,
                                               &relids);

    /*
     * root->parse->jointree must always be a FromExpr, so insert a dummy one
     * if we got a bare RangeTblRef or JoinExpr out of the recursion.
     */
    if (IsA(jtnode, FromExpr))
        root->parse->jointree = (FromExpr *) jtnode;
    else
        root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
}

Node* pull_up_subqueries ( PlannerInfo root,
Node jtnode 
)

Definition at line 599 of file prepjointree.c.

References NULL, and pull_up_subqueries_recurse().

Referenced by subquery_planner().

{
    /* Start off with no containing join nor appendrel */
    return pull_up_subqueries_recurse(root, jtnode, NULL, NULL, NULL);
}

void reduce_outer_joins ( PlannerInfo root  ) 

Definition at line 1897 of file prepjointree.c.

References reduce_outer_joins_state::contains_outer, elog, ERROR, Query::jointree, NIL, NULL, PlannerInfo::parse, reduce_outer_joins_pass1(), and reduce_outer_joins_pass2().

Referenced by subquery_planner().

{
    reduce_outer_joins_state *state;

    /*
     * To avoid doing strictness checks on more quals than necessary, we want
     * to stop descending the jointree as soon as there are no outer joins
     * below our current point.  This consideration forces a two-pass process.
     * The first pass gathers information about which base rels appear below
     * each side of each join clause, and about whether there are outer
     * join(s) below each side of each join clause. The second pass examines
     * qual clauses and changes join types as it descends the tree.
     */
    state = reduce_outer_joins_pass1((Node *) root->parse->jointree);

    /* planner.c shouldn't have called me if no outer joins */
    if (state == NULL || !state->contains_outer)
        elog(ERROR, "so where are the outer joins?");

    reduce_outer_joins_pass2((Node *) root->parse->jointree,
                             state, root, NULL, NIL, NIL);
}