diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index ae7f0382031..5d859b7c99e 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -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" diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 574e7bc4fa0..152696035cd 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -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; diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index b7a8725e2dc..8daf09c785a 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -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" diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 079d0160a8b..7085ed2c4c8 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -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 * diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c index b9fa3f4842a..6d6da5299fa 100644 --- a/src/backend/nodes/print.c +++ b/src/backend/nodes/print.c @@ -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" diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 3739b9817a0..50452706ed1 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -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 diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 30b0e925d3c..19be1f375c5 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -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" diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index f8e674c9c4e..be50d56b5a9 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -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); diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 8bfe9c3ff74..dfbbfdac6d7 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -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 diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c index 74b5a151350..94c88bd6622 100644 --- a/src/backend/optimizer/path/tidpath.c +++ b/src/backend/optimizer/path/tidpath.c @@ -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; diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 1c78852a881..a2376d2ed7e 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -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" diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 272710eed2d..5db88afd893 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -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. diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index fd19d0acf1c..60403eef913 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -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); diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index bcbca1a0f50..1f64004cf61 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -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); diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index 234dc5b3e7f..2bd6c200cfa 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -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; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index ea11dbb67c3..99616063f45 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -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); diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c index 9420f1347ae..c62ba88d1b2 100644 --- a/src/backend/optimizer/util/orclauses.c +++ b/src/backend/optimizer/util/orclauses.c @@ -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 diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 3d5ef6922ca..ecbb0db18c3 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -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; diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index e633881d8a6..c1bda812c70 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -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; diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 48175b746b8..5116d7f3490 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -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); } diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 8ed38168667..5b73378a19c 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -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 diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 901433c68c7..f5155fe062e 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -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; diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c index 1d7e028874b..a8e9f722140 100644 --- a/src/backend/statistics/dependencies.c +++ b/src/backend/statistics/dependencies.c @@ -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 diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index bcf4f104cf6..12bba1b63a0 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -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" diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 5b5aa2d80a5..aa25fab14a4 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -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); diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h index a9f76bbb330..98759346d12 100644 --- a/src/include/nodes/nodeFuncs.h +++ b/src/include/nodes/nodeFuncs.h @@ -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); diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index 6891d0dc9c0..3f5342886da 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -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); diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index a03a024ce93..17c44c46b9d 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -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 diff --git a/src/include/optimizer/var.h b/src/include/optimizer/var.h index a0c1387094a..f975074bf0b 100644 --- a/src/include/optimizer/var.h +++ b/src/include/optimizer/var.h @@ -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 */ diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c index 6c9ed9db48c..c03748cb3c3 100644 --- a/src/test/modules/test_predtest/test_predtest.c +++ b/src/test/modules/test_predtest/test_predtest.c @@ -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"