Header And Logo

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

Data Structures | Functions

var.c File Reference

#include "postgres.h"
#include "access/sysattr.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/prep.h"
#include "optimizer/var.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
Include dependency graph for var.c:

Go to the source code of this file.

Data Structures

struct  pull_varnos_context
struct  pull_varattnos_context
struct  pull_vars_context
struct  locate_var_of_level_context
struct  pull_var_clause_context
struct  flatten_join_alias_vars_context

Functions

static bool pull_varnos_walker (Node *node, pull_varnos_context *context)
static bool pull_varattnos_walker (Node *node, pull_varattnos_context *context)
static bool pull_vars_walker (Node *node, pull_vars_context *context)
static bool contain_var_clause_walker (Node *node, void *context)
static bool contain_vars_of_level_walker (Node *node, int *sublevels_up)
static bool locate_var_of_level_walker (Node *node, locate_var_of_level_context *context)
static bool pull_var_clause_walker (Node *node, pull_var_clause_context *context)
static Nodeflatten_join_alias_vars_mutator (Node *node, flatten_join_alias_vars_context *context)
static Relids alias_relid_set (PlannerInfo *root, Relids relids)
Relids pull_varnos (Node *node)
Relids pull_varnos_of_level (Node *node, int levelsup)
void pull_varattnos (Node *node, Index varno, Bitmapset **varattnos)
Listpull_vars_of_level (Node *node, int levelsup)
bool contain_var_clause (Node *node)
bool contain_vars_of_level (Node *node, int levelsup)
int locate_var_of_level (Node *node, int levelsup)
Listpull_var_clause (Node *node, PVCAggregateBehavior aggbehavior, PVCPlaceHolderBehavior phbehavior)
Nodeflatten_join_alias_vars (PlannerInfo *root, Node *node)

Function Documentation

static Relids alias_relid_set ( PlannerInfo root,
Relids  relids 
) [static]

Definition at line 764 of file var.c.

References bms_add_member(), bms_copy(), bms_first_member(), bms_free(), bms_join(), get_relids_for_join(), PlannerInfo::parse, rt_fetch, Query::rtable, RTE_JOIN, and RangeTblEntry::rtekind.

Referenced by flatten_join_alias_vars_mutator().

{
    Relids      result = NULL;
    Relids      tmprelids;
    int         rtindex;

    tmprelids = bms_copy(relids);
    while ((rtindex = bms_first_member(tmprelids)) >= 0)
    {
        RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);

        if (rte->rtekind == RTE_JOIN)
            result = bms_join(result, get_relids_for_join(root, rtindex));
        else
            result = bms_add_member(result, rtindex);
    }
    bms_free(tmprelids);
    return result;
}

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

Definition at line 330 of file var.c.

References expression_tree_walker(), IsA, and NULL.

Referenced by contain_var_clause().

{
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
        if (((Var *) node)->varlevelsup == 0)
            return true;        /* abort the tree traversal and return true */
        return false;
    }
    if (IsA(node, CurrentOfExpr))
        return true;
    if (IsA(node, PlaceHolderVar))
    {
        if (((PlaceHolderVar *) node)->phlevelsup == 0)
            return true;        /* abort the tree traversal and return true */
        /* else fall through to check the contained expr */
    }
    return expression_tree_walker(node, contain_var_clause_walker, context);
}

bool contain_vars_of_level ( Node node,
int  levelsup 
)
static bool contain_vars_of_level_walker ( Node node,
int *  sublevels_up 
) [static]

Definition at line 373 of file var.c.

References expression_tree_walker(), IsA, NULL, and query_tree_walker().

Referenced by contain_vars_of_level().

{
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
        if (((Var *) node)->varlevelsup == *sublevels_up)
            return true;        /* abort tree traversal and return true */
        return false;
    }
    if (IsA(node, CurrentOfExpr))
    {
        if (*sublevels_up == 0)
            return true;
        return false;
    }
    if (IsA(node, PlaceHolderVar))
    {
        if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
            return true;        /* abort the tree traversal and return true */
        /* else fall through to check the contained expr */
    }
    if (IsA(node, Query))
    {
        /* Recurse into subselects */
        bool        result;

        (*sublevels_up)++;
        result = query_tree_walker((Query *) node,
                                   contain_vars_of_level_walker,
                                   (void *) sublevels_up,
                                   0);
        (*sublevels_up)--;
        return result;
    }
    return expression_tree_walker(node,
                                  contain_vars_of_level_walker,
                                  (void *) sublevels_up);
}

Node* flatten_join_alias_vars ( PlannerInfo root,
Node node 
)

Definition at line 608 of file var.c.

References flatten_join_alias_vars_mutator(), Query::hasSubLinks, flatten_join_alias_vars_context::inserted_sublink, PlannerInfo::parse, flatten_join_alias_vars_context::possible_sublink, flatten_join_alias_vars_context::root, and flatten_join_alias_vars_context::sublevels_up.

Referenced by parseCheckAggregates(), preprocess_expression(), and subquery_planner().

{
    flatten_join_alias_vars_context context;

    context.root = root;
    context.sublevels_up = 0;
    /* flag whether join aliases could possibly contain SubLinks */
    context.possible_sublink = root->parse->hasSubLinks;
    /* if hasSubLinks is already true, no need to work hard */
    context.inserted_sublink = root->parse->hasSubLinks;

    return flatten_join_alias_vars_mutator(node, &context);
}

static Node * flatten_join_alias_vars_mutator ( Node node,
flatten_join_alias_vars_context context 
) [static]

Definition at line 623 of file var.c.

References alias_relid_set(), RowExpr::args, Assert, checkExprHasSubLink(), RowExpr::colnames, Alias::colnames, copyObject(), RangeTblEntry::eref, expression_tree_mutator(), forboth, Query::hasSubLinks, IncrementVarSublevelsUp(), flatten_join_alias_vars_context::inserted_sublink, InvalidAttrNumber, IsA, RangeTblEntry::joinaliasvars, lappend(), lfirst, list_length(), list_nth(), RowExpr::location, Var::location, makeNode, NULL, PlannerInfo::parse, PlaceHolderVar::phlevelsup, PlaceHolderVar::phrels, flatten_join_alias_vars_context::possible_sublink, QTW_IGNORE_JOINALIASES, query_tree_mutator(), flatten_join_alias_vars_context::root, RowExpr::row_format, RowExpr::row_typeid, rt_fetch, Query::rtable, RTE_JOIN, RangeTblEntry::rtekind, flatten_join_alias_vars_context::sublevels_up, Var::varattno, Var::varlevelsup, Var::varno, and Var::vartype.

Referenced by flatten_join_alias_vars().

{
    if (node == NULL)
        return NULL;
    if (IsA(node, Var))
    {
        Var        *var = (Var *) node;
        RangeTblEntry *rte;
        Node       *newvar;

        /* No change unless Var belongs to a JOIN of the target level */
        if (var->varlevelsup != context->sublevels_up)
            return node;        /* no need to copy, really */
        rte = rt_fetch(var->varno, context->root->parse->rtable);
        if (rte->rtekind != RTE_JOIN)
            return node;
        if (var->varattno == InvalidAttrNumber)
        {
            /* Must expand whole-row reference */
            RowExpr    *rowexpr;
            List       *fields = NIL;
            List       *colnames = NIL;
            AttrNumber  attnum;
            ListCell   *lv;
            ListCell   *ln;

            attnum = 0;
            Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
            forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
            {
                newvar = (Node *) lfirst(lv);
                attnum++;
                /* Ignore dropped columns */
                if (IsA(newvar, Const))
                    continue;
                newvar = copyObject(newvar);

                /*
                 * If we are expanding an alias carried down from an upper
                 * query, must adjust its varlevelsup fields.
                 */
                if (context->sublevels_up != 0)
                    IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
                /* Preserve original Var's location, if possible */
                if (IsA(newvar, Var))
                    ((Var *) newvar)->location = var->location;
                /* Recurse in case join input is itself a join */
                /* (also takes care of setting inserted_sublink if needed) */
                newvar = flatten_join_alias_vars_mutator(newvar, context);
                fields = lappend(fields, newvar);
                /* We need the names of non-dropped columns, too */
                colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
            }
            rowexpr = makeNode(RowExpr);
            rowexpr->args = fields;
            rowexpr->row_typeid = var->vartype;
            rowexpr->row_format = COERCE_IMPLICIT_CAST;
            rowexpr->colnames = colnames;
            rowexpr->location = var->location;

            return (Node *) rowexpr;
        }

        /* Expand join alias reference */
        Assert(var->varattno > 0);
        newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
        newvar = copyObject(newvar);

        /*
         * If we are expanding an alias carried down from an upper query, must
         * adjust its varlevelsup fields.
         */
        if (context->sublevels_up != 0)
            IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);

        /* Preserve original Var's location, if possible */
        if (IsA(newvar, Var))
            ((Var *) newvar)->location = var->location;

        /* Recurse in case join input is itself a join */
        newvar = flatten_join_alias_vars_mutator(newvar, context);

        /* Detect if we are adding a sublink to query */
        if (context->possible_sublink && !context->inserted_sublink)
            context->inserted_sublink = checkExprHasSubLink(newvar);

        return newvar;
    }
    if (IsA(node, PlaceHolderVar))
    {
        /* Copy the PlaceHolderVar node with correct mutation of subnodes */
        PlaceHolderVar *phv;

        phv = (PlaceHolderVar *) expression_tree_mutator(node,
                                             flatten_join_alias_vars_mutator,
                                                         (void *) context);
        /* now fix PlaceHolderVar's relid sets */
        if (phv->phlevelsup == context->sublevels_up)
        {
            phv->phrels = alias_relid_set(context->root,
                                          phv->phrels);
        }
        return (Node *) phv;
    }

    if (IsA(node, Query))
    {
        /* Recurse into RTE subquery or not-yet-planned sublink subquery */
        Query      *newnode;
        bool        save_inserted_sublink;

        context->sublevels_up++;
        save_inserted_sublink = context->inserted_sublink;
        context->inserted_sublink = ((Query *) node)->hasSubLinks;
        newnode = query_tree_mutator((Query *) node,
                                     flatten_join_alias_vars_mutator,
                                     (void *) context,
                                     QTW_IGNORE_JOINALIASES);
        newnode->hasSubLinks |= context->inserted_sublink;
        context->inserted_sublink = save_inserted_sublink;
        context->sublevels_up--;
        return (Node *) newnode;
    }
    /* Already-planned tree not supported */
    Assert(!IsA(node, SubPlan));
    /* Shouldn't need to handle these planner auxiliary nodes here */
    Assert(!IsA(node, SpecialJoinInfo));
    Assert(!IsA(node, LateralJoinInfo));
    Assert(!IsA(node, PlaceHolderInfo));
    Assert(!IsA(node, MinMaxAggInfo));

    return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
                                   (void *) context);
}

int locate_var_of_level ( Node node,
int  levelsup 
)

Definition at line 430 of file var.c.

References locate_var_of_level_walker(), query_or_expression_tree_walker(), locate_var_of_level_context::sublevels_up, and locate_var_of_level_context::var_location.

Referenced by checkExprIsVarFree(), and transformSetOperationTree().

{
    locate_var_of_level_context context;

    context.var_location = -1;  /* in case we find nothing */
    context.sublevels_up = levelsup;

    (void) query_or_expression_tree_walker(node,
                                           locate_var_of_level_walker,
                                           (void *) &context,
                                           0);

    return context.var_location;
}

static bool locate_var_of_level_walker ( Node node,
locate_var_of_level_context context 
) [static]

Definition at line 446 of file var.c.

References expression_tree_walker(), IsA, Var::location, NULL, query_tree_walker(), locate_var_of_level_context::sublevels_up, locate_var_of_level_context::var_location, and Var::varlevelsup.

Referenced by locate_var_of_level().

{
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
        Var        *var = (Var *) node;

        if (var->varlevelsup == context->sublevels_up &&
            var->location >= 0)
        {
            context->var_location = var->location;
            return true;        /* abort tree traversal and return true */
        }
        return false;
    }
    if (IsA(node, CurrentOfExpr))
    {
        /* since CurrentOfExpr doesn't carry location, nothing we can do */
        return false;
    }
    /* No extra code needed for PlaceHolderVar; just look in contained expr */
    if (IsA(node, Query))
    {
        /* Recurse into subselects */
        bool        result;

        context->sublevels_up++;
        result = query_tree_walker((Query *) node,
                                   locate_var_of_level_walker,
                                   (void *) context,
                                   0);
        context->sublevels_up--;
        return result;
    }
    return expression_tree_walker(node,
                                  locate_var_of_level_walker,
                                  (void *) context);
}

List* pull_var_clause ( Node node,
PVCAggregateBehavior  aggbehavior,
PVCPlaceHolderBehavior  phbehavior 
)
static bool pull_var_clause_walker ( Node node,
pull_var_clause_context context 
) [static]

Definition at line 530 of file var.c.

References pull_var_clause_context::aggbehavior, elog, ERROR, expression_tree_walker(), IsA, lappend(), NULL, pull_var_clause_context::phbehavior, PVC_INCLUDE_AGGREGATES, PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_PLACEHOLDERS, PVC_REJECT_AGGREGATES, PVC_REJECT_PLACEHOLDERS, and pull_var_clause_context::varlist.

Referenced by pull_var_clause().

{
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
        if (((Var *) node)->varlevelsup != 0)
            elog(ERROR, "Upper-level Var found where not expected");
        context->varlist = lappend(context->varlist, node);
        return false;
    }
    else if (IsA(node, Aggref))
    {
        if (((Aggref *) node)->agglevelsup != 0)
            elog(ERROR, "Upper-level Aggref found where not expected");
        switch (context->aggbehavior)
        {
            case PVC_REJECT_AGGREGATES:
                elog(ERROR, "Aggref found where not expected");
                break;
            case PVC_INCLUDE_AGGREGATES:
                context->varlist = lappend(context->varlist, node);
                /* we do NOT descend into the contained expression */
                return false;
            case PVC_RECURSE_AGGREGATES:
                /* ignore the aggregate, look at its argument instead */
                break;
        }
    }
    else if (IsA(node, PlaceHolderVar))
    {
        if (((PlaceHolderVar *) node)->phlevelsup != 0)
            elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
        switch (context->phbehavior)
        {
            case PVC_REJECT_PLACEHOLDERS:
                elog(ERROR, "PlaceHolderVar found where not expected");
                break;
            case PVC_INCLUDE_PLACEHOLDERS:
                context->varlist = lappend(context->varlist, node);
                /* we do NOT descend into the contained expression */
                return false;
            case PVC_RECURSE_PLACEHOLDERS:
                /* ignore the placeholder, look at its argument instead */
                break;
        }
    }
    return expression_tree_walker(node, pull_var_clause_walker,
                                  (void *) context);
}

void pull_varattnos ( Node node,
Index  varno,
Bitmapset **  varattnos 
)
static bool pull_varattnos_walker ( Node node,
pull_varattnos_context context 
) [static]

Definition at line 225 of file var.c.

References Assert, bms_add_member(), expression_tree_walker(), FirstLowInvalidHeapAttributeNumber, IsA, NULL, Var::varattno, pull_varattnos_context::varattnos, Var::varlevelsup, pull_varattnos_context::varno, and Var::varno.

Referenced by pull_varattnos().

{
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
        Var        *var = (Var *) node;

        if (var->varno == context->varno && var->varlevelsup == 0)
            context->varattnos =
                bms_add_member(context->varattnos,
                         var->varattno - FirstLowInvalidHeapAttributeNumber);
        return false;
    }

    /* Should not find an unplanned subquery */
    Assert(!IsA(node, Query));

    return expression_tree_walker(node, pull_varattnos_walker,
                                  (void *) context);
}

Relids pull_varnos ( Node node  ) 
Relids pull_varnos_of_level ( Node node,
int  levelsup 
)

Definition at line 121 of file var.c.

References pull_varnos_walker(), query_or_expression_tree_walker(), pull_varnos_context::sublevels_up, and pull_varnos_context::varnos.

Referenced by is_simple_subquery().

{
    pull_varnos_context context;

    context.varnos = NULL;
    context.sublevels_up = levelsup;

    /*
     * Must be prepared to start with a Query or a bare expression tree; if
     * it's a Query, we don't want to increment sublevels_up.
     */
    query_or_expression_tree_walker(node,
                                    pull_varnos_walker,
                                    (void *) &context,
                                    0);

    return context.varnos;
}

static bool pull_varnos_walker ( Node node,
pull_varnos_context context 
) [static]

Definition at line 141 of file var.c.

References bms_add_member(), bms_add_members(), bms_is_empty(), bms_join(), CurrentOfExpr::cvarno, expression_tree_walker(), IsA, NULL, PlaceHolderVar::phexpr, PlaceHolderVar::phlevelsup, PlaceHolderVar::phrels, query_tree_walker(), pull_varnos_context::sublevels_up, Var::varlevelsup, Var::varno, and pull_varnos_context::varnos.

Referenced by pull_varnos(), and pull_varnos_of_level().

{
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
        Var        *var = (Var *) node;

        if (var->varlevelsup == context->sublevels_up)
            context->varnos = bms_add_member(context->varnos, var->varno);
        return false;
    }
    if (IsA(node, CurrentOfExpr))
    {
        CurrentOfExpr *cexpr = (CurrentOfExpr *) node;

        if (context->sublevels_up == 0)
            context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
        return false;
    }
    if (IsA(node, PlaceHolderVar))
    {
        /*
         * Normally, we can just take the varnos in the contained expression.
         * But if it is variable-free, use the PHV's syntactic relids.
         */
        PlaceHolderVar *phv = (PlaceHolderVar *) node;
        pull_varnos_context subcontext;

        subcontext.varnos = NULL;
        subcontext.sublevels_up = context->sublevels_up;
        (void) pull_varnos_walker((Node *) phv->phexpr, &subcontext);

        if (bms_is_empty(subcontext.varnos) &&
            phv->phlevelsup == context->sublevels_up)
            context->varnos = bms_add_members(context->varnos, phv->phrels);
        else
            context->varnos = bms_join(context->varnos, subcontext.varnos);
        return false;
    }
    if (IsA(node, Query))
    {
        /* Recurse into RTE subquery or not-yet-planned sublink subquery */
        bool        result;

        context->sublevels_up++;
        result = query_tree_walker((Query *) node, pull_varnos_walker,
                                   (void *) context, 0);
        context->sublevels_up--;
        return result;
    }
    return expression_tree_walker(node, pull_varnos_walker,
                                  (void *) context);
}

List* pull_vars_of_level ( Node node,
int  levelsup 
)

Definition at line 256 of file var.c.

References pull_vars_walker(), query_or_expression_tree_walker(), pull_vars_context::sublevels_up, and pull_vars_context::vars.

Referenced by extract_lateral_references().

{
    pull_vars_context context;

    context.vars = NIL;
    context.sublevels_up = levelsup;

    /*
     * Must be prepared to start with a Query or a bare expression tree; if
     * it's a Query, we don't want to increment sublevels_up.
     */
    query_or_expression_tree_walker(node,
                                    pull_vars_walker,
                                    (void *) &context,
                                    0);

    return context.vars;
}

static bool pull_vars_walker ( Node node,
pull_vars_context context 
) [static]

Definition at line 276 of file var.c.

References expression_tree_walker(), IsA, lappend(), NULL, PlaceHolderVar::phlevelsup, query_tree_walker(), pull_vars_context::sublevels_up, Var::varlevelsup, and pull_vars_context::vars.

Referenced by pull_vars_of_level().

{
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
        Var        *var = (Var *) node;

        if (var->varlevelsup == context->sublevels_up)
            context->vars = lappend(context->vars, var);
        return false;
    }
    if (IsA(node, PlaceHolderVar))
    {
        PlaceHolderVar *phv = (PlaceHolderVar *) node;

        if (phv->phlevelsup == context->sublevels_up)
            context->vars = lappend(context->vars, phv);
        /* we don't want to look into the contained expression */
        return false;
    }
    if (IsA(node, Query))
    {
        /* Recurse into RTE subquery or not-yet-planned sublink subquery */
        bool        result;

        context->sublevels_up++;
        result = query_tree_walker((Query *) node, pull_vars_walker,
                                   (void *) context, 0);
        context->sublevels_up--;
        return result;
    }
    return expression_tree_walker(node, pull_vars_walker,
                                  (void *) context);
}