Make some small planner API cleanups.

Move a few very simple node-creation and node-type-testing functions
from the planner's clauses.c to nodes/makefuncs and nodes/nodeFuncs.
There's nothing planner-specific about them, as evidenced by the
number of other places that were using them.

While at it, rename and_clause() etc to is_andclause() etc, to clarify
that they are node-type-testing functions not node-creation functions.
And use "static inline" implementations for the shortest ones.

Also, modify flatten_join_alias_vars() and some subsidiary functions
to take a Query not a PlannerInfo to define the join structure that
Vars should be translated according to.  They were only using the
"parse" field of the PlannerInfo anyway, so this just requires removing
one level of indirection.  The advantage is that now parse_agg.c can
use flatten_join_alias_vars() without the horrid kluge of creating an
incomplete PlannerInfo, which will allow that file to be decoupled from
relation.h in a subsequent patch.

Discussion: https://postgr.es/m/11460.1548706639@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2019-01-29 15:26:44 -05:00
parent e77cfa54d7
commit a1b8c41e99
30 changed files with 309 additions and 345 deletions

View File

@ -22,6 +22,7 @@
#include "foreign/fdwapi.h"
#include "jit/jit.h"
#include "nodes/extensible.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"

View File

@ -33,8 +33,8 @@
#include "executor/executor.h"
#include "executor/nodeSubplan.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@ -888,7 +888,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
/* single combining operator */
oplist = list_make1(subplan->testexpr);
}
else if (and_clause((Node *) subplan->testexpr))
else if (is_andclause(subplan->testexpr))
{
/* multiple combining operators */
oplist = castNode(BoolExpr, subplan->testexpr)->args;

View File

@ -28,7 +28,7 @@
#include "executor/execdebug.h"
#include "executor/nodeTidscan.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "nodes/nodeFuncs.h"
#include "storage/bufmgr.h"
#include "utils/array.h"
#include "utils/rel.h"

View File

@ -598,6 +598,141 @@ makeFuncCall(List *name, List *args, int location)
return n;
}
/*
* make_opclause
* Creates an operator clause given its operator info, left operand
* and right operand (pass NULL to create single-operand clause),
* and collation info.
*/
Expr *
make_opclause(Oid opno, Oid opresulttype, bool opretset,
Expr *leftop, Expr *rightop,
Oid opcollid, Oid inputcollid)
{
OpExpr *expr = makeNode(OpExpr);
expr->opno = opno;
expr->opfuncid = InvalidOid;
expr->opresulttype = opresulttype;
expr->opretset = opretset;
expr->opcollid = opcollid;
expr->inputcollid = inputcollid;
if (rightop)
expr->args = list_make2(leftop, rightop);
else
expr->args = list_make1(leftop);
expr->location = -1;
return (Expr *) expr;
}
/*
* make_andclause
*
* Creates an 'and' clause given a list of its subclauses.
*/
Expr *
make_andclause(List *andclauses)
{
BoolExpr *expr = makeNode(BoolExpr);
expr->boolop = AND_EXPR;
expr->args = andclauses;
expr->location = -1;
return (Expr *) expr;
}
/*
* make_orclause
*
* Creates an 'or' clause given a list of its subclauses.
*/
Expr *
make_orclause(List *orclauses)
{
BoolExpr *expr = makeNode(BoolExpr);
expr->boolop = OR_EXPR;
expr->args = orclauses;
expr->location = -1;
return (Expr *) expr;
}
/*
* make_notclause
*
* Create a 'not' clause given the expression to be negated.
*/
Expr *
make_notclause(Expr *notclause)
{
BoolExpr *expr = makeNode(BoolExpr);
expr->boolop = NOT_EXPR;
expr->args = list_make1(notclause);
expr->location = -1;
return (Expr *) expr;
}
/*
* make_and_qual
*
* Variant of make_andclause for ANDing two qual conditions together.
* Qual conditions have the property that a NULL nodetree is interpreted
* as 'true'.
*
* NB: this makes no attempt to preserve AND/OR flatness; so it should not
* be used on a qual that has already been run through prepqual.c.
*/
Node *
make_and_qual(Node *qual1, Node *qual2)
{
if (qual1 == NULL)
return qual2;
if (qual2 == NULL)
return qual1;
return (Node *) make_andclause(list_make2(qual1, qual2));
}
/*
* The planner and executor usually represent qualification expressions
* as lists of boolean expressions with implicit AND semantics.
*
* These functions convert between an AND-semantics expression list and the
* ordinary representation of a boolean expression.
*
* Note that an empty list is considered equivalent to TRUE.
*/
Expr *
make_ands_explicit(List *andclauses)
{
if (andclauses == NIL)
return (Expr *) makeBoolConst(true, false);
else if (list_length(andclauses) == 1)
return (Expr *) linitial(andclauses);
else
return make_andclause(andclauses);
}
List *
make_ands_implicit(Expr *clause)
{
/*
* NB: because the parser sets the qual field to NULL in a query that has
* no WHERE clause, we must consider a NULL input clause as TRUE, even
* though one might more reasonably think it FALSE.
*/
if (clause == NULL)
return NIL; /* NULL -> NIL list == TRUE */
else if (is_andclause(clause))
return ((BoolExpr *) clause)->args;
else if (IsA(clause, Const) &&
!((Const *) clause)->constisnull &&
DatumGetBool(((Const *) clause)->constvalue))
return NIL; /* constant TRUE input -> NIL list */
else
return list_make1(clause);
}
/*
* makeGroupingSet
*

View File

@ -21,8 +21,9 @@
#include "access/printtup.h"
#include "lib/stringinfo.h"
#include "nodes/nodeFuncs.h"
#include "nodes/print.h"
#include "optimizer/clauses.h"
#include "nodes/relation.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"

View File

@ -15,6 +15,7 @@
#include "postgres.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
@ -688,7 +689,7 @@ clause_selectivity(PlannerInfo *root,
/* XXX any way to do better than default? */
}
}
else if (not_clause(clause))
else if (is_notclause(clause))
{
/* inverse of the selectivity of the underlying clause */
s1 = 1.0 - clause_selectivity(root,
@ -697,7 +698,7 @@ clause_selectivity(PlannerInfo *root,
jointype,
sjinfo);
}
else if (and_clause(clause))
else if (is_andclause(clause))
{
/* share code with clauselist_selectivity() */
s1 = clauselist_selectivity(root,
@ -706,7 +707,7 @@ clause_selectivity(PlannerInfo *root,
jointype,
sjinfo);
}
else if (or_clause(clause))
else if (is_orclause(clause))
{
/*
* Selectivities for an OR clause are computed as s1+s2 - s1*s2 to

View File

@ -79,6 +79,7 @@
#include "executor/executor.h"
#include "executor/nodeHash.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"

View File

@ -1297,7 +1297,7 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
List *indlist;
/* OR arguments should be ANDs or sub-RestrictInfos */
if (and_clause(orarg))
if (is_andclause(orarg))
{
List *andargs = ((BoolExpr *) orarg)->args;
@ -3368,7 +3368,7 @@ match_boolean_index_clause(Node *clause,
if (match_index_to_operand(clause, indexcol, index))
return true;
/* NOT clause? */
if (not_clause(clause))
if (is_notclause(clause))
{
if (match_index_to_operand((Node *) get_notclausearg((Expr *) clause),
indexcol, index))
@ -3680,7 +3680,7 @@ expand_boolean_index_clause(Node *clause,
InvalidOid, InvalidOid);
}
/* NOT clause? */
if (not_clause(clause))
if (is_notclause(clause))
{
Node *arg = (Node *) get_notclausearg((Expr *) clause);

View File

@ -15,6 +15,7 @@
#include "postgres.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/appendinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/joininfo.h"
@ -1554,8 +1555,7 @@ have_partkey_equi_join(RelOptInfo *joinrel,
if (!rinfo->mergeopfamilies && !OidIsValid(rinfo->hashjoinoperator))
continue;
opexpr = (OpExpr *) rinfo->clause;
Assert(is_opclause(opexpr));
opexpr = castNode(OpExpr, rinfo->clause);
/*
* The equi-join between partition keys is strict if equi-join between

View File

@ -250,7 +250,7 @@ TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
List *sublist;
/* OR arguments should be ANDs or sub-RestrictInfos */
if (and_clause(orarg))
if (is_andclause(orarg))
{
List *andargs = ((BoolExpr *) orarg)->args;

View File

@ -16,6 +16,7 @@
#include "catalog/pg_type.h"
#include "catalog/pg_class.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"

View File

@ -849,7 +849,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
*/
if (rte->lateral && root->hasJoinRTEs)
rte->subquery = (Query *)
flatten_join_alias_vars(root, (Node *) rte->subquery);
flatten_join_alias_vars(root->parse,
(Node *) rte->subquery);
}
else if (rte->rtekind == RTE_FUNCTION)
{
@ -1054,7 +1055,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
kind == EXPRKIND_VALUES ||
kind == EXPRKIND_TABLESAMPLE ||
kind == EXPRKIND_TABLEFUNC))
expr = flatten_join_alias_vars(root, expr);
expr = flatten_join_alias_vars(root->parse, expr);
/*
* Simplify constant expressions.

View File

@ -739,7 +739,7 @@ testexpr_is_hashable(Node *testexpr)
if (hash_ok_operator((OpExpr *) testexpr))
return true;
}
else if (and_clause(testexpr))
else if (is_andclause(testexpr))
{
ListCell *l;
@ -1693,7 +1693,7 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
* propagates down in both cases. (Note that this is unlike the meaning
* of "top level qual" used in most other places in Postgres.)
*/
if (and_clause(node))
if (is_andclause(node))
{
List *newargs = NIL;
ListCell *l;
@ -1706,7 +1706,7 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
Node *newarg;
newarg = process_sublinks_mutator(lfirst(l), &locContext);
if (and_clause(newarg))
if (is_andclause(newarg))
newargs = list_concat(newargs, ((BoolExpr *) newarg)->args);
else
newargs = lappend(newargs, newarg);
@ -1714,7 +1714,7 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
return (Node *) make_andclause(newargs);
}
if (or_clause(node))
if (is_orclause(node))
{
List *newargs = NIL;
ListCell *l;
@ -1727,7 +1727,7 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
Node *newarg;
newarg = process_sublinks_mutator(lfirst(l), &locContext);
if (or_clause(newarg))
if (is_orclause(newarg))
newargs = list_concat(newargs, ((BoolExpr *) newarg)->args);
else
newargs = lappend(newargs, newarg);

View File

@ -497,7 +497,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
/* Else return it unmodified */
return node;
}
if (not_clause(node))
if (is_notclause(node))
{
/* If the immediate argument of NOT is EXISTS, try to convert */
SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
@ -564,7 +564,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
/* Else return it unmodified */
return node;
}
if (and_clause(node))
if (is_andclause(node))
{
/* Recurse into AND clause */
List *newclauses = NIL;
@ -968,7 +968,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
* maybe even in the rewriter; but for now let's just fix this case here.)
*/
subquery->targetList = (List *)
flatten_join_alias_vars(subroot, (Node *) subquery->targetList);
flatten_join_alias_vars(subroot->parse, (Node *) subquery->targetList);
/*
* Adjust level-0 varnos in subquery so that we can append its rangetable
@ -3317,11 +3317,11 @@ get_relids_in_jointree(Node *jtnode, bool include_joins)
* get_relids_for_join: get set of base RT indexes making up a join
*/
Relids
get_relids_for_join(PlannerInfo *root, int joinrelid)
get_relids_for_join(Query *query, int joinrelid)
{
Node *jtnode;
jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree,
jtnode = find_jointree_node_for_rel((Node *) query->jointree,
joinrelid);
if (!jtnode)
elog(ERROR, "could not find join node %d", joinrelid);

View File

@ -32,6 +32,7 @@
#include "postgres.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/prep.h"
#include "utils/lsyscache.h"
@ -333,7 +334,7 @@ pull_ands(List *andlist)
* built a new arglist not shared with any other expr. Otherwise we'd
* need a list_copy here.
*/
if (and_clause(subexpr))
if (is_andclause(subexpr))
out_list = list_concat(out_list,
pull_ands(((BoolExpr *) subexpr)->args));
else
@ -365,7 +366,7 @@ pull_ors(List *orlist)
* built a new arglist not shared with any other expr. Otherwise we'd
* need a list_copy here.
*/
if (or_clause(subexpr))
if (is_orclause(subexpr))
out_list = list_concat(out_list,
pull_ors(((BoolExpr *) subexpr)->args));
else
@ -415,7 +416,7 @@ pull_ors(List *orlist)
static Expr *
find_duplicate_ors(Expr *qual, bool is_check)
{
if (or_clause((Node *) qual))
if (is_orclause(qual))
{
List *orlist = NIL;
ListCell *temp;
@ -459,7 +460,7 @@ find_duplicate_ors(Expr *qual, bool is_check)
/* Now we can look for duplicate ORs */
return process_duplicate_ors(orlist);
}
else if (and_clause((Node *) qual))
else if (is_andclause(qual))
{
List *andlist = NIL;
ListCell *temp;
@ -550,7 +551,7 @@ process_duplicate_ors(List *orlist)
{
Expr *clause = (Expr *) lfirst(temp);
if (and_clause((Node *) clause))
if (is_andclause(clause))
{
List *subclauses = ((BoolExpr *) clause)->args;
int nclauses = list_length(subclauses);
@ -588,7 +589,7 @@ process_duplicate_ors(List *orlist)
{
Expr *clause = (Expr *) lfirst(temp2);
if (and_clause((Node *) clause))
if (is_andclause(clause))
{
if (!list_member(((BoolExpr *) clause)->args, refclause))
{
@ -631,7 +632,7 @@ process_duplicate_ors(List *orlist)
{
Expr *clause = (Expr *) lfirst(temp);
if (and_clause((Node *) clause))
if (is_andclause(clause))
{
List *subclauses = ((BoolExpr *) clause)->args;

View File

@ -157,244 +157,6 @@ static Node *substitute_actual_srf_parameters_mutator(Node *node,
static bool tlist_matches_coltypelist(List *tlist, List *coltypelist);
/*****************************************************************************
* OPERATOR clause functions
*****************************************************************************/
/*
* make_opclause
* Creates an operator clause given its operator info, left operand
* and right operand (pass NULL to create single-operand clause),
* and collation info.
*/
Expr *
make_opclause(Oid opno, Oid opresulttype, bool opretset,
Expr *leftop, Expr *rightop,
Oid opcollid, Oid inputcollid)
{
OpExpr *expr = makeNode(OpExpr);
expr->opno = opno;
expr->opfuncid = InvalidOid;
expr->opresulttype = opresulttype;
expr->opretset = opretset;
expr->opcollid = opcollid;
expr->inputcollid = inputcollid;
if (rightop)
expr->args = list_make2(leftop, rightop);
else
expr->args = list_make1(leftop);
expr->location = -1;
return (Expr *) expr;
}
/*
* get_leftop
*
* Returns the left operand of a clause of the form (op expr expr)
* or (op expr)
*/
Node *
get_leftop(const Expr *clause)
{
const OpExpr *expr = (const OpExpr *) clause;
if (expr->args != NIL)
return linitial(expr->args);
else
return NULL;
}
/*
* get_rightop
*
* Returns the right operand in a clause of the form (op expr expr).
* NB: result will be NULL if applied to a unary op clause.
*/
Node *
get_rightop(const Expr *clause)
{
const OpExpr *expr = (const OpExpr *) clause;
if (list_length(expr->args) >= 2)
return lsecond(expr->args);
else
return NULL;
}
/*****************************************************************************
* NOT clause functions
*****************************************************************************/
/*
* not_clause
*
* Returns t iff this is a 'not' clause: (NOT expr).
*/
bool
not_clause(Node *clause)
{
return (clause != NULL &&
IsA(clause, BoolExpr) &&
((BoolExpr *) clause)->boolop == NOT_EXPR);
}
/*
* make_notclause
*
* Create a 'not' clause given the expression to be negated.
*/
Expr *
make_notclause(Expr *notclause)
{
BoolExpr *expr = makeNode(BoolExpr);
expr->boolop = NOT_EXPR;
expr->args = list_make1(notclause);
expr->location = -1;
return (Expr *) expr;
}
/*
* get_notclausearg
*
* Retrieve the clause within a 'not' clause
*/
Expr *
get_notclausearg(Expr *notclause)
{
return linitial(((BoolExpr *) notclause)->args);
}
/*****************************************************************************
* OR clause functions
*****************************************************************************/
/*
* or_clause
*
* Returns t iff the clause is an 'or' clause: (OR { expr }).
*/
bool
or_clause(Node *clause)
{
return (clause != NULL &&
IsA(clause, BoolExpr) &&
((BoolExpr *) clause)->boolop == OR_EXPR);
}
/*
* make_orclause
*
* Creates an 'or' clause given a list of its subclauses.
*/
Expr *
make_orclause(List *orclauses)
{
BoolExpr *expr = makeNode(BoolExpr);
expr->boolop = OR_EXPR;
expr->args = orclauses;
expr->location = -1;
return (Expr *) expr;
}
/*****************************************************************************
* AND clause functions
*****************************************************************************/
/*
* and_clause
*
* Returns t iff its argument is an 'and' clause: (AND { expr }).
*/
bool
and_clause(Node *clause)
{
return (clause != NULL &&
IsA(clause, BoolExpr) &&
((BoolExpr *) clause)->boolop == AND_EXPR);
}
/*
* make_andclause
*
* Creates an 'and' clause given a list of its subclauses.
*/
Expr *
make_andclause(List *andclauses)
{
BoolExpr *expr = makeNode(BoolExpr);
expr->boolop = AND_EXPR;
expr->args = andclauses;
expr->location = -1;
return (Expr *) expr;
}
/*
* make_and_qual
*
* Variant of make_andclause for ANDing two qual conditions together.
* Qual conditions have the property that a NULL nodetree is interpreted
* as 'true'.
*
* NB: this makes no attempt to preserve AND/OR flatness; so it should not
* be used on a qual that has already been run through prepqual.c.
*/
Node *
make_and_qual(Node *qual1, Node *qual2)
{
if (qual1 == NULL)
return qual2;
if (qual2 == NULL)
return qual1;
return (Node *) make_andclause(list_make2(qual1, qual2));
}
/*
* The planner frequently prefers to represent qualification expressions
* as lists of boolean expressions with implicit AND semantics.
*
* These functions convert between an AND-semantics expression list and the
* ordinary representation of a boolean expression.
*
* Note that an empty list is considered equivalent to TRUE.
*/
Expr *
make_ands_explicit(List *andclauses)
{
if (andclauses == NIL)
return (Expr *) makeBoolConst(true, false);
else if (list_length(andclauses) == 1)
return (Expr *) linitial(andclauses);
else
return make_andclause(andclauses);
}
List *
make_ands_implicit(Expr *clause)
{
/*
* NB: because the parser sets the qual field to NULL in a query that has
* no WHERE clause, we must consider a NULL input clause as TRUE, even
* though one might more reasonably think it FALSE. Grumble. If this
* causes trouble, consider changing the parser's behavior.
*/
if (clause == NULL)
return NIL; /* NULL -> NIL list == TRUE */
else if (and_clause((Node *) clause))
return ((BoolExpr *) clause)->args;
else if (IsA(clause, Const) &&
!((Const *) clause)->constisnull &&
DatumGetBool(((Const *) clause)->constvalue))
return NIL; /* constant TRUE input -> NIL list */
else
return list_make1(clause);
}
/*****************************************************************************
* Aggregate-function clause manipulation
*****************************************************************************/
@ -3979,7 +3741,7 @@ simplify_or_arguments(List *args,
unprocessed_args = list_delete_first(unprocessed_args);
/* flatten nested ORs as per above comment */
if (or_clause(arg))
if (is_orclause(arg))
{
List *subargs = list_copy(((BoolExpr *) arg)->args);
@ -4005,7 +3767,7 @@ simplify_or_arguments(List *args,
* since it's not a mainstream case. In particular we don't worry
* about const-simplifying the input twice.
*/
if (or_clause(arg))
if (is_orclause(arg))
{
List *subargs = list_copy(((BoolExpr *) arg)->args);
@ -4081,7 +3843,7 @@ simplify_and_arguments(List *args,
unprocessed_args = list_delete_first(unprocessed_args);
/* flatten nested ANDs as per above comment */
if (and_clause(arg))
if (is_andclause(arg))
{
List *subargs = list_copy(((BoolExpr *) arg)->args);
@ -4107,7 +3869,7 @@ simplify_and_arguments(List *args,
* since it's not a mainstream case. In particular we don't worry
* about const-simplifying the input twice.
*/
if (and_clause(arg))
if (is_andclause(arg))
{
List *subargs = list_copy(((BoolExpr *) arg)->args);

View File

@ -15,6 +15,8 @@
#include "postgres.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/orclauses.h"
@ -173,7 +175,7 @@ extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel)
* selectivity and other cached data is computed exactly the same way for
* a restriction clause as for a join clause, which seems undesirable.
*/
Assert(or_clause((Node *) or_rinfo->orclause));
Assert(is_orclause(or_rinfo->orclause));
foreach(lc, ((BoolExpr *) or_rinfo->orclause)->args)
{
Node *orarg = (Node *) lfirst(lc);
@ -181,7 +183,7 @@ extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel)
Node *subclause;
/* OR arguments should be ANDs or sub-RestrictInfos */
if (and_clause(orarg))
if (is_andclause(orarg))
{
List *andargs = ((BoolExpr *) orarg)->args;
ListCell *lc2;
@ -231,7 +233,7 @@ extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel)
* to preserve AND/OR flatness (ie, no OR directly underneath OR).
*/
subclause = (Node *) make_ands_explicit(subclauses);
if (or_clause(subclause))
if (is_orclause(subclause))
clauselist = list_concat(clauselist,
list_copy(((BoolExpr *) subclause)->args));
else

View File

@ -19,6 +19,7 @@
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/predtest.h"
@ -839,14 +840,14 @@ predicate_classify(Node *clause, PredIterInfo info)
}
/* Handle normal AND and OR boolean clauses */
if (and_clause(clause))
if (is_andclause(clause))
{
info->startup_fn = boolexpr_startup_fn;
info->next_fn = list_next_fn;
info->cleanup_fn = list_cleanup_fn;
return CLASS_AND;
}
if (or_clause(clause))
if (is_orclause(clause))
{
info->startup_fn = boolexpr_startup_fn;
info->next_fn = list_next_fn;

View File

@ -14,6 +14,8 @@
*/
#include "postgres.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/var.h"
@ -67,7 +69,7 @@ make_restrictinfo(Expr *clause,
* If it's an OR clause, build a modified copy with RestrictInfos inserted
* above each subclause of the top-level AND/OR structure.
*/
if (or_clause((Node *) clause))
if (is_orclause(clause))
return (RestrictInfo *) make_sub_restrictinfos(clause,
is_pushed_down,
outerjoin_delayed,
@ -78,7 +80,7 @@ make_restrictinfo(Expr *clause,
nullable_relids);
/* Shouldn't be an AND clause, else AND/OR flattening messed up */
Assert(!and_clause((Node *) clause));
Assert(!is_andclause(clause));
return make_restrictinfo_internal(clause,
NULL,
@ -232,7 +234,7 @@ make_sub_restrictinfos(Expr *clause,
Relids outer_relids,
Relids nullable_relids)
{
if (or_clause((Node *) clause))
if (is_orclause(clause))
{
List *orlist = NIL;
ListCell *temp;
@ -257,7 +259,7 @@ make_sub_restrictinfos(Expr *clause,
outer_relids,
nullable_relids);
}
else if (and_clause((Node *) clause))
else if (is_andclause(clause))
{
List *andlist = NIL;
ListCell *temp;

View File

@ -60,7 +60,7 @@ typedef struct
typedef struct
{
PlannerInfo *root;
Query *query; /* outer Query */
int sublevels_up;
bool possible_sublink; /* could aliases include a SubLink? */
bool inserted_sublink; /* have we inserted a SubLink? */
@ -78,7 +78,7 @@ static bool pull_var_clause_walker(Node *node,
pull_var_clause_context *context);
static Node *flatten_join_alias_vars_mutator(Node *node,
flatten_join_alias_vars_context *context);
static Relids alias_relid_set(PlannerInfo *root, Relids relids);
static Relids alias_relid_set(Query *query, Relids relids);
/*
@ -667,16 +667,16 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
* subqueries).
*/
Node *
flatten_join_alias_vars(PlannerInfo *root, Node *node)
flatten_join_alias_vars(Query *query, Node *node)
{
flatten_join_alias_vars_context context;
context.root = root;
context.query = query;
context.sublevels_up = 0;
/* flag whether join aliases could possibly contain SubLinks */
context.possible_sublink = root->parse->hasSubLinks;
context.possible_sublink = query->hasSubLinks;
/* if hasSubLinks is already true, no need to work hard */
context.inserted_sublink = root->parse->hasSubLinks;
context.inserted_sublink = query->hasSubLinks;
return flatten_join_alias_vars_mutator(node, &context);
}
@ -696,7 +696,7 @@ flatten_join_alias_vars_mutator(Node *node,
/* 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);
rte = rt_fetch(var->varno, context->query->rtable);
if (rte->rtekind != RTE_JOIN)
return node;
if (var->varattno == InvalidAttrNumber)
@ -783,7 +783,7 @@ flatten_join_alias_vars_mutator(Node *node,
/* now fix PlaceHolderVar's relid sets */
if (phv->phlevelsup == context->sublevels_up)
{
phv->phrels = alias_relid_set(context->root,
phv->phrels = alias_relid_set(context->query,
phv->phrels);
}
return (Node *) phv;
@ -823,7 +823,7 @@ flatten_join_alias_vars_mutator(Node *node,
* underlying base relids
*/
static Relids
alias_relid_set(PlannerInfo *root, Relids relids)
alias_relid_set(Query *query, Relids relids)
{
Relids result = NULL;
int rtindex;
@ -831,10 +831,10 @@ alias_relid_set(PlannerInfo *root, Relids relids)
rtindex = -1;
while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
{
RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
if (rte->rtekind == RTE_JOIN)
result = bms_join(result, get_relids_for_join(root, rtindex));
result = bms_join(result, get_relids_for_join(query, rtindex));
else
result = bms_add_member(result, rtindex);
}

View File

@ -43,7 +43,7 @@ typedef struct
{
ParseState *pstate;
Query *qry;
PlannerInfo *root;
bool hasJoinRTEs;
List *groupClauses;
List *groupClauseCommonVars;
bool have_non_var_grouping;
@ -65,7 +65,7 @@ static void check_ungrouped_columns(Node *node, ParseState *pstate, Query *qry,
static bool check_ungrouped_columns_walker(Node *node,
check_ungrouped_columns_context *context);
static void finalize_grouping_exprs(Node *node, ParseState *pstate, Query *qry,
List *groupClauses, PlannerInfo *root,
List *groupClauses, bool hasJoinRTEs,
bool have_non_var_grouping);
static bool finalize_grouping_exprs_walker(Node *node,
check_ungrouped_columns_context *context);
@ -1039,7 +1039,6 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
ListCell *l;
bool hasJoinRTEs;
bool hasSelfRefRTEs;
PlannerInfo *root = NULL;
Node *clause;
/* This should only be called if we found aggregates or grouping */
@ -1130,20 +1129,11 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
* If there are join alias vars involved, we have to flatten them to the
* underlying vars, so that aliased and unaliased vars will be correctly
* taken as equal. We can skip the expense of doing this if no rangetable
* entries are RTE_JOIN kind. We use the planner's flatten_join_alias_vars
* routine to do the flattening; it wants a PlannerInfo root node, which
* fortunately can be mostly dummy.
* entries are RTE_JOIN kind.
*/
if (hasJoinRTEs)
{
root = makeNode(PlannerInfo);
root->parse = qry;
root->planner_cxt = CurrentMemoryContext;
root->hasJoinRTEs = true;
groupClauses = (List *) flatten_join_alias_vars(root,
groupClauses = (List *) flatten_join_alias_vars(qry,
(Node *) groupClauses);
}
/*
* Detect whether any of the grouping expressions aren't simple Vars; if
@ -1183,10 +1173,10 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
*/
clause = (Node *) qry->targetList;
finalize_grouping_exprs(clause, pstate, qry,
groupClauses, root,
groupClauses, hasJoinRTEs,
have_non_var_grouping);
if (hasJoinRTEs)
clause = flatten_join_alias_vars(root, clause);
clause = flatten_join_alias_vars(qry, clause);
check_ungrouped_columns(clause, pstate, qry,
groupClauses, groupClauseCommonVars,
have_non_var_grouping,
@ -1194,10 +1184,10 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
clause = (Node *) qry->havingQual;
finalize_grouping_exprs(clause, pstate, qry,
groupClauses, root,
groupClauses, hasJoinRTEs,
have_non_var_grouping);
if (hasJoinRTEs)
clause = flatten_join_alias_vars(root, clause);
clause = flatten_join_alias_vars(qry, clause);
check_ungrouped_columns(clause, pstate, qry,
groupClauses, groupClauseCommonVars,
have_non_var_grouping,
@ -1245,7 +1235,7 @@ check_ungrouped_columns(Node *node, ParseState *pstate, Query *qry,
context.pstate = pstate;
context.qry = qry;
context.root = NULL;
context.hasJoinRTEs = false; /* assume caller flattened join Vars */
context.groupClauses = groupClauses;
context.groupClauseCommonVars = groupClauseCommonVars;
context.have_non_var_grouping = have_non_var_grouping;
@ -1445,14 +1435,14 @@ check_ungrouped_columns_walker(Node *node,
*/
static void
finalize_grouping_exprs(Node *node, ParseState *pstate, Query *qry,
List *groupClauses, PlannerInfo *root,
List *groupClauses, bool hasJoinRTEs,
bool have_non_var_grouping)
{
check_ungrouped_columns_context context;
context.pstate = pstate;
context.qry = qry;
context.root = root;
context.hasJoinRTEs = hasJoinRTEs;
context.groupClauses = groupClauses;
context.groupClauseCommonVars = NIL;
context.have_non_var_grouping = have_non_var_grouping;
@ -1525,8 +1515,8 @@ finalize_grouping_exprs_walker(Node *node,
Node *expr = lfirst(lc);
Index ref = 0;
if (context->root)
expr = flatten_join_alias_vars(context->root, expr);
if (context->hasJoinRTEs)
expr = flatten_join_alias_vars(context->qry, expr);
/*
* Each expression must match a grouping entry at the current

View File

@ -775,7 +775,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
* independently, collect their step IDs to be stored in the
* combine step we'll be creating.
*/
if (or_clause((Node *) clause))
if (is_orclause(clause))
{
List *arg_stepids = NIL;
bool all_args_contradictory = true;
@ -865,7 +865,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
}
continue;
}
else if (and_clause((Node *) clause))
else if (is_andclause(clause))
{
List *args = ((BoolExpr *) clause)->args;
List *argsteps,
@ -3262,7 +3262,7 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
}
else
{
bool is_not_clause = not_clause((Node *) clause);
bool is_not_clause = is_notclause(clause);
leftop = is_not_clause ? get_notclausearg(clause) : clause;

View File

@ -18,6 +18,7 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_statistic_ext.h"
#include "lib/stringinfo.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/var.h"
@ -802,7 +803,7 @@ dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum)
/* OK to proceed with checking "var" */
}
else if (not_clause((Node *) rinfo->clause))
else if (is_notclause(rinfo->clause))
{
/*
* "NOT x" can be interpreted as "x = false", so get the argument and

View File

@ -69,6 +69,7 @@
#include "commands/policy.h"
#include "commands/trigger.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/prep.h"

View File

@ -80,6 +80,18 @@ extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype, List *args,
extern FuncCall *makeFuncCall(List *name, List *args, int location);
extern Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset,
Expr *leftop, Expr *rightop,
Oid opcollid, Oid inputcollid);
extern Expr *make_andclause(List *andclauses);
extern Expr *make_orclause(List *orclauses);
extern Expr *make_notclause(Expr *notclause);
extern Node *make_and_qual(Node *qual1, Node *qual2);
extern Expr *make_ands_explicit(List *andclauses);
extern List *make_ands_implicit(Expr *clause);
extern DefElem *makeDefElem(char *name, Node *arg, int location);
extern DefElem *makeDefElemExtended(char *nameSpace, char *name, Node *arg,
DefElemAction defaction, int location);

View File

@ -50,6 +50,78 @@ extern void fix_opfuncids(Node *node);
extern void set_opfuncid(OpExpr *opexpr);
extern void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
/* Is clause a FuncExpr clause? */
static inline bool
is_funcclause(const void *clause)
{
return clause != NULL && IsA(clause, FuncExpr);
}
/* Is clause an OpExpr clause? */
static inline bool
is_opclause(const void *clause)
{
return clause != NULL && IsA(clause, OpExpr);
}
/* Extract left arg of a binary opclause, or only arg of a unary opclause */
static inline Node *
get_leftop(const void *clause)
{
const OpExpr *expr = (const OpExpr *) clause;
if (expr->args != NIL)
return (Node *) linitial(expr->args);
else
return NULL;
}
/* Extract right arg of a binary opclause (NULL if it's a unary opclause) */
static inline Node *
get_rightop(const void *clause)
{
const OpExpr *expr = (const OpExpr *) clause;
if (list_length(expr->args) >= 2)
return (Node *) lsecond(expr->args);
else
return NULL;
}
/* Is clause an AND clause? */
static inline bool
is_andclause(const void *clause)
{
return (clause != NULL &&
IsA(clause, BoolExpr) &&
((const BoolExpr *) clause)->boolop == AND_EXPR);
}
/* Is clause an OR clause? */
static inline bool
is_orclause(const void *clause)
{
return (clause != NULL &&
IsA(clause, BoolExpr) &&
((const BoolExpr *) clause)->boolop == OR_EXPR);
}
/* Is clause a NOT clause? */
static inline bool
is_notclause(const void *clause)
{
return (clause != NULL &&
IsA(clause, BoolExpr) &&
((const BoolExpr *) clause)->boolop == NOT_EXPR);
}
/* Extract argument from a clause known to be a NOT clause */
static inline Expr *
get_notclausearg(const void *notclause)
{
return (Expr *) linitial(((const BoolExpr *) notclause)->args);
}
extern bool check_functions_in_node(Node *node, check_function_callback checker,
void *context);

View File

@ -17,9 +17,6 @@
#include "access/htup.h"
#include "nodes/relation.h"
#define is_opclause(clause) ((clause) != NULL && IsA(clause, OpExpr))
#define is_funcclause(clause) ((clause) != NULL && IsA(clause, FuncExpr))
typedef struct
{
int numWindowFuncs; /* total number of WindowFuncs found */
@ -27,25 +24,6 @@ typedef struct
List **windowFuncs; /* lists of WindowFuncs for each winref */
} WindowFuncLists;
extern Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset,
Expr *leftop, Expr *rightop,
Oid opcollid, Oid inputcollid);
extern Node *get_leftop(const Expr *clause);
extern Node *get_rightop(const Expr *clause);
extern bool not_clause(Node *clause);
extern Expr *make_notclause(Expr *notclause);
extern Expr *get_notclausearg(Expr *notclause);
extern bool or_clause(Node *clause);
extern Expr *make_orclause(List *orclauses);
extern bool and_clause(Node *clause);
extern Expr *make_andclause(List *andclauses);
extern Node *make_and_qual(Node *qual1, Node *qual2);
extern Expr *make_ands_explicit(List *andclauses);
extern List *make_ands_implicit(Expr *clause);
extern bool contain_agg_clause(Node *clause);
extern void get_agg_clause_costs(PlannerInfo *root, Node *clause,
AggSplit aggsplit, AggClauseCosts *costs);

View File

@ -29,7 +29,7 @@ extern void flatten_simple_union_all(PlannerInfo *root);
extern void reduce_outer_joins(PlannerInfo *root);
extern void remove_useless_result_rtes(PlannerInfo *root);
extern Relids get_relids_in_jointree(Node *jtnode, bool include_joins);
extern Relids get_relids_for_join(PlannerInfo *root, int joinrelid);
extern Relids get_relids_for_join(Query *query, int joinrelid);
/*
* prototypes for prepqual.c

View File

@ -35,6 +35,6 @@ extern bool contain_var_clause(Node *node);
extern bool contain_vars_of_level(Node *node, int levelsup);
extern int locate_var_of_level(Node *node, int levelsup);
extern List *pull_var_clause(Node *node, int flags);
extern Node *flatten_join_alias_vars(PlannerInfo *root, Node *node);
extern Node *flatten_join_alias_vars(Query *query, Node *node);
#endif /* VAR_H */

View File

@ -17,6 +17,7 @@
#include "catalog/pg_type.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/predtest.h"
#include "utils/builtins.h"