diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-12-12 15:49:42 +0000 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-12-12 15:49:42 +0000 |
| commit | a0bf885f9eaccadd23b766ecbc064f17f06ae883 (patch) | |
| tree | 62b65e5cf1a8ec02ece3a98c15457ddff018bb94 /src/backend/optimizer | |
| parent | debb072886efcb15e7f0825e35b168afe316d37d (diff) | |
| download | postgresql-a0bf885f9eaccadd23b766ecbc064f17f06ae883.tar.gz | |
Phase 2 of read-only-plans project: restructure expression-tree nodes
so that all executable expression nodes inherit from a common supertype
Expr. This is somewhat of an exercise in code purity rather than any
real functional advance, but getting rid of the extra Oper or Func node
formerly used in each operator or function call should provide at least
a little space and speed improvement.
initdb forced by changes in stored-rules representation.
Diffstat (limited to 'src/backend/optimizer')
| -rw-r--r-- | src/backend/optimizer/path/clausesel.c | 23 | ||||
| -rw-r--r-- | src/backend/optimizer/path/costsize.c | 91 | ||||
| -rw-r--r-- | src/backend/optimizer/path/indxpath.c | 92 | ||||
| -rw-r--r-- | src/backend/optimizer/path/orindxpath.c | 4 | ||||
| -rw-r--r-- | src/backend/optimizer/path/pathkeys.c | 31 | ||||
| -rw-r--r-- | src/backend/optimizer/path/tidpath.c | 53 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 29 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 29 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 10 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 62 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/subselect.c | 44 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/prepqual.c | 101 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/preptlist.c | 6 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 16 | ||||
| -rw-r--r-- | src/backend/optimizer/util/clauses.c | 1114 | ||||
| -rw-r--r-- | src/backend/optimizer/util/tlist.c | 6 | ||||
| -rw-r--r-- | src/backend/optimizer/util/var.c | 18 |
17 files changed, 869 insertions, 860 deletions
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index d0976ca421..0294c82812 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.53 2002/11/25 21:29:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.54 2002/12/12 15:49:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -141,7 +141,7 @@ clauselist_selectivity(Query *root, if (is_opclause(clause) && (varRelid != 0 || NumRelids(clause) == 1)) { - Expr *expr = (Expr *) clause; + OpExpr *expr = (OpExpr *) clause; if (length(expr->args) == 2) { @@ -151,7 +151,7 @@ clauselist_selectivity(Query *root, (varonleft = false, is_pseudo_constant_clause(lfirst(expr->args)))) { - Oid opno = ((Oper *) expr->oper)->opno; + Oid opno = expr->opno; RegProcedure oprrest = get_oprrest(opno); s2 = restriction_selectivity(root, opno, @@ -430,7 +430,7 @@ clause_selectivity(Query *root, { /* share code with clauselist_selectivity() */ s1 = clauselist_selectivity(root, - ((Expr *) clause)->args, + ((BoolExpr *) clause)->args, varRelid); } else if (or_clause(clause)) @@ -443,7 +443,7 @@ clause_selectivity(Query *root, List *arg; s1 = 0.0; - foreach(arg, ((Expr *) clause)->args) + foreach(arg, ((BoolExpr *) clause)->args) { Selectivity s2 = clause_selectivity(root, (Node *) lfirst(arg), @@ -454,7 +454,7 @@ clause_selectivity(Query *root, } else if (is_opclause(clause)) { - Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno; + Oid opno = ((OpExpr *) clause)->opno; bool is_join_clause; if (varRelid != 0) @@ -479,13 +479,14 @@ clause_selectivity(Query *root, { /* Estimate selectivity for a join clause. */ s1 = join_selectivity(root, opno, - ((Expr *) clause)->args); + ((OpExpr *) clause)->args); } else { /* Estimate selectivity for a restriction clause. */ s1 = restriction_selectivity(root, opno, - ((Expr *) clause)->args, varRelid); + ((OpExpr *) clause)->args, + varRelid); } } else if (is_funcclause(clause)) @@ -509,7 +510,7 @@ clause_selectivity(Query *root, /* Use node specific selectivity calculation function */ s1 = nulltestsel(root, ((NullTest *) clause)->nulltesttype, - ((NullTest *) clause)->arg, + (Node *) ((NullTest *) clause)->arg, varRelid); } else if (IsA(clause, BooleanTest)) @@ -517,14 +518,14 @@ clause_selectivity(Query *root, /* Use node specific selectivity calculation function */ s1 = booltestsel(root, ((BooleanTest *) clause)->booltesttype, - ((BooleanTest *) clause)->arg, + (Node *) ((BooleanTest *) clause)->arg, varRelid); } else if (IsA(clause, RelabelType)) { /* Not sure this case is needed, but it can't hurt */ s1 = clause_selectivity(root, - ((RelabelType *) clause)->arg, + (Node *) ((RelabelType *) clause)->arg, varRelid); } diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 1db310fc52..2125ff034f 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -42,7 +42,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.93 2002/11/30 05:21:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.94 2002/12/12 15:49:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1220,63 +1220,48 @@ cost_qual_eval_walker(Node *node, Cost *total) * Should we try to account for the possibility of short-circuit * evaluation of AND/OR? */ - if (IsA(node, Expr)) + if (IsA(node, FuncExpr) || + IsA(node, OpExpr) || + IsA(node, DistinctExpr)) + *total += cpu_operator_cost; + else if (IsA(node, SubPlanExpr)) { - Expr *expr = (Expr *) node; + /* + * A subplan node in an expression indicates that the + * subplan will be executed on each evaluation, so charge + * accordingly. (We assume that sub-selects that can be + * executed as InitPlans have already been removed from + * the expression.) + * + * NOTE: this logic should agree with the estimates used by + * make_subplan() in plan/subselect.c. + */ + SubPlanExpr *subplan = (SubPlanExpr *) node; + Plan *plan = subplan->plan; + Cost subcost; - switch (expr->opType) + if (subplan->sublink->subLinkType == EXISTS_SUBLINK) { - case OP_EXPR: - case DISTINCT_EXPR: - case FUNC_EXPR: - *total += cpu_operator_cost; - break; - case OR_EXPR: - case AND_EXPR: - case NOT_EXPR: - break; - case SUBPLAN_EXPR: - - /* - * A subplan node in an expression indicates that the - * subplan will be executed on each evaluation, so charge - * accordingly. (We assume that sub-selects that can be - * executed as InitPlans have already been removed from - * the expression.) - * - * NOTE: this logic should agree with the estimates used by - * make_subplan() in plan/subselect.c. - */ - { - SubPlan *subplan = (SubPlan *) expr->oper; - Plan *plan = subplan->plan; - Cost subcost; - - if (subplan->sublink->subLinkType == EXISTS_SUBLINK) - { - /* we only need to fetch 1 tuple */ - subcost = plan->startup_cost + - (plan->total_cost - plan->startup_cost) / plan->plan_rows; - } - else if (subplan->sublink->subLinkType == ALL_SUBLINK || - subplan->sublink->subLinkType == ANY_SUBLINK) - { - /* assume we need 50% of the tuples */ - subcost = plan->startup_cost + - 0.50 * (plan->total_cost - plan->startup_cost); - /* XXX what if subplan has been materialized? */ - } - else - { - /* assume we need all tuples */ - subcost = plan->total_cost; - } - *total += subcost; - } - break; + /* we only need to fetch 1 tuple */ + subcost = plan->startup_cost + + (plan->total_cost - plan->startup_cost) / plan->plan_rows; } - /* fall through to examine args of Expr node */ + else if (subplan->sublink->subLinkType == ALL_SUBLINK || + subplan->sublink->subLinkType == ANY_SUBLINK) + { + /* assume we need 50% of the tuples */ + subcost = plan->startup_cost + + 0.50 * (plan->total_cost - plan->startup_cost); + /* XXX what if subplan has been materialized? */ + } + else + { + /* assume we need all tuples */ + subcost = plan->total_cost; + } + *total += subcost; } + return expression_tree_walker(node, cost_qual_eval_walker, (void *) total); } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index c0241bb9ef..7a20de8c1c 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.126 2002/11/25 21:29:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.127 2002/12/12 15:49:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -73,6 +73,8 @@ static bool match_clause_to_indexkey(RelOptInfo *rel, IndexOptInfo *index, int indexkey, Oid opclass, Expr *clause); static bool match_join_clause_to_indexkey(RelOptInfo *rel, IndexOptInfo *index, int indexkey, Oid opclass, Expr *clause); +static Oid indexable_operator(Expr *clause, Oid opclass, + bool indexkey_on_left); static bool pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list, int relvarno); static bool pred_test_restrict_list(Expr *predicate, List *restrictinfo_list); @@ -280,7 +282,7 @@ match_index_orclauses(RelOptInfo *rel, */ restrictinfo->subclauseindices = match_index_orclause(rel, index, - restrictinfo->clause->args, + ((BoolExpr *) restrictinfo->clause)->args, restrictinfo->subclauseindices); } } @@ -377,7 +379,7 @@ match_or_subclause_to_indexkey(RelOptInfo *rel, { List *item; - foreach(item, clause->args) + foreach(item, ((BoolExpr *) clause)->args) { if (match_clause_to_indexkey(rel, index, indexkey, opclass, lfirst(item))) @@ -443,7 +445,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel, if (and_clause((Node *) orsubclause)) { - foreach(item, orsubclause->args) + foreach(item, ((BoolExpr *) orsubclause)->args) { Expr *subsubclause = (Expr *) lfirst(item); @@ -715,7 +717,7 @@ match_clause_to_indexkey(RelOptInfo *rel, *rightop; /* Clause must be a binary opclause. */ - if (!is_opclause((Node *) clause)) + if (!is_opclause(clause)) return false; leftop = get_leftop(clause); rightop = get_rightop(clause); @@ -803,7 +805,7 @@ match_join_clause_to_indexkey(RelOptInfo *rel, *rightop; /* Clause must be a binary opclause. */ - if (!is_opclause((Node *) clause)) + if (!is_opclause(clause)) return false; leftop = get_leftop(clause); rightop = get_rightop(clause); @@ -857,10 +859,10 @@ match_join_clause_to_indexkey(RelOptInfo *rel, * (Formerly, this routine might return a binary-compatible operator * rather than the original one, but that kluge is history.) */ -Oid +static Oid indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left) { - Oid expr_op = ((Oper *) clause->oper)->opno; + Oid expr_op = ((OpExpr *) clause)->opno; Oid commuted_op; /* Get the commuted operator if necessary */ @@ -985,7 +987,7 @@ pred_test_recurse_clause(Expr *predicate, Node *clause) Assert(clause != NULL); if (or_clause(clause)) { - items = ((Expr *) clause)->args; + items = ((BoolExpr *) clause)->args; foreach(item, items) { /* if any OR item doesn't imply the predicate, clause doesn't */ @@ -996,7 +998,7 @@ pred_test_recurse_clause(Expr *predicate, Node *clause) } else if (and_clause(clause)) { - items = ((Expr *) clause)->args; + items = ((BoolExpr *) clause)->args; foreach(item, items) { /* @@ -1029,7 +1031,7 @@ pred_test_recurse_pred(Expr *predicate, Node *clause) Assert(predicate != NULL); if (or_clause((Node *) predicate)) { - items = predicate->args; + items = ((BoolExpr *) predicate)->args; foreach(item, items) { /* if any item is implied, the whole predicate is implied */ @@ -1040,7 +1042,7 @@ pred_test_recurse_pred(Expr *predicate, Node *clause) } else if (and_clause((Node *) predicate)) { - items = predicate->args; + items = ((BoolExpr *) predicate)->args; foreach(item, items) { /* @@ -1121,7 +1123,6 @@ pred_test_simple_clause(Expr *predicate, Node *clause) StrategyNumber pred_strategy = 0, clause_strategy, test_strategy; - Oper *test_oper; Expr *test_expr; Datum test_result; bool isNull; @@ -1140,7 +1141,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause) * Can't do anything more unless they are both binary opclauses with a * Var on the left and a Const on the right. */ - if (!is_opclause((Node *) predicate)) + if (!is_opclause(predicate)) return false; pred_var = (Var *) get_leftop(predicate); pred_const = (Const *) get_rightop(predicate); @@ -1167,8 +1168,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause) return false; /* Get the operators for the two clauses we're comparing */ - pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno; - clause_op = ((Oper *) ((Expr *) clause)->oper)->opno; + pred_op = ((OpExpr *) predicate)->opno; + clause_op = ((OpExpr *) clause)->opno; /* * 1. Find a "btree" strategy number for the pred_op @@ -1267,14 +1268,12 @@ pred_test_simple_clause(Expr *predicate, Node *clause) /* * 5. Evaluate the test */ - test_oper = makeOper(test_op, /* opno */ - InvalidOid, /* opid */ - BOOLOID, /* opresulttype */ - false); /* opretset */ - replace_opid(test_oper); - test_expr = make_opclause(test_oper, - (Var *) clause_const, - (Var *) pred_const); + test_expr = make_opclause(test_op, + BOOLOID, + false, + (Expr *) clause_const, + (Expr *) pred_const); + set_opfuncid((OpExpr *) test_expr); econtext = MakeExprContext(NULL, TransactionCommandContext); test_result = ExecEvalExprSwitchContext((Node *) test_expr, econtext, @@ -1627,7 +1626,7 @@ static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index) { int relvarno = lfirsti(rel->relids); - Func *function; + FuncExpr *function; List *funcargs; int *indexKeys = index->indexkeys; List *arg; @@ -1636,13 +1635,12 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index) /* * sanity check, make sure we know what we're dealing with here. */ - if (funcOpnd == NULL || !IsA(funcOpnd, Expr) || - funcOpnd->opType != FUNC_EXPR || - funcOpnd->oper == NULL || indexKeys == NULL) + if (funcOpnd == NULL || !IsA(funcOpnd, FuncExpr) || + indexKeys == NULL) return false; - function = (Func *) funcOpnd->oper; - funcargs = funcOpnd->args; + function = (FuncExpr *) funcOpnd; + funcargs = function->args; if (function->funcid != index->indproc) return false; @@ -1752,7 +1750,7 @@ match_special_index_operator(Expr *clause, Oid opclass, /* we know these will succeed */ leftop = get_leftop(clause); rightop = get_rightop(clause); - expr_op = ((Oper *) clause->oper)->opno; + expr_op = ((OpExpr *) clause)->opno; /* again, required for all current special ops: */ if (!IsA(rightop, Const) || @@ -1916,7 +1914,7 @@ expand_indexqual_conditions(List *indexquals) /* we know these will succeed */ Var *leftop = get_leftop(clause); Var *rightop = get_rightop(clause); - Oid expr_op = ((Oper *) clause->oper)->opno; + Oid expr_op = ((OpExpr *) clause)->opno; Const *patt = (Const *) rightop; Const *prefix = NULL; Const *rest = NULL; @@ -2011,7 +2009,6 @@ prefix_quals(Var *leftop, Oid expr_op, Oid oproid; char *prefix; Const *con; - Oper *op; Expr *expr; Const *greaterstr = NULL; @@ -2070,8 +2067,8 @@ prefix_quals(Var *leftop, Oid expr_op, if (oproid == InvalidOid) elog(ERROR, "prefix_quals: no = operator for type %u", datatype); con = string_to_const(prefix, datatype); - op = makeOper(oproid, InvalidOid, BOOLOID, false); - expr = make_opclause(op, leftop, (Var *) con); + expr = make_opclause(oproid, BOOLOID, false, + (Expr *) leftop, (Expr *) con); result = makeList1(expr); return result; } @@ -2085,8 +2082,8 @@ prefix_quals(Var *leftop, Oid expr_op, if (oproid == InvalidOid) elog(ERROR, "prefix_quals: no >= operator for type %u", datatype); con = string_to_const(prefix, datatype); - op = makeOper(oproid, InvalidOid, BOOLOID, false); - expr = make_opclause(op, leftop, (Var *) con); + expr = make_opclause(oproid, BOOLOID, false, + (Expr *) leftop, (Expr *) con); result = makeList1(expr); /*------- @@ -2100,8 +2097,8 @@ prefix_quals(Var *leftop, Oid expr_op, oproid = find_operator("<", datatype); if (oproid == InvalidOid) elog(ERROR, "prefix_quals: no < operator for type %u", datatype); - op = makeOper(oproid, InvalidOid, BOOLOID, false); - expr = make_opclause(op, leftop, (Var *) greaterstr); + expr = make_opclause(oproid, BOOLOID, false, + (Expr *) leftop, (Expr *) greaterstr); result = lappend(result, expr); } @@ -2124,7 +2121,6 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) Oid opr2oid; List *result; Oid datatype; - Oper *op; Expr *expr; switch (expr_op) @@ -2164,10 +2160,10 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) opr1right = network_scan_first(rightop); - op = makeOper(opr1oid, InvalidOid, BOOLOID, false); - expr = make_opclause(op, leftop, - (Var *) makeConst(datatype, -1, opr1right, - false, false)); + expr = make_opclause(opr1oid, BOOLOID, false, + (Expr *) leftop, + (Expr *) makeConst(datatype, -1, opr1right, + false, false)); result = makeList1(expr); /* create clause "key <= network_scan_last( rightop )" */ @@ -2179,10 +2175,10 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) opr2right = network_scan_last(rightop); - op = makeOper(opr2oid, InvalidOid, BOOLOID, false); - expr = make_opclause(op, leftop, - (Var *) makeConst(datatype, -1, opr2right, - false, false)); + expr = make_opclause(opr2oid, BOOLOID, false, + (Expr *) leftop, + (Expr *) makeConst(datatype, -1, opr2right, + false, false)); result = lappend(result, expr); return result; diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index 009afdff07..101866867b 100644 --- a/src/backend/optimizer/path/orindxpath.c +++ b/src/backend/optimizer/path/orindxpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.48 2002/11/24 21:52:14 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.49 2002/12/12 15:49:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -96,7 +96,7 @@ create_or_index_paths(Query *root, RelOptInfo *rel) best_or_subclause_indices(root, rel, - restrictinfo->clause->args, + ((BoolExpr *) restrictinfo->clause)->args, restrictinfo->subclauseindices, pathnode); diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 350c761165..af0b61a403 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -11,7 +11,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.41 2002/09/18 21:35:21 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.42 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -514,14 +514,16 @@ build_index_pathkeys(Query *root, if (index->indproc) { /* Functional index: build a representation of the function call */ - Func *funcnode = makeNode(Func); + Expr *funcnode; List *funcargs = NIL; - funcnode->funcid = index->indproc; - funcnode->funcresulttype = get_func_rettype(index->indproc); - funcnode->funcretset = false; /* can never be a set */ - funcnode->funcformat = COERCE_DONTCARE; /* to match any user expr */ - funcnode->func_fcache = NULL; + sortop = *ordering; + if (ScanDirectionIsBackward(scandir)) + { + sortop = get_commutator(sortop); + if (sortop == InvalidOid) + return NIL; /* oops, no reverse sort operator? */ + } while (*indexkeys != 0) { @@ -530,17 +532,14 @@ build_index_pathkeys(Query *root, indexkeys++; } - sortop = *ordering; - if (ScanDirectionIsBackward(scandir)) - { - sortop = get_commutator(sortop); - if (sortop == InvalidOid) - return NIL; /* oops, no reverse sort operator? */ - } + funcnode = make_funcclause(index->indproc, + get_func_rettype(index->indproc), + false, /* cannot be a set */ + COERCE_DONTCARE, /* to match any user expr */ + funcargs); /* Make a one-sublist pathkeys list for the function expression */ - item = makePathKeyItem((Node *) make_funcclause(funcnode, funcargs), - sortop); + item = makePathKeyItem((Node *) funcnode, sortop); retval = makeList1(make_canonical_pathkey(root, item)); } else diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c index 27fe9e281f..f11ff81ea4 100644 --- a/src/backend/optimizer/path/tidpath.c +++ b/src/backend/optimizer/path/tidpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.12 2002/11/24 21:52:14 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.13 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,15 +27,14 @@ static List *TidqualFromRestrictinfo(List *relids, List *restrictinfo); static bool isEvaluable(int varno, Node *node); -static Node *TidequalClause(int varno, Expr *node); +static Node *TidequalClause(int varno, OpExpr *node); static List *TidqualFromExpr(int varno, Expr *expr); -static -bool +static bool isEvaluable(int varno, Node *node) { List *lst; - Expr *expr; + FuncExpr *expr; if (IsA(node, Const)) return true; @@ -51,7 +50,7 @@ isEvaluable(int varno, Node *node) } if (!is_funcclause(node)) return false; - expr = (Expr *) node; + expr = (FuncExpr *) node; foreach(lst, expr->args) { if (!isEvaluable(varno, lfirst(lst))) @@ -66,33 +65,26 @@ isEvaluable(int varno, Node *node) * Extract the right node if the opclause is CTID= .... * or the left node if the opclause is ....=CTID */ -static -Node * -TidequalClause(int varno, Expr *node) +static Node * +TidequalClause(int varno, OpExpr *node) { - Node *rnode = 0, + Node *rnode = NULL, *arg1, *arg2, *arg; - Oper *oper; Var *var; Const *aconst; Param *param; - Expr *expr; + FuncExpr *expr; - if (!node->oper) - return rnode; - if (!node->args) + if (node->opno != TIDEqualOperator) return rnode; if (length(node->args) != 2) return rnode; - oper = (Oper *) node->oper; - if (oper->opno != TIDEqualOperator) - return rnode; arg1 = lfirst(node->args); arg2 = lsecond(node->args); - arg = (Node *) 0; + arg = NULL; if (IsA(arg1, Var)) { var = (Var *) arg1; @@ -138,11 +130,9 @@ TidequalClause(int varno, Expr *node) return rnode; rnode = arg; break; - case T_Expr: - expr = (Expr *) arg; - if (expr->typeOid != TIDOID) - return rnode; - if (expr->opType != FUNC_EXPR) + case T_FuncExpr: + expr = (FuncExpr *) arg; + if (expr->funcresulttype != TIDOID) return rnode; if (isEvaluable(varno, (Node *) expr)) rnode = arg; @@ -162,8 +152,7 @@ TidequalClause(int varno, Expr *node) * CTID values if we could extract the CTID values from a member * node. */ -static -List * +static List * TidqualFromExpr(int varno, Expr *expr) { List *rlst = NIL, @@ -174,17 +163,15 @@ TidqualFromExpr(int varno, Expr *expr) if (is_opclause(node)) { - rnode = TidequalClause(varno, expr); + rnode = TidequalClause(varno, (OpExpr *) expr); if (rnode) rlst = lcons(rnode, rlst); } else if (and_clause(node)) { - foreach(lst, expr->args) + foreach(lst, ((BoolExpr *) expr)->args) { node = lfirst(lst); - if (!IsA(node, Expr)) - continue; rlst = TidqualFromExpr(varno, (Expr *) node); if (rlst) break; @@ -192,11 +179,11 @@ TidqualFromExpr(int varno, Expr *expr) } else if (or_clause(node)) { - foreach(lst, expr->args) + foreach(lst, ((BoolExpr *) expr)->args) { node = lfirst(lst); - if (IsA(node, Expr) && - (frtn = TidqualFromExpr(varno, (Expr *) node))) + frtn = TidqualFromExpr(varno, (Expr *) node); + if (frtn) rlst = nconc(rlst, frtn); else { diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 0414fdf2f3..a67e23fbf2 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.127 2002/12/05 15:50:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.128 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1041,12 +1041,12 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index, foreach(i, indexqual) { - Expr *clause = (Expr *) lfirst(i); - Expr *newclause; + OpExpr *clause = (OpExpr *) lfirst(i); + OpExpr *newclause; List *leftvarnos; Oid opclass; - if (!is_opclause((Node *) clause) || length(clause->args) != 2) + if (!IsA(clause, OpExpr) || length(clause->args) != 2) elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause"); /* @@ -1056,7 +1056,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index, * is a subplan in the arguments of the opclause. So just do a * full copy. */ - newclause = (Expr *) copyObject((Node *) clause); + newclause = (OpExpr *) copyObject((Node *) clause); /* * Check to see if the indexkey is on the right; if so, commute @@ -1083,7 +1083,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index, * Finally, check to see if index is lossy for this operator. If * so, add (a copy of) original form of clause to recheck list. */ - if (op_requires_recheck(((Oper *) newclause->oper)->opno, opclass)) + if (op_requires_recheck(newclause->opno, opclass)) recheck_qual = lappend(recheck_qual, copyObject((Node *) clause)); } @@ -1100,7 +1100,7 @@ fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index, * Remove any binary-compatible relabeling of the indexkey */ if (IsA(node, RelabelType)) - node = ((RelabelType *) node)->arg; + node = (Node *) ((RelabelType *) node)->arg; /* * We represent index keys by Var nodes having the varno of the base @@ -1168,11 +1168,11 @@ switch_outer(List *clauses) foreach(i, clauses) { - Expr *clause = (Expr *) lfirst(i); + OpExpr *clause = (OpExpr *) lfirst(i); Var *op; - Assert(is_opclause((Node *) clause)); - op = get_rightop(clause); + Assert(is_opclause(clause)); + op = get_rightop((Expr *) clause); Assert(op && IsA(op, Var)); if (var_is_outer(op)) { @@ -1181,10 +1181,13 @@ switch_outer(List *clauses) * the clause without changing the original list. Could use * copyObject, but a complete deep copy is overkill. */ - Expr *temp; + OpExpr *temp = makeNode(OpExpr); - temp = make_clause(clause->opType, clause->oper, - listCopy(clause->args)); + temp->opno = clause->opno; + temp->opfuncid = InvalidOid; + temp->opresulttype = clause->opresulttype; + temp->opretset = clause->opretset; + temp->args = listCopy(clause->args); /* Commute it --- note this modifies the temp node in-place. */ CommuteClause(temp); t_list = lappend(t_list, temp); diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 529ba712f4..aca2c6f4f6 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.77 2002/11/24 21:52:14 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.78 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -761,14 +761,11 @@ process_implied_equality(Query *root, Node *item1, Node *item2, elog(ERROR, "Equality operator for types '%s' and '%s' should be mergejoinable, but isn't", format_type_be(ltype), format_type_be(rtype)); - clause = makeNode(Expr); - clause->typeOid = BOOLOID; - clause->opType = OP_EXPR; - clause->oper = (Node *) makeOper(oprid(eq_operator), /* opno */ - InvalidOid, /* opid */ - BOOLOID, /* opresulttype */ - false); /* opretset */ - clause->args = makeList2(item1, item2); + clause = make_opclause(oprid(eq_operator), /* opno */ + BOOLOID, /* opresulttype */ + false, /* opretset */ + (Expr *) item1, + (Expr *) item2); ReleaseSysCache(eq_operator); @@ -969,7 +966,7 @@ check_mergejoinable(RestrictInfo *restrictinfo) leftOp, rightOp; - if (!is_opclause((Node *) clause)) + if (!is_opclause(clause)) return; left = get_leftop(clause); @@ -978,10 +975,11 @@ check_mergejoinable(RestrictInfo *restrictinfo) /* caution: is_opclause accepts more than I do, so check it */ if (!right) return; /* unary opclauses need not apply */ - if (!IsA(left, Var) ||!IsA(right, Var)) + if (!IsA(left, Var) || + !IsA(right, Var)) return; - opno = ((Oper *) clause->oper)->opno; + opno = ((OpExpr *) clause)->opno; if (op_mergejoinable(opno, left->vartype, @@ -1012,7 +1010,7 @@ check_hashjoinable(RestrictInfo *restrictinfo) *right; Oid opno; - if (!is_opclause((Node *) clause)) + if (!is_opclause(clause)) return; left = get_leftop(clause); @@ -1021,10 +1019,11 @@ check_hashjoinable(RestrictInfo *restrictinfo) /* caution: is_opclause accepts more than I do, so check it */ if (!right) return; /* unary opclauses need not apply */ - if (!IsA(left, Var) ||!IsA(right, Var)) + if (!IsA(left, Var) || + !IsA(right, Var)) return; - opno = ((Oper *) clause->oper)->opno; + opno = ((OpExpr *) clause)->opno; if (op_hashjoinable(opno, left->vartype, diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index ebb9f3d209..b3d7b5303c 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.133 2002/12/05 21:46:37 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.134 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -91,7 +91,7 @@ planner(Query *parse) * purpose is communication across multiple sub-Queries. * * Note we do NOT save and restore PlannerPlanId: it exists to assign - * unique IDs to SubPlan nodes, and we want those IDs to be unique for + * unique IDs to SubPlanExpr nodes, and we want those IDs to be unique for * the life of a backend. Also, PlannerInitPlan is saved/restored in * subquery_planner, not here. */ @@ -278,7 +278,7 @@ subquery_planner(Query *parse, double tuple_fraction) /* Must add the initPlans' extParams to the topmost node's, too */ foreach(lst, plan->initPlan) { - SubPlan *subplan = (SubPlan *) lfirst(lst); + SubPlanExpr *subplan = (SubPlanExpr *) lfirst(lst); plan->extParam = set_unioni(plan->extParam, subplan->plan->extParam); @@ -1015,7 +1015,7 @@ grouping_planner(Query *parse, double tuple_fraction) -1, 0); - ctid = makeTargetEntry(resdom, (Node *) var); + ctid = makeTargetEntry(resdom, (Expr *) var); tlist = lappend(tlist, ctid); } } @@ -1707,7 +1707,7 @@ make_subplanTargetList(Query *parse, exprTypmod(groupexpr), NULL, false), - groupexpr); + (Expr *) groupexpr); sub_tlist = lappend(sub_tlist, te); } diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index b23843a030..0d66c97964 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.84 2002/12/05 15:50:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.85 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -52,7 +52,7 @@ static Node *replace_vars_with_subplan_refs(Node *node, bool tlist_has_non_vars); static Node *replace_vars_with_subplan_refs_mutator(Node *node, replace_vars_with_subplan_refs_context *context); -static bool fix_opids_walker(Node *node, void *context); +static bool fix_opfuncids_walker(Node *node, void *context); /***************************************************************************** * @@ -219,7 +219,7 @@ set_plan_references(Plan *plan, List *rtable) * subplan references in this plan's tlist and quals. If we did the * reference-adjustments bottom-up, then we would fail to match this * plan's var nodes against the already-modified nodes of the - * children. Fortunately, that consideration doesn't apply to SubPlan + * children. Fortunately, that consideration doesn't apply to SubPlanExpr * nodes; else we'd need two passes over the expression trees. */ set_plan_references(plan->lefttree, rtable); @@ -227,9 +227,9 @@ set_plan_references(Plan *plan, List *rtable) foreach(pl, plan->initPlan) { - SubPlan *sp = (SubPlan *) lfirst(pl); + SubPlanExpr *sp = (SubPlanExpr *) lfirst(pl); - Assert(IsA(sp, SubPlan)); + Assert(IsA(sp, SubPlanExpr)); set_plan_references(sp->plan, sp->rtable); } } @@ -238,8 +238,8 @@ set_plan_references(Plan *plan, List *rtable) * fix_expr_references * Do final cleanup on expressions (targetlists or quals). * - * This consists of looking up operator opcode info for Oper nodes - * and recursively performing set_plan_references on SubPlans. + * This consists of looking up operator opcode info for OpExpr nodes + * and recursively performing set_plan_references on subplans. * * The Plan argument is currently unused, but might be needed again someday. */ @@ -255,20 +255,15 @@ fix_expr_references_walker(Node *node, void *context) { if (node == NULL) return false; - if (IsA(node, Expr)) + if (IsA(node, OpExpr)) + set_opfuncid((OpExpr *) node); + else if (IsA(node, DistinctExpr)) + set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ + else if (IsA(node, SubPlanExpr)) { - Expr *expr = (Expr *) node; + SubPlanExpr *sp = (SubPlanExpr *) node; - if (expr->opType == OP_EXPR || - expr->opType == DISTINCT_EXPR) - replace_opid((Oper *) expr->oper); - else if (expr->opType == SUBPLAN_EXPR) - { - SubPlan *sp = (SubPlan *) expr->oper; - - Assert(IsA(sp, SubPlan)); - set_plan_references(sp->plan, sp->rtable); - } + set_plan_references(sp->plan, sp->rtable); } return expression_tree_walker(node, fix_expr_references_walker, context); } @@ -362,12 +357,13 @@ set_uppernode_references(Plan *plan, Index subvarno) TargetEntry *tle = (TargetEntry *) lfirst(l); Node *newexpr; - newexpr = replace_vars_with_subplan_refs(tle->expr, + newexpr = replace_vars_with_subplan_refs((Node *) tle->expr, subvarno, subplan_targetlist, tlist_has_non_vars); output_targetlist = lappend(output_targetlist, - makeTargetEntry(tle->resdom, newexpr)); + makeTargetEntry(tle->resdom, + (Expr *) newexpr)); } plan->targetlist = output_targetlist; @@ -570,8 +566,8 @@ replace_vars_with_subplan_refs_mutator(Node *node, *****************************************************************************/ /* - * fix_opids - * Calculate opid field from opno for each Oper node in given tree. + * fix_opfuncids + * Calculate opfuncid field from opno for each OpExpr node in given tree. * The given tree can be anything expression_tree_walker handles. * * The argument is modified in-place. (This is OK since we'd want the @@ -579,24 +575,20 @@ replace_vars_with_subplan_refs_mutator(Node *node, * shared structure.) */ void -fix_opids(Node *node) +fix_opfuncids(Node *node) { /* This tree walk requires no special setup, so away we go... */ - fix_opids_walker(node, NULL); + fix_opfuncids_walker(node, NULL); } static bool -fix_opids_walker(Node *node, void *context) +fix_opfuncids_walker(Node *node, void *context) { if (node == NULL) return false; - if (IsA(node, Expr)) - { - Expr *expr = (Expr *) node; - - if (expr->opType == OP_EXPR || - expr->opType == DISTINCT_EXPR) - replace_opid((Oper *) expr->oper); - } - return expression_tree_walker(node, fix_opids_walker, context); + if (IsA(node, OpExpr)) + set_opfuncid((OpExpr *) node); + else if (IsA(node, DistinctExpr)) + set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ + return expression_tree_walker(node, fix_opfuncids_walker, context); } diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index a65de72c90..fe17b8ebb0 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.59 2002/12/05 15:50:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.60 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -144,12 +144,12 @@ generate_new_param(Oid paramtype, int32 paramtypmod) } /* - * Convert a bare SubLink (as created by the parser) into a SubPlan. + * Convert a bare SubLink (as created by the parser) into a SubPlanExpr. */ static Node * make_subplan(SubLink *slink) { - SubPlan *node = makeNode(SubPlan); + SubPlanExpr *node = makeNode(SubPlanExpr); Query *subquery = (Query *) (slink->subselect); Oid result_type = exprType((Node *) slink); double tuple_fraction; @@ -210,11 +210,13 @@ make_subplan(SubLink *slink) node->plan = plan = subquery_planner(subquery, tuple_fraction); node->plan_id = PlannerPlanId++; /* Assign unique ID to this - * SubPlan */ + * SubPlanExpr */ node->rtable = subquery->rtable; node->sublink = slink; + node->typeOid = result_type; + slink->subselect = NULL; /* cool ?! see error check above! */ /* @@ -270,7 +272,6 @@ make_subplan(SubLink *slink) } else { - Expr *expr = makeNode(Expr); List *args = NIL; /* @@ -350,14 +351,7 @@ make_subplan(SubLink *slink) convert_sublink_opers(slink, plan->targetlist, NULL); /* - * Make expression of SUBPLAN type - */ - expr->typeOid = result_type; - expr->opType = SUBPLAN_EXPR; - expr->oper = (Node *) node; - - /* - * Make expr->args from parParam. + * Make node->args from parParam. */ foreach(lst, node->parParam) { @@ -373,9 +367,9 @@ make_subplan(SubLink *slink) var->varlevelsup = 0; args = lappend(args, var); } - expr->args = args; + node->args = args; - result = (Node *) expr; + result = (Node *) node; } return result; @@ -385,7 +379,7 @@ make_subplan(SubLink *slink) * convert_sublink_opers: convert a SubLink's oper list from the * parser/rewriter format into the executor's format. * - * The oper list is initially just a list of Oper nodes. We replace it + * The oper list is initially just a list of OpExpr nodes. We replace it * with a list of actually executable expressions, in which the specified * operators are applied to corresponding elements of the lefthand list * and Params representing the results of the subplan. lefthand is then @@ -404,7 +398,7 @@ convert_sublink_opers(SubLink *slink, List *targetlist, foreach(lst, slink->oper) { - Oper *oper = (Oper *) lfirst(lst); + OpExpr *oper = (OpExpr *) lfirst(lst); Node *lefthand = lfirst(leftlist); TargetEntry *te = lfirst(targetlist); Param *prm; @@ -422,7 +416,7 @@ convert_sublink_opers(SubLink *slink, List *targetlist, *setParams = lappendi(*setParams, prm->paramid); /* Look up the operator to check its declared input types */ - Assert(IsA(oper, Oper)); + Assert(IsA(oper, OpExpr)); tup = SearchSysCache(OPEROID, ObjectIdGetDatum(oper->opno), 0, 0, 0); @@ -439,9 +433,11 @@ convert_sublink_opers(SubLink *slink, List *targetlist, left = make_operand(lefthand, exprType(lefthand), opform->oprleft); right = make_operand((Node *) prm, prm->paramtype, opform->oprright); newoper = lappend(newoper, - make_opclause(oper, - (Var *) left, - (Var *) right)); + make_opclause(oper->opno, + oper->opresulttype, + oper->opretset, + (Expr *) left, + (Expr *) right)); ReleaseSysCache(tup); @@ -482,7 +478,7 @@ finalize_primnode(Node *node, finalize_primnode_results *results) } if (is_subplan(node)) { - SubPlan *subplan = (SubPlan *) ((Expr *) node)->oper; + SubPlanExpr *subplan = (SubPlanExpr *) node; List *lst; /* Check extParam list for params to add to paramids */ @@ -559,12 +555,12 @@ process_sublinks_mutator(Node *node, void *context) */ sublink->lefthand = (List *) process_sublinks_mutator((Node *) sublink->lefthand, context); - /* Now build the SubPlan node and make the expr to return */ + /* Now build the SubPlanExpr node and make the expr to return */ return make_subplan(sublink); } /* - * Note that we will never see a SubPlan expression in the input + * Note that we will never see a SubPlanExpr expression in the input * (since this is the very routine that creates 'em to begin with). So * the code in expression_tree_mutator() that might do inappropriate * things with SubPlans or SubLinks will not be exercised. diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index bb00555f69..4016ba476d 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.33 2002/09/02 02:47:02 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.34 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -294,7 +294,7 @@ flatten_andors(Expr *qual) List *out_list = NIL; List *arg; - foreach(arg, qual->args) + foreach(arg, ((BoolExpr *) qual)->args) { Expr *subexpr = flatten_andors((Expr *) lfirst(arg)); @@ -305,7 +305,7 @@ flatten_andors(Expr *qual) * with any other expr. Otherwise we'd need a listCopy here. */ if (and_clause((Node *) subexpr)) - out_list = nconc(out_list, subexpr->args); + out_list = nconc(out_list, ((BoolExpr *) subexpr)->args); else out_list = lappend(out_list, subexpr); } @@ -316,7 +316,7 @@ flatten_andors(Expr *qual) List *out_list = NIL; List *arg; - foreach(arg, qual->args) + foreach(arg, ((BoolExpr *) qual)->args) { Expr *subexpr = flatten_andors((Expr *) lfirst(arg)); @@ -327,7 +327,7 @@ flatten_andors(Expr *qual) * with any other expr. Otherwise we'd need a listCopy here. */ if (or_clause((Node *) subexpr)) - out_list = nconc(out_list, subexpr->args); + out_list = nconc(out_list, ((BoolExpr *) subexpr)->args); else out_list = lappend(out_list, subexpr); } @@ -335,20 +335,17 @@ flatten_andors(Expr *qual) } else if (not_clause((Node *) qual)) return make_notclause(flatten_andors(get_notclausearg(qual))); - else if (is_opclause((Node *) qual)) + else if (is_opclause(qual)) { + OpExpr *opexpr = (OpExpr *) qual; Expr *left = (Expr *) get_leftop(qual); Expr *right = (Expr *) get_rightop(qual); - if (right) - return make_clause(qual->opType, qual->oper, - lcons(flatten_andors(left), - lcons(flatten_andors(right), - NIL))); - else - return make_clause(qual->opType, qual->oper, - lcons(flatten_andors(left), - NIL)); + return make_opclause(opexpr->opno, + opexpr->opresulttype, + opexpr->opretset, + flatten_andors(left), + flatten_andors(right)); } else return qual; @@ -379,7 +376,8 @@ pull_ors(List *orlist) * we'd need a listCopy here. */ if (or_clause((Node *) subexpr)) - out_list = nconc(out_list, pull_ors(subexpr->args)); + out_list = nconc(out_list, + pull_ors(((BoolExpr *) subexpr)->args)); else out_list = lappend(out_list, subexpr); } @@ -410,7 +408,8 @@ pull_ands(List *andlist) * we'd need a listCopy here. */ if (and_clause((Node *) subexpr)) - out_list = nconc(out_list, pull_ands(subexpr->args)); + out_list = nconc(out_list, + pull_ands(((BoolExpr *) subexpr)->args)); else out_list = lappend(out_list, subexpr); } @@ -433,20 +432,17 @@ find_nots(Expr *qual) #ifdef NOT_USED /* recursing into operator expressions is probably not worth it. */ - if (is_opclause((Node *) qual)) + if (is_opclause(qual)) { + OpExpr *opexpr = (OpExpr *) qual; Expr *left = (Expr *) get_leftop(qual); Expr *right = (Expr *) get_rightop(qual); - if (right) - return make_clause(qual->opType, qual->oper, - lcons(find_nots(left), - lcons(find_nots(right), - NIL))); - else - return make_clause(qual->opType, qual->oper, - lcons(find_nots(left), - NIL)); + return make_opclause(opexpr->opno, + opexpr->opresulttype, + opexpr->opretset, + find_nots(left), + find_nots(right)); } #endif if (and_clause((Node *) qual)) @@ -454,7 +450,7 @@ find_nots(Expr *qual) List *t_list = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) t_list = lappend(t_list, find_nots(lfirst(temp))); return make_andclause(pull_ands(t_list)); } @@ -463,7 +459,7 @@ find_nots(Expr *qual) List *t_list = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) t_list = lappend(t_list, find_nots(lfirst(temp))); return make_orclause(pull_ors(t_list)); } @@ -492,20 +488,17 @@ push_nots(Expr *qual) * Otherwise, retain the clause as it is (the 'not' can't be pushed * down any farther). */ - if (is_opclause((Node *) qual)) + if (is_opclause(qual)) { - Oper *oper = (Oper *) ((Expr *) qual)->oper; - Oid negator = get_negator(oper->opno); + OpExpr *opexpr = (OpExpr *) qual; + Oid negator = get_negator(opexpr->opno); if (negator) - { - Oper *op = (Oper *) makeOper(negator, - InvalidOid, - oper->opresulttype, - oper->opretset); - - return make_opclause(op, get_leftop(qual), get_rightop(qual)); - } + return make_opclause(negator, + opexpr->opresulttype, + opexpr->opretset, + (Expr *) get_leftop(qual), + (Expr *) get_rightop(qual)); else return make_notclause(qual); } @@ -521,7 +514,7 @@ push_nots(Expr *qual) List *t_list = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) t_list = lappend(t_list, push_nots(lfirst(temp))); return make_orclause(pull_ors(t_list)); } @@ -530,7 +523,7 @@ push_nots(Expr *qual) List *t_list = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) t_list = lappend(t_list, push_nots(lfirst(temp))); return make_andclause(pull_ands(t_list)); } @@ -576,7 +569,7 @@ find_ors(Expr *qual) List *andlist = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) andlist = lappend(andlist, find_ors(lfirst(temp))); return make_andclause(pull_ands(andlist)); } @@ -585,7 +578,7 @@ find_ors(Expr *qual) List *orlist = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) orlist = lappend(orlist, find_ors(lfirst(temp))); return or_normalize(pull_ors(orlist)); } @@ -629,7 +622,7 @@ or_normalize(List *orlist) if (and_clause((Node *) clause)) { - int nclauses = length(clause->args); + int nclauses = length(((BoolExpr *) clause)->args); if (nclauses > num_subclauses) { @@ -650,7 +643,7 @@ or_normalize(List *orlist) */ orlist = lremove(distributable, orlist); - foreach(temp, distributable->args) + foreach(temp, ((BoolExpr *) distributable)->args) { Expr *andclause = lfirst(temp); List *neworlist; @@ -703,7 +696,7 @@ find_ands(Expr *qual) List *orlist = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) orlist = lappend(orlist, find_ands(lfirst(temp))); return make_orclause(pull_ors(orlist)); } @@ -712,7 +705,7 @@ find_ands(Expr *qual) List *andlist = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) andlist = lappend(andlist, find_ands(lfirst(temp))); return and_normalize(pull_ands(andlist)); } @@ -757,7 +750,7 @@ and_normalize(List *andlist) if (or_clause((Node *) clause)) { - int nclauses = length(clause->args); + int nclauses = length(((BoolExpr *) clause)->args); if (nclauses > num_subclauses) { @@ -778,7 +771,7 @@ and_normalize(List *andlist) */ andlist = lremove(distributable, andlist); - foreach(temp, distributable->args) + foreach(temp, ((BoolExpr *) distributable)->args) { Expr *orclause = lfirst(temp); List *newandlist; @@ -829,7 +822,7 @@ qual_cleanup(Expr *qual) List *andlist = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) andlist = lappend(andlist, qual_cleanup(lfirst(temp))); andlist = remove_duplicates(pull_ands(andlist)); @@ -844,7 +837,7 @@ qual_cleanup(Expr *qual) List *orlist = NIL; List *temp; - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) orlist = lappend(orlist, qual_cleanup(lfirst(temp))); orlist = remove_duplicates(pull_ors(orlist)); @@ -910,7 +903,7 @@ count_bool_nodes(Expr *qual, *nodes = *cnfnodes = 0.0; *dnfnodes = 1.0; /* DNF nodes will be product of sub-counts */ - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) { count_bool_nodes(lfirst(temp), &subnodes, &subcnfnodes, &subdnfnodes); @@ -931,7 +924,7 @@ count_bool_nodes(Expr *qual, *nodes = *dnfnodes = 0.0; *cnfnodes = 1.0; /* CNF nodes will be product of sub-counts */ - foreach(temp, qual->args) + foreach(temp, ((BoolExpr *) qual)->args) { count_bool_nodes(lfirst(temp), &subnodes, &subcnfnodes, &subdnfnodes); diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 6889514306..87d3c983a7 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.58 2002/11/25 21:29:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.59 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -96,7 +96,7 @@ preprocess_targetlist(List *tlist, if (command_type == CMD_DELETE) tlist = listCopy(tlist); - tlist = lappend(tlist, makeTargetEntry(resdom, (Node *) var)); + tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) var)); } return tlist; @@ -215,7 +215,7 @@ expand_targetlist(List *tlist, int command_type, atttypmod, pstrdup(NameStr(att_tup->attname)), false), - new_expr); + (Expr *) new_expr); } new_tlist = lappend(new_tlist, new_tle); diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 79063c0280..a55af2e2d0 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.81 2002/11/25 21:29:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.82 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -406,7 +406,7 @@ generate_setop_tlist(List *colTypes, int flag, * the output tlists of upper-level nodes! */ if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const)) - expr = inputtle->expr; + expr = (Node *) inputtle->expr; else expr = (Node *) makeVar(0, inputtle->resdom->resno, @@ -430,7 +430,7 @@ generate_setop_tlist(List *colTypes, int flag, colTypmod, pstrdup(reftle->resdom->resname), false); - tlist = lappend(tlist, makeTargetEntry(resdom, expr)); + tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr)); input_tlist = lnext(input_tlist); refnames_tlist = lnext(refnames_tlist); } @@ -449,7 +449,7 @@ generate_setop_tlist(List *colTypes, int flag, Int32GetDatum(flag), false, true); - tlist = lappend(tlist, makeTargetEntry(resdom, expr)); + tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr)); } return tlist; @@ -543,7 +543,7 @@ generate_append_tlist(List *colTypes, bool flag, colTypmod, pstrdup(reftle->resdom->resname), false); - tlist = lappend(tlist, makeTargetEntry(resdom, expr)); + tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr)); refnames_tlist = lnext(refnames_tlist); } @@ -561,7 +561,7 @@ generate_append_tlist(List *colTypes, bool flag, INT4OID, -1, 0); - tlist = lappend(tlist, makeTargetEntry(resdom, expr)); + tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr)); } pfree(colTypmods); @@ -872,13 +872,13 @@ adjust_inherited_attrs_mutator(Node *node, */ if (is_subplan(node)) { - SubPlan *subplan; + SubPlanExpr *subplan; /* Copy the node and process subplan args */ node = expression_tree_mutator(node, adjust_inherited_attrs_mutator, (void *) context); /* Make sure we have separate copies of subplan and its rtable */ - subplan = (SubPlan *) ((Expr *) node)->oper; + subplan = (SubPlanExpr *) node; subplan->plan = copyObject(subplan->plan); subplan->rtable = copyObject(subplan->rtable); return node; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index a0d1b752bc..ef317c5b22 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.115 2002/12/01 21:05:14 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.116 2002/12/12 15:49:32 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -70,84 +70,41 @@ static bool contain_mutable_functions_walker(Node *node, void *context); static bool contain_volatile_functions_walker(Node *node, void *context); static bool contain_nonstrict_functions_walker(Node *node, void *context); static Node *eval_const_expressions_mutator(Node *node, List *active_fns); -static Expr *simplify_op_or_func(Expr *expr, List *args, bool allow_inline, - List *active_fns); -static Expr *evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple); -static Expr *inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple, +static Expr *simplify_function(Oid funcid, List *args, bool allow_inline, List *active_fns); +static Expr *evaluate_function(Oid funcid, List *args, HeapTuple func_tuple); +static Expr *inline_function(Oid funcid, List *args, HeapTuple func_tuple, + List *active_fns); static Node *substitute_actual_parameters(Node *expr, int nargs, List *args, int *usecounts); static Node *substitute_actual_parameters_mutator(Node *node, substitute_actual_parameters_context *context); -Expr * -make_clause(int type, Node *oper, List *args) -{ - Expr *expr = makeNode(Expr); - - switch (type) - { - case AND_EXPR: - case OR_EXPR: - case NOT_EXPR: - expr->typeOid = BOOLOID; - break; - case OP_EXPR: - case DISTINCT_EXPR: - expr->typeOid = ((Oper *) oper)->opresulttype; - break; - case FUNC_EXPR: - expr->typeOid = ((Func *) oper)->funcresulttype; - break; - default: - elog(ERROR, "make_clause: unsupported type %d", type); - break; - } - expr->opType = type; - expr->oper = oper; /* ignored for AND, OR, NOT */ - expr->args = args; - return expr; -} - - /***************************************************************************** * OPERATOR clause functions *****************************************************************************/ - -/* - * is_opclause - * - * Returns t iff the clause is an operator clause: - * (op expr expr) or (op expr). - */ -bool -is_opclause(Node *clause) -{ - return (clause != NULL && - IsA(clause, Expr) && - ((Expr *) clause)->opType == OP_EXPR); -} - /* * make_opclause - * Creates a clause given its operator, left operand, and right - * operand (pass NULL to create single-operand clause). + * Creates an operator clause given its operator info, left operand, + * and right operand (pass NULL to create single-operand clause). */ Expr * -make_opclause(Oper *op, Var *leftop, Var *rightop) +make_opclause(Oid opno, Oid opresulttype, bool opretset, + Expr *leftop, Expr *rightop) { - Expr *expr = makeNode(Expr); + OpExpr *expr = makeNode(OpExpr); - expr->typeOid = op->opresulttype; - expr->opType = OP_EXPR; - expr->oper = (Node *) op; + expr->opno = opno; + expr->opfuncid = InvalidOid; + expr->opresulttype = opresulttype; + expr->opretset = opretset; if (rightop) expr->args = makeList2(leftop, rightop); else expr->args = makeList1(leftop); - return expr; + return (Expr *) expr; } /* @@ -163,8 +120,10 @@ make_opclause(Oper *op, Var *leftop, Var *rightop) Var * get_leftop(Expr *clause) { - if (clause->args != NULL) - return lfirst(clause->args); + OpExpr *expr = (OpExpr *) clause; + + if (expr->args != NULL) + return lfirst(expr->args); else return NULL; } @@ -178,124 +137,109 @@ get_leftop(Expr *clause) Var * get_rightop(Expr *clause) { - if (clause->args != NULL && lnext(clause->args) != NULL) - return lfirst(lnext(clause->args)); + OpExpr *expr = (OpExpr *) clause; + + if (expr->args != NULL && lnext(expr->args) != NULL) + return lfirst(lnext(expr->args)); else return NULL; } /***************************************************************************** - * FUNC clause functions + * FUNCTION clause functions *****************************************************************************/ /* - * is_funcclause - * - * Returns t iff the clause is a function clause: (func { expr }). - */ -bool -is_funcclause(Node *clause) -{ - return (clause != NULL && - IsA(clause, Expr) && - ((Expr *) clause)->opType == FUNC_EXPR); -} - -/* * make_funcclause - * - * Creates a function clause given the FUNC node and the functional - * arguments. + * Creates a function clause given its function info and argument list. */ Expr * -make_funcclause(Func *func, List *funcargs) +make_funcclause(Oid funcid, Oid funcresulttype, bool funcretset, + CoercionForm funcformat, List *funcargs) { - Expr *expr = makeNode(Expr); + FuncExpr *expr = makeNode(FuncExpr); - expr->typeOid = func->funcresulttype; - expr->opType = FUNC_EXPR; - expr->oper = (Node *) func; + expr->funcid = funcid; + expr->funcresulttype = funcresulttype; + expr->funcretset = funcretset; + expr->funcformat = funcformat; expr->args = funcargs; - return expr; + return (Expr *) expr; } /***************************************************************************** - * OR clause functions + * NOT clause functions *****************************************************************************/ /* - * or_clause + * not_clause * - * Returns t iff the clause is an 'or' clause: (OR { expr }). + * Returns t iff this is a 'not' clause: (NOT expr). */ bool -or_clause(Node *clause) +not_clause(Node *clause) { return (clause != NULL && - IsA(clause, Expr) && - ((Expr *) clause)->opType == OR_EXPR); + IsA(clause, BoolExpr) && + ((BoolExpr *) clause)->boolop == NOT_EXPR); } /* - * make_orclause + * make_notclause * - * Creates an 'or' clause given a list of its subclauses. + * Create a 'not' clause given the expression to be negated. */ Expr * -make_orclause(List *orclauses) +make_notclause(Expr *notclause) { - Expr *expr = makeNode(Expr); + BoolExpr *expr = makeNode(BoolExpr); - expr->typeOid = BOOLOID; - expr->opType = OR_EXPR; - expr->oper = NULL; - expr->args = orclauses; - return expr; + expr->boolop = NOT_EXPR; + expr->args = makeList1(notclause); + return (Expr *) expr; } -/***************************************************************************** - * NOT clause functions - *****************************************************************************/ - /* - * not_clause + * get_notclausearg * - * Returns t iff this is a 'not' clause: (NOT expr). + * Retrieve the clause within a 'not' clause */ -bool -not_clause(Node *clause) +Expr * +get_notclausearg(Expr *notclause) { - return (clause != NULL && - IsA(clause, Expr) && - ((Expr *) clause)->opType == NOT_EXPR); + return lfirst(((BoolExpr *) notclause)->args); } +/***************************************************************************** + * OR clause functions + *****************************************************************************/ + /* - * make_notclause + * or_clause * - * Create a 'not' clause given the expression to be negated. + * Returns t iff the clause is an 'or' clause: (OR { expr }). */ -Expr * -make_notclause(Expr *notclause) +bool +or_clause(Node *clause) { - Expr *expr = makeNode(Expr); - - expr->typeOid = BOOLOID; - expr->opType = NOT_EXPR; - expr->oper = NULL; - expr->args = makeList1(notclause); - return expr; + return (clause != NULL && + IsA(clause, BoolExpr) && + ((BoolExpr *) clause)->boolop == OR_EXPR); } /* - * get_notclausearg + * make_orclause * - * Retrieve the clause within a 'not' clause + * Creates an 'or' clause given a list of its subclauses. */ Expr * -get_notclausearg(Expr *notclause) +make_orclause(List *orclauses) { - return lfirst(notclause->args); + BoolExpr *expr = makeNode(BoolExpr); + + expr->boolop = OR_EXPR; + expr->args = orclauses; + return (Expr *) expr; } /***************************************************************************** @@ -312,25 +256,23 @@ bool and_clause(Node *clause) { return (clause != NULL && - IsA(clause, Expr) && - ((Expr *) clause)->opType == AND_EXPR); + IsA(clause, BoolExpr) && + ((BoolExpr *) clause)->boolop == AND_EXPR); } /* * make_andclause * - * Create an 'and' clause given its arguments in a list. + * Creates an 'and' clause given a list of its subclauses. */ Expr * make_andclause(List *andclauses) { - Expr *expr = makeNode(Expr); + BoolExpr *expr = makeNode(BoolExpr); - expr->typeOid = BOOLOID; - expr->opType = AND_EXPR; - expr->oper = NULL; + expr->boolop = AND_EXPR; expr->args = andclauses; - return expr; + return (Expr *) expr; } /* @@ -382,7 +324,7 @@ make_ands_implicit(Expr *clause) if (clause == NULL) return NIL; /* NULL -> NIL list == TRUE */ else if (and_clause((Node *) clause)) - return clause->args; + return ((BoolExpr *) clause)->args; else if (IsA(clause, Const) && !((Const *) clause)->constisnull && DatumGetBool(((Const *) clause)->constvalue)) @@ -476,7 +418,7 @@ pull_agg_clause_walker(Node *node, List **listptr) * Complain if the aggregate's argument contains any aggregates; * nested agg functions are semantically nonsensical. */ - if (contain_agg_clause(((Aggref *) node)->target)) + if (contain_agg_clause((Node *) ((Aggref *) node)->target)) elog(ERROR, "Aggregate function calls may not be nested"); /* @@ -512,38 +454,41 @@ expression_returns_set_walker(Node *node, void *context) { if (node == NULL) return false; - if (IsA(node, Expr)) + if (IsA(node, FuncExpr)) { - Expr *expr = (Expr *) node; + FuncExpr *expr = (FuncExpr *) node; - switch (expr->opType) - { - case OP_EXPR: - case DISTINCT_EXPR: - if (((Oper *) expr->oper)->opretset) - return true; - /* else fall through to check args */ - break; - case FUNC_EXPR: - if (((Func *) expr->oper)->funcretset) - return true; - /* else fall through to check args */ - break; - case OR_EXPR: - case AND_EXPR: - case NOT_EXPR: - /* Booleans can't return a set, so no need to recurse */ - return false; - case SUBPLAN_EXPR: - /* Subplans can't presently return sets either */ - return false; - } + if (expr->funcretset) + return true; + /* else fall through to check args */ + } + if (IsA(node, OpExpr)) + { + OpExpr *expr = (OpExpr *) node; + + if (expr->opretset) + return true; + /* else fall through to check args */ + } + if (IsA(node, DistinctExpr)) + { + DistinctExpr *expr = (DistinctExpr *) node; + + if (expr->opretset) + return true; + /* else fall through to check args */ } - /* Avoid recursion for some other cases that can't return a set */ + + /* Avoid recursion for some cases that can't return a set */ + if (IsA(node, BoolExpr)) + return false; if (IsA(node, Aggref)) return false; if (IsA(node, SubLink)) return false; + if (IsA(node, SubPlanExpr)) + return false; + return expression_tree_walker(node, expression_returns_set_walker, context); } @@ -574,7 +519,8 @@ contain_subplans_walker(Node *node, void *context) { if (node == NULL) return false; - if (is_subplan(node) || IsA(node, SubLink)) + if (IsA(node, SubPlanExpr) || + IsA(node, SubLink)) return true; /* abort the tree traversal and return * true */ return expression_tree_walker(node, contain_subplans_walker, context); @@ -584,8 +530,8 @@ contain_subplans_walker(Node *node, void *context) * pull_subplans * Recursively pulls all subplans from an expression tree. * - * Returns list of subplan nodes found. Note the nodes themselves are not - * copied, only referenced. + * Returns list of SubPlanExpr nodes found. Note the nodes themselves + * are not copied, only referenced. */ List * pull_subplans(Node *clause) @@ -603,7 +549,7 @@ pull_subplans_walker(Node *node, List **listptr) return false; if (is_subplan(node)) { - *listptr = lappend(*listptr, ((Expr *) node)->oper); + *listptr = lappend(*listptr, node); /* fall through to check args to subplan */ } return expression_tree_walker(node, pull_subplans_walker, @@ -710,7 +656,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node, */ List *t; - foreach(t, ((Expr *) node)->args) + foreach(t, ((SubPlanExpr *) node)->args) { Node *thisarg = lfirst(t); Var *var; @@ -789,24 +735,29 @@ contain_mutable_functions_walker(Node *node, void *context) { if (node == NULL) return false; - if (IsA(node, Expr)) + if (IsA(node, FuncExpr)) { - Expr *expr = (Expr *) node; + FuncExpr *expr = (FuncExpr *) node; - switch (expr->opType) - { - case OP_EXPR: - case DISTINCT_EXPR: - if (op_volatile(((Oper *) expr->oper)->opno) != PROVOLATILE_IMMUTABLE) - return true; - break; - case FUNC_EXPR: - if (func_volatile(((Func *) expr->oper)->funcid) != PROVOLATILE_IMMUTABLE) - return true; - break; - default: - break; - } + if (func_volatile(expr->funcid) != PROVOLATILE_IMMUTABLE) + return true; + /* else fall through to check args */ + } + if (IsA(node, OpExpr)) + { + OpExpr *expr = (OpExpr *) node; + + if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE) + return true; + /* else fall through to check args */ + } + if (IsA(node, DistinctExpr)) + { + DistinctExpr *expr = (DistinctExpr *) node; + + if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE) + return true; + /* else fall through to check args */ } return expression_tree_walker(node, contain_mutable_functions_walker, context); @@ -839,24 +790,29 @@ contain_volatile_functions_walker(Node *node, void *context) { if (node == NULL) return false; - if (IsA(node, Expr)) + if (IsA(node, FuncExpr)) { - Expr *expr = (Expr *) node; + FuncExpr *expr = (FuncExpr *) node; - switch (expr->opType) - { - case OP_EXPR: - case DISTINCT_EXPR: - if (op_volatile(((Oper *) expr->oper)->opno) == PROVOLATILE_VOLATILE) - return true; - break; - case FUNC_EXPR: - if (func_volatile(((Func *) expr->oper)->funcid) == PROVOLATILE_VOLATILE) - return true; - break; - default: - break; - } + if (func_volatile(expr->funcid) == PROVOLATILE_VOLATILE) + return true; + /* else fall through to check args */ + } + if (IsA(node, OpExpr)) + { + OpExpr *expr = (OpExpr *) node; + + if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE) + return true; + /* else fall through to check args */ + } + if (IsA(node, DistinctExpr)) + { + DistinctExpr *expr = (DistinctExpr *) node; + + if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE) + return true; + /* else fall through to check args */ } return expression_tree_walker(node, contain_volatile_functions_walker, context); @@ -876,7 +832,7 @@ contain_volatile_functions_walker(Node *node, void *context) * * XXX we do not examine sublinks/subplans to see if they contain uses of * nonstrict functions. It's not real clear if that is correct or not... - * for the current usage it does not matter, since inline_op_or_func() + * for the current usage it does not matter, since inline_function() * rejects cases with sublinks. */ bool @@ -890,23 +846,33 @@ contain_nonstrict_functions_walker(Node *node, void *context) { if (node == NULL) return false; - if (IsA(node, Expr)) + if (IsA(node, FuncExpr)) + { + FuncExpr *expr = (FuncExpr *) node; + + if (!func_strict(expr->funcid)) + return true; + /* else fall through to check args */ + } + if (IsA(node, OpExpr)) + { + OpExpr *expr = (OpExpr *) node; + + if (!op_strict(expr->opno)) + return true; + /* else fall through to check args */ + } + if (IsA(node, DistinctExpr)) + { + /* IS DISTINCT FROM is inherently non-strict */ + return true; + } + if (IsA(node, BoolExpr)) { - Expr *expr = (Expr *) node; + BoolExpr *expr = (BoolExpr *) node; - switch (expr->opType) + switch (expr->boolop) { - case OP_EXPR: - if (!op_strict(((Oper *) expr->oper)->opno)) - return true; - break; - case DISTINCT_EXPR: - /* IS DISTINCT FROM is inherently non-strict */ - return true; - case FUNC_EXPR: - if (!func_strict(((Func *) expr->oper)->funcid)) - return true; - break; case OR_EXPR: case AND_EXPR: /* OR, AND are inherently non-strict */ @@ -1147,39 +1113,28 @@ NumRelids(Node *clause) * XXX the clause is destructively modified! */ void -CommuteClause(Expr *clause) +CommuteClause(OpExpr *clause) { Oid opoid; - HeapTuple optup; - Form_pg_operator commuTup; - Oper *commu; Node *temp; - if (!is_opclause((Node *) clause) || + if (!is_opclause(clause) || length(clause->args) != 2) elog(ERROR, "CommuteClause: applied to non-binary-operator clause"); - opoid = ((Oper *) clause->oper)->opno; - - optup = SearchSysCache(OPEROID, - ObjectIdGetDatum(get_commutator(opoid)), - 0, 0, 0); - if (!HeapTupleIsValid(optup)) - elog(ERROR, "CommuteClause: no commutator for operator %u", opoid); - - commuTup = (Form_pg_operator) GETSTRUCT(optup); + opoid = get_commutator(clause->opno); - commu = makeOper(HeapTupleGetOid(optup), - commuTup->oprcode, - commuTup->oprresult, - ((Oper *) clause->oper)->opretset); - - ReleaseSysCache(optup); + if (!OidIsValid(opoid)) + elog(ERROR, "CommuteClause: no commutator for operator %u", + clause->opno); /* - * re-form the clause in-place! + * modify the clause in-place! */ - clause->oper = (Node *) commu; + clause->opno = opoid; + clause->opfuncid = InvalidOid; + /* opresulttype and opretset are assumed not to change */ + temp = lfirst(clause->args); lfirst(clause->args) = lsecond(clause->args); lsecond(clause->args) = temp; @@ -1223,15 +1178,94 @@ eval_const_expressions_mutator(Node *node, List *active_fns) { if (node == NULL) return NULL; - if (IsA(node, Expr)) + if (IsA(node, FuncExpr)) { - Expr *expr = (Expr *) node; + FuncExpr *expr = (FuncExpr *) node; List *args; - Const *const_input; - Expr *newexpr; + Expr *simple; + FuncExpr *newexpr; + + /* + * Reduce constants in the FuncExpr's arguments. We know args is + * either NIL or a List node, so we can call + * expression_tree_mutator directly rather than recursing to self. + */ + args = (List *) expression_tree_mutator((Node *) expr->args, + eval_const_expressions_mutator, + (void *) active_fns); + /* + * Code for op/func reduction is pretty bulky, so split it out + * as a separate function. + */ + simple = simplify_function(expr->funcid, args, true, active_fns); + if (simple) /* successfully simplified it */ + return (Node *) simple; + /* + * The expression cannot be simplified any further, so build and + * return a replacement FuncExpr node using the possibly-simplified + * arguments. + */ + newexpr = makeNode(FuncExpr); + newexpr->funcid = expr->funcid; + newexpr->funcresulttype = expr->funcresulttype; + newexpr->funcretset = expr->funcretset; + newexpr->funcformat = expr->funcformat; + newexpr->args = args; + return (Node *) newexpr; + } + if (IsA(node, OpExpr)) + { + OpExpr *expr = (OpExpr *) node; + List *args; + Expr *simple; + OpExpr *newexpr; /* - * Reduce constants in the Expr's arguments. We know args is + * Reduce constants in the OpExpr's arguments. We know args is + * either NIL or a List node, so we can call + * expression_tree_mutator directly rather than recursing to self. + */ + args = (List *) expression_tree_mutator((Node *) expr->args, + eval_const_expressions_mutator, + (void *) active_fns); + /* + * Need to get OID of underlying function. Okay to scribble on + * input to this extent. + */ + set_opfuncid(expr); + /* + * Code for op/func reduction is pretty bulky, so split it out + * as a separate function. + */ + simple = simplify_function(expr->opfuncid, args, true, active_fns); + if (simple) /* successfully simplified it */ + return (Node *) simple; + /* + * The expression cannot be simplified any further, so build and + * return a replacement OpExpr node using the possibly-simplified + * arguments. + */ + newexpr = makeNode(OpExpr); + newexpr->opno = expr->opno; + newexpr->opfuncid = expr->opfuncid; + newexpr->opresulttype = expr->opresulttype; + newexpr->opretset = expr->opretset; + newexpr->args = args; + return (Node *) newexpr; + } + if (IsA(node, DistinctExpr)) + { + DistinctExpr *expr = (DistinctExpr *) node; + List *args; + List *arg; + bool has_null_input = false; + bool all_null_input = true; + bool has_nonconst_input = false; + Expr *simple; + DistinctExpr *newexpr; + + /* + * Reduce constants in the DistinctExpr's arguments. We know args is * either NIL or a List node, so we can call * expression_tree_mutator directly rather than recursing to self. */ @@ -1239,76 +1273,83 @@ eval_const_expressions_mutator(Node *node, List *active_fns) eval_const_expressions_mutator, (void *) active_fns); - switch (expr->opType) + /* + * We must do our own check for NULLs because + * DistinctExpr has different results for NULL input + * than the underlying operator does. + */ + foreach(arg, args) { - case OP_EXPR: - case FUNC_EXPR: + if (IsA(lfirst(arg), Const)) + { + has_null_input |= ((Const *) lfirst(arg))->constisnull; + all_null_input &= ((Const *) lfirst(arg))->constisnull; + } + else + has_nonconst_input = true; + } - /* - * Code for op/func case is pretty bulky, so split it out - * as a separate function. - */ - newexpr = simplify_op_or_func(expr, args, - true, active_fns); - if (newexpr) /* successfully simplified it */ - return (Node *) newexpr; + /* all constants? then can optimize this out */ + if (!has_nonconst_input) + { + /* all nulls? then not distinct */ + if (all_null_input) + return MAKEBOOLCONST(false, false); - /* - * else fall out to build new Expr node with simplified - * args - */ - break; - case DISTINCT_EXPR: - { - List *arg; - bool has_null_input = false; - bool all_null_input = true; - bool has_nonconst_input = false; + /* one null? then distinct */ + if (has_null_input) + return MAKEBOOLCONST(true, false); - /* - * We must do our own check for NULLs because - * DISTINCT_EXPR has different results for NULL input - * than the underlying operator does. - */ - foreach(arg, args) - { - if (IsA(lfirst(arg), Const)) - { - has_null_input |= ((Const *) lfirst(arg))->constisnull; - all_null_input &= ((Const *) lfirst(arg))->constisnull; - } - else - has_nonconst_input = true; - } + /* otherwise try to evaluate the '=' operator */ + /* (NOT okay to try to inline it, though!) */ - /* all constants? then can optimize this out */ - if (!has_nonconst_input) - { - /* all nulls? then not distinct */ - if (all_null_input) - return MAKEBOOLCONST(false, false); - - /* one null? then distinct */ - if (has_null_input) - return MAKEBOOLCONST(true, false); - - /* otherwise try to evaluate the '=' operator */ - /* (NOT okay to try to inline it, though!) */ - newexpr = simplify_op_or_func(expr, args, - false, active_fns); - if (newexpr) /* successfully simplified it */ - return (Node *) newexpr; - } + /* + * Need to get OID of underlying function. Okay to scribble on + * input to this extent. + */ + set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */ + /* + * Code for op/func reduction is pretty bulky, so split it out + * as a separate function. + */ + simple = simplify_function(expr->opfuncid, args, + false, active_fns); + if (simple) /* successfully simplified it */ + return (Node *) simple; + } - /* - * else fall out to build new Expr node with simplified - * args - */ - break; - } + /* + * The expression cannot be simplified any further, so build and + * return a replacement DistinctExpr node using the + * possibly-simplified arguments. + */ + newexpr = makeNode(DistinctExpr); + newexpr->opno = expr->opno; + newexpr->opfuncid = expr->opfuncid; + newexpr->opresulttype = expr->opresulttype; + newexpr->opretset = expr->opretset; + newexpr->args = args; + return (Node *) newexpr; + } + if (IsA(node, BoolExpr)) + { + BoolExpr *expr = (BoolExpr *) node; + List *args; + Const *const_input; + + /* + * Reduce constants in the BoolExpr's arguments. We know args is + * either NIL or a List node, so we can call + * expression_tree_mutator directly rather than recursing to self. + */ + args = (List *) expression_tree_mutator((Node *) expr->args, + eval_const_expressions_mutator, + (void *) active_fns); + + switch (expr->boolop) + { case OR_EXPR: { - /*---------- * OR arguments are handled as follows: * non constant: keep @@ -1361,7 +1402,6 @@ eval_const_expressions_mutator(Node *node, List *active_fns) } case AND_EXPR: { - /*---------- * AND arguments are handled as follows: * non constant: keep @@ -1414,47 +1454,34 @@ eval_const_expressions_mutator(Node *node, List *active_fns) } case NOT_EXPR: Assert(length(args) == 1); - if (!IsA(lfirst(args), Const)) - break; - const_input = (Const *) lfirst(args); - /* NOT NULL => NULL */ - if (const_input->constisnull) - return MAKEBOOLCONST(false, true); - /* otherwise pretty easy */ - return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue), - false); - case SUBPLAN_EXPR: - - /* - * Return a SubPlan unchanged --- too late to do anything - * with it. The arglist simplification above was wasted - * work (the list probably only contains Var nodes - * anyway). - * - * XXX should we elog() here instead? Probably this routine - * should never be invoked after SubPlan creation. - */ - return (Node *) expr; + if (IsA(lfirst(args), Const)) + { + const_input = (Const *) lfirst(args); + /* NOT NULL => NULL */ + if (const_input->constisnull) + return MAKEBOOLCONST(false, true); + /* otherwise pretty easy */ + return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue), + false); + } + /* Else we still need a NOT node */ + return (Node *) make_notclause(lfirst(args)); default: - elog(ERROR, "eval_const_expressions: unexpected opType %d", - (int) expr->opType); + elog(ERROR, "eval_const_expressions: unexpected boolop %d", + (int) expr->boolop); break; } - + } + if (IsA(node, SubPlanExpr)) + { /* - * If we break out of the above switch on opType, then the - * expression cannot be simplified any further, so build and - * return a replacement Expr node using the possibly-simplified - * arguments and the original oper node. Can't use make_clause() - * here because we want to be sure the typeOid field is - * preserved... + * Return a SubPlanExpr unchanged --- too late to do anything + * with it. + * + * XXX should we elog() here instead? Probably this routine + * should never be invoked after SubPlanExpr creation. */ - newexpr = makeNode(Expr); - newexpr->typeOid = expr->typeOid; - newexpr->opType = expr->opType; - newexpr->oper = expr->oper; - newexpr->args = args; - return (Node *) newexpr; + return node; } if (IsA(node, RelabelType)) { @@ -1466,14 +1493,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns) RelabelType *relabel = (RelabelType *) node; Node *arg; - arg = eval_const_expressions_mutator(relabel->arg, active_fns); + arg = eval_const_expressions_mutator((Node *) relabel->arg, + active_fns); /* * If we find stacked RelabelTypes (eg, from foo :: int :: oid) we * can discard all but the top one. */ while (arg && IsA(arg, RelabelType)) - arg = ((RelabelType *) arg)->arg; + arg = (Node *) ((RelabelType *) arg)->arg; if (arg && IsA(arg, Const)) { @@ -1493,7 +1521,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns) { RelabelType *newrelabel = makeNode(RelabelType); - newrelabel->arg = arg; + newrelabel->arg = (Expr *) arg; newrelabel->resulttype = relabel->resulttype; newrelabel->resulttypmod = relabel->resulttypmod; return (Node *) newrelabel; @@ -1545,7 +1573,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns) * alternative, the CASE reduces to just this alternative. */ if (newargs == NIL) - return casewhen->result; + return (Node *) casewhen->result; /* * Otherwise, add it to the list, and drop all the rest. @@ -1555,7 +1583,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns) } /* Simplify the default result */ - defresult = eval_const_expressions_mutator(caseexpr->defresult, + defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult, active_fns); /* @@ -1569,7 +1597,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns) newcase->casetype = caseexpr->casetype; newcase->arg = NULL; newcase->args = newargs; - newcase->defresult = defresult; + newcase->defresult = (Expr *) defresult; return (Node *) newcase; } @@ -1585,19 +1613,18 @@ eval_const_expressions_mutator(Node *node, List *active_fns) } /* - * Subroutine for eval_const_expressions: try to simplify an op or func + * Subroutine for eval_const_expressions: try to simplify a function call + * (which might originally have been an operator; we don't care) * - * Inputs are the op or func Expr node, and the pre-simplified argument list; + * Inputs are the function OID and the pre-simplified argument list; * also a list of already-active inline function expansions. * * Returns a simplified expression if successful, or NULL if cannot - * simplify the op/func. + * simplify the function call. */ static Expr * -simplify_op_or_func(Expr *expr, List *args, bool allow_inline, - List *active_fns) +simplify_function(Oid funcid, List *args, bool allow_inline, List *active_fns) { - Oid funcid; HeapTuple func_tuple; Expr *newexpr; @@ -1609,30 +1636,16 @@ simplify_op_or_func(Expr *expr, List *args, bool allow_inline, * to the function's pg_proc tuple, so fetch it just once to use in both * attempts. */ - if (expr->opType == FUNC_EXPR) - { - Func *func = (Func *) expr->oper; - - funcid = func->funcid; - } - else /* OP_EXPR or DISTINCT_EXPR */ - { - Oper *oper = (Oper *) expr->oper; - - replace_opid(oper); /* OK to scribble on input to this extent */ - funcid = oper->opid; - } - func_tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); if (!HeapTupleIsValid(func_tuple)) elog(ERROR, "Function OID %u does not exist", funcid); - newexpr = evaluate_op_or_func(expr, args, func_tuple); + newexpr = evaluate_function(funcid, args, func_tuple); if (!newexpr && allow_inline) - newexpr = inline_op_or_func(expr, args, func_tuple, active_fns); + newexpr = inline_function(funcid, args, func_tuple, active_fns); ReleaseSysCache(func_tuple); @@ -1640,17 +1653,17 @@ simplify_op_or_func(Expr *expr, List *args, bool allow_inline, } /* - * evaluate_op_or_func: try to pre-evaluate an op or func + * evaluate_function: try to pre-evaluate a function call * * We can do this if the function is strict and has any constant-null inputs * (just return a null constant), or if the function is immutable and has all * constant inputs (call it and return the result as a Const node). * * Returns a simplified expression if successful, or NULL if cannot - * simplify the op/func. + * simplify the function. */ static Expr * -evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple) +evaluate_function(Oid funcid, List *args, HeapTuple func_tuple) { Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); Oid result_typeid = funcform->prorettype; @@ -1658,7 +1671,7 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple) bool resultTypByVal; bool has_nonconst_input = false; bool has_null_input = false; - Expr *newexpr; + FuncExpr *newexpr; ExprContext *econtext; Datum const_val; bool const_is_null; @@ -1705,21 +1718,20 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple) * We use the executor's routine ExecEvalExpr() to avoid duplication of * code and ensure we get the same result as the executor would get. * - * Build a new Expr node containing the already-simplified arguments. - * The only other setup needed here is the replace_opid() that - * simplify_op_or_func already did for the OP_EXPR/DISTINCT_EXPR case. + * Build a new FuncExpr node containing the already-simplified arguments. */ - newexpr = makeNode(Expr); - newexpr->typeOid = expr->typeOid; - newexpr->opType = expr->opType; - newexpr->oper = expr->oper; + newexpr = makeNode(FuncExpr); + newexpr->funcid = funcid; + newexpr->funcresulttype = result_typeid; + newexpr->funcretset = false; + newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */ newexpr->args = args; /* Get info needed about result datatype */ get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal); /* - * It is OK to pass a dummy econtext because none of the + * It is OK to use a dummy econtext because none of the * ExecEvalExpr() code used in this situation will use econtext. That * might seem fortuitous, but it's not so unreasonable --- a constant * expression does not depend on context, by definition, n'est ce pas? @@ -1745,7 +1757,7 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple) } /* - * inline_op_or_func: try to expand inline an op or func + * inline_function: try to expand a function call inline * * If the function is a sufficiently simple SQL-language function * (just "SELECT expression"), then we can inline it and avoid the rather @@ -1763,14 +1775,13 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple) * functions by inlining them. * * Returns a simplified expression if successful, or NULL if cannot - * simplify the op/func. + * simplify the function. */ static Expr * -inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple, - List *active_fns) +inline_function(Oid funcid, List *args, HeapTuple func_tuple, + List *active_fns) { Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); - Oid funcid = HeapTupleGetOid(func_tuple); Oid result_typeid = funcform->prorettype; char result_typtype; char *src; @@ -1816,7 +1827,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple, * stuff that parsing might create. */ mycxt = AllocSetContextCreate(CurrentMemoryContext, - "inline_op_or_func", + "inline_function", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); @@ -1828,7 +1839,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple, Anum_pg_proc_prosrc, &isNull); if (isNull) - elog(ERROR, "inline_op_or_func: null prosrc for procedure %u", + elog(ERROR, "inline_function: null prosrc for procedure %u", funcid); src = DatumGetCString(DirectFunctionCall1(textout, tmp)); @@ -1877,7 +1888,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple, length(querytree->targetList) != 1) goto fail; - newexpr = ((TargetEntry *) lfirst(querytree->targetList))->expr; + newexpr = (Node *) ((TargetEntry *) lfirst(querytree->targetList))->expr; /* * Additional validity checks on the expression. It mustn't return a @@ -2065,17 +2076,17 @@ substitute_actual_parameters_mutator(Node *node, * FromExpr, JoinExpr, and SetOperationStmt nodes are handled, so that query * jointrees and setOperation trees can be processed without additional code. * - * expression_tree_walker will handle SubLink and SubPlan nodes by recursing - * normally into the "lefthand" arguments (which belong to the outer plan). - * It will also call the walker on the sub-Query node; however, when - * expression_tree_walker itself is called on a Query node, it does nothing - * and returns "false". The net effect is that unless the walker does - * something special at a Query node, sub-selects will not be visited - * during an expression tree walk. This is exactly the behavior wanted - * in many cases --- and for those walkers that do want to recurse into - * sub-selects, special behavior is typically needed anyway at the entry - * to a sub-select (such as incrementing a depth counter). A walker that - * wants to examine sub-selects should include code along the lines of: + * expression_tree_walker will handle SubLink and SubPlanExpr nodes by + * recursing normally into the "lefthand" arguments (which are expressions + * belonging to the outer plan). It will also call the walker on the + * sub-Query node; however, when expression_tree_walker itself is called on a + * Query node, it does nothing and returns "false". The net effect is that + * unless the walker does something special at a Query node, sub-selects will + * not be visited during an expression tree walk. This is exactly the behavior + * wanted in many cases --- and for those walkers that do want to recurse into + * sub-selects, special behavior is typically needed anyway at the entry to a + * sub-select (such as incrementing a depth counter). A walker that wants to + * examine sub-selects should include code along the lines of: * * if (IsA(node, Query)) * { @@ -2115,29 +2126,12 @@ expression_tree_walker(Node *node, return false; switch (nodeTag(node)) { - case T_Const: case T_Var: + case T_Const: case T_Param: case T_RangeTblRef: /* primitive node types with no subnodes */ break; - case T_Expr: - { - Expr *expr = (Expr *) node; - - if (expr->opType == SUBPLAN_EXPR) - { - /* recurse to the SubLink node (skipping SubPlan!) */ - if (walker((Node *) ((SubPlan *) expr->oper)->sublink, - context)) - return true; - } - /* for all Expr node types, examine args list */ - if (expression_tree_walker((Node *) expr->args, - walker, context)) - return true; - } - break; case T_Aggref: return walker(((Aggref *) node)->target, context); case T_ArrayRef: @@ -2158,41 +2152,41 @@ expression_tree_walker(Node *node, return true; } break; - case T_FieldSelect: - return walker(((FieldSelect *) node)->arg, context); - case T_RelabelType: - return walker(((RelabelType *) node)->arg, context); - case T_CaseExpr: + case T_FuncExpr: { - CaseExpr *caseexpr = (CaseExpr *) node; + FuncExpr *expr = (FuncExpr *) node; - /* we assume walker doesn't care about CaseWhens, either */ - foreach(temp, caseexpr->args) - { - CaseWhen *when = (CaseWhen *) lfirst(temp); + if (expression_tree_walker((Node *) expr->args, + walker, context)) + return true; + } + break; + case T_OpExpr: + { + OpExpr *expr = (OpExpr *) node; - Assert(IsA(when, CaseWhen)); - if (walker(when->expr, context)) - return true; - if (walker(when->result, context)) - return true; - } - /* caseexpr->arg should be null, but we'll check it anyway */ - if (walker(caseexpr->arg, context)) + if (expression_tree_walker((Node *) expr->args, + walker, context)) return true; - if (walker(caseexpr->defresult, context)) + } + break; + case T_DistinctExpr: + { + DistinctExpr *expr = (DistinctExpr *) node; + + if (expression_tree_walker((Node *) expr->args, + walker, context)) return true; } break; - case T_NullTest: - return walker(((NullTest *) node)->arg, context); - case T_BooleanTest: - return walker(((BooleanTest *) node)->arg, context); - case T_ConstraintTest: - if (walker(((ConstraintTest *) node)->arg, context)) - return true; - return walker(((ConstraintTest *) node)->check_expr, context); - case T_ConstraintTestValue: + case T_BoolExpr: + { + BoolExpr *expr = (BoolExpr *) node; + + if (expression_tree_walker((Node *) expr->args, + walker, context)) + return true; + } break; case T_SubLink: { @@ -2202,7 +2196,7 @@ expression_tree_walker(Node *node, * If the SubLink has already been processed by * subselect.c, it will have lefthand=NIL, and we need to * scan the oper list. Otherwise we only need to look at - * the lefthand list (the incomplete Oper nodes in the + * the lefthand list (the incomplete OpExpr nodes in the * oper list are deemed uninteresting, perhaps even * confusing). */ @@ -2224,6 +2218,57 @@ expression_tree_walker(Node *node, return walker(sublink->subselect, context); } break; + case T_SubPlanExpr: + { + SubPlanExpr *expr = (SubPlanExpr *) node; + + /* recurse to the SubLink node, but not into the Plan */ + if (walker((Node *) expr->sublink, context)) + return true; + /* also examine args list */ + if (expression_tree_walker((Node *) expr->args, + walker, context)) + return true; + } + break; + case T_FieldSelect: + return walker(((FieldSelect *) node)->arg, context); + case T_RelabelType: + return walker(((RelabelType *) node)->arg, context); + case T_CaseExpr: + { + CaseExpr *caseexpr = (CaseExpr *) node; + + /* we assume walker doesn't care about CaseWhens, either */ + foreach(temp, caseexpr->args) + { + CaseWhen *when = (CaseWhen *) lfirst(temp); + + Assert(IsA(when, CaseWhen)); + if (walker(when->expr, context)) + return true; + if (walker(when->result, context)) + return true; + } + /* caseexpr->arg should be null, but we'll check it anyway */ + if (walker(caseexpr->arg, context)) + return true; + if (walker(caseexpr->defresult, context)) + return true; + } + break; + case T_NullTest: + return walker(((NullTest *) node)->arg, context); + case T_BooleanTest: + return walker(((BooleanTest *) node)->arg, context); + case T_ConstraintTest: + if (walker(((ConstraintTest *) node)->arg, context)) + return true; + return walker(((ConstraintTest *) node)->check_expr, context); + case T_ConstraintTestValue: + break; + case T_TargetEntry: + return walker(((TargetEntry *) node)->expr, context); case T_Query: /* Do nothing with a sub-Query, per discussion above */ break; @@ -2234,8 +2279,6 @@ expression_tree_walker(Node *node, return true; } break; - case T_TargetEntry: - return walker(((TargetEntry *) node)->expr, context); case T_FromExpr: { FromExpr *from = (FromExpr *) node; @@ -2387,14 +2430,14 @@ query_tree_walker(Query *query, * expression_tree_mutator include all those normally found in target lists * and qualifier clauses during the planning stage. * - * expression_tree_mutator will handle a SUBPLAN_EXPR node by recursing into - * the args and slink->oper lists (which belong to the outer plan), but it + * expression_tree_mutator will handle a SubPlanExpr node by recursing into + * the args and sublink->oper lists (which belong to the outer plan), but it * will simply copy the link to the inner plan, since that's typically what * expression tree mutators want. A mutator that wants to modify the subplan * can force appropriate behavior by recognizing subplan expression nodes * and doing the right thing. * - * Bare SubLink nodes (without a SUBPLAN_EXPR) are handled by recursing into + * Bare SubLink nodes (without a SubPlanExpr) are handled by recursing into * the "lefthand" argument list only. (A bare SubLink should be seen only if * the tree has not yet been processed by subselect.c.) Again, this can be * overridden by the mutator, but it seems to be the most useful default @@ -2428,61 +2471,19 @@ expression_tree_mutator(Node *node, return NULL; switch (nodeTag(node)) { - case T_Const: case T_Var: + case T_Const: case T_Param: case T_RangeTblRef: /* primitive node types with no subnodes */ return (Node *) copyObject(node); - case T_Expr: - { - Expr *expr = (Expr *) node; - Expr *newnode; - - FLATCOPY(newnode, expr, Expr); - - if (expr->opType == SUBPLAN_EXPR) - { - SubLink *oldsublink = ((SubPlan *) expr->oper)->sublink; - SubPlan *newsubplan; - - /* flat-copy the oper node, which is a SubPlan */ - CHECKFLATCOPY(newsubplan, expr->oper, SubPlan); - newnode->oper = (Node *) newsubplan; - /* likewise its SubLink node */ - CHECKFLATCOPY(newsubplan->sublink, oldsublink, SubLink); - - /* - * transform args list (params to be passed to - * subplan) - */ - MUTATE(newnode->args, expr->args, List *); - /* transform sublink's oper list as well */ - MUTATE(newsubplan->sublink->oper, oldsublink->oper, List *); - - /* - * but not the subplan itself, which is referenced - * as-is - */ - } - else - { - /* - * for other Expr node types, just transform args - * list, linking to original oper node (OK?) - */ - MUTATE(newnode->args, expr->args, List *); - } - return (Node *) newnode; - } - break; case T_Aggref: { Aggref *aggref = (Aggref *) node; Aggref *newnode; FLATCOPY(newnode, aggref, Aggref); - MUTATE(newnode->target, aggref->target, Node *); + MUTATE(newnode->target, aggref->target, Expr *); return (Node *) newnode; } break; @@ -2497,9 +2498,81 @@ expression_tree_mutator(Node *node, MUTATE(newnode->reflowerindexpr, arrayref->reflowerindexpr, List *); MUTATE(newnode->refexpr, arrayref->refexpr, - Node *); + Expr *); MUTATE(newnode->refassgnexpr, arrayref->refassgnexpr, - Node *); + Expr *); + return (Node *) newnode; + } + break; + case T_FuncExpr: + { + FuncExpr *expr = (FuncExpr *) node; + FuncExpr *newnode; + + FLATCOPY(newnode, expr, FuncExpr); + MUTATE(newnode->args, expr->args, List *); + return (Node *) newnode; + } + break; + case T_OpExpr: + { + OpExpr *expr = (OpExpr *) node; + OpExpr *newnode; + + FLATCOPY(newnode, expr, OpExpr); + MUTATE(newnode->args, expr->args, List *); + return (Node *) newnode; + } + break; + case T_DistinctExpr: + { + DistinctExpr *expr = (DistinctExpr *) node; + DistinctExpr *newnode; + + FLATCOPY(newnode, expr, DistinctExpr); + MUTATE(newnode->args, expr->args, List *); + return (Node *) newnode; + } + break; + case T_BoolExpr: + { + BoolExpr *expr = (BoolExpr *) node; + BoolExpr *newnode; + + FLATCOPY(newnode, expr, BoolExpr); + MUTATE(newnode->args, expr->args, List *); + return (Node *) newnode; + } + break; + case T_SubLink: + { + /* + * A "bare" SubLink (note we will not come here if we + * found a SubPlanExpr node above it). Transform the + * lefthand side, but not the oper list nor the subquery. + */ + SubLink *sublink = (SubLink *) node; + SubLink *newnode; + + FLATCOPY(newnode, sublink, SubLink); + MUTATE(newnode->lefthand, sublink->lefthand, List *); + return (Node *) newnode; + } + break; + case T_SubPlanExpr: + { + SubPlanExpr *expr = (SubPlanExpr *) node; + SubLink *oldsublink = expr->sublink; + SubPlanExpr *newnode; + + FLATCOPY(newnode, expr, SubPlanExpr); + /* flat-copy the SubLink node */ + CHECKFLATCOPY(newnode->sublink, oldsublink, SubLink); + /* transform args list (params to be passed to subplan) */ + MUTATE(newnode->args, expr->args, List *); + /* transform sublink's oper list as well */ + MUTATE(newnode->sublink->oper, oldsublink->oper, List *); + /* but not the subplan itself, which is referenced as-is */ return (Node *) newnode; } break; @@ -2509,7 +2582,7 @@ expression_tree_mutator(Node *node, FieldSelect *newnode; FLATCOPY(newnode, fselect, FieldSelect); - MUTATE(newnode->arg, fselect->arg, Node *); + MUTATE(newnode->arg, fselect->arg, Expr *); return (Node *) newnode; } break; @@ -2519,7 +2592,7 @@ expression_tree_mutator(Node *node, RelabelType *newnode; FLATCOPY(newnode, relabel, RelabelType); - MUTATE(newnode->arg, relabel->arg, Node *); + MUTATE(newnode->arg, relabel->arg, Expr *); return (Node *) newnode; } break; @@ -2531,8 +2604,8 @@ expression_tree_mutator(Node *node, FLATCOPY(newnode, caseexpr, CaseExpr); MUTATE(newnode->args, caseexpr->args, List *); /* caseexpr->arg should be null, but we'll check it anyway */ - MUTATE(newnode->arg, caseexpr->arg, Node *); - MUTATE(newnode->defresult, caseexpr->defresult, Node *); + MUTATE(newnode->arg, caseexpr->arg, Expr *); + MUTATE(newnode->defresult, caseexpr->defresult, Expr *); return (Node *) newnode; } break; @@ -2542,8 +2615,8 @@ expression_tree_mutator(Node *node, CaseWhen *newnode; FLATCOPY(newnode, casewhen, CaseWhen); - MUTATE(newnode->expr, casewhen->expr, Node *); - MUTATE(newnode->result, casewhen->result, Node *); + MUTATE(newnode->expr, casewhen->expr, Expr *); + MUTATE(newnode->result, casewhen->result, Expr *); return (Node *) newnode; } break; @@ -2553,7 +2626,7 @@ expression_tree_mutator(Node *node, NullTest *newnode; FLATCOPY(newnode, ntest, NullTest); - MUTATE(newnode->arg, ntest->arg, Node *); + MUTATE(newnode->arg, ntest->arg, Expr *); return (Node *) newnode; } break; @@ -2563,7 +2636,7 @@ expression_tree_mutator(Node *node, BooleanTest *newnode; FLATCOPY(newnode, btest, BooleanTest); - MUTATE(newnode->arg, btest->arg, Node *); + MUTATE(newnode->arg, btest->arg, Expr *); return (Node *) newnode; } break; @@ -2573,8 +2646,8 @@ expression_tree_mutator(Node *node, ConstraintTest *newnode; FLATCOPY(newnode, ctest, ConstraintTest); - MUTATE(newnode->arg, ctest->arg, Node *); - MUTATE(newnode->check_expr, ctest->check_expr, Node *); + MUTATE(newnode->arg, ctest->arg, Expr *); + MUTATE(newnode->check_expr, ctest->check_expr, Expr *); return (Node *) newnode; } break; @@ -2587,18 +2660,17 @@ expression_tree_mutator(Node *node, return (Node *) newnode; } break; - case T_SubLink: + case T_TargetEntry: { /* - * A "bare" SubLink (note we will not come here if we - * found a SUBPLAN_EXPR node above it). Transform the - * lefthand side, but not the oper list nor the subquery. + * We mutate the expression, but not the resdom, by + * default. */ - SubLink *sublink = (SubLink *) node; - SubLink *newnode; + TargetEntry *targetentry = (TargetEntry *) node; + TargetEntry *newnode; - FLATCOPY(newnode, sublink, SubLink); - MUTATE(newnode->lefthand, sublink->lefthand, List *); + FLATCOPY(newnode, targetentry, TargetEntry); + MUTATE(newnode->expr, targetentry->expr, Expr *); return (Node *) newnode; } break; @@ -2622,20 +2694,6 @@ expression_tree_mutator(Node *node, return (Node *) resultlist; } break; - case T_TargetEntry: - { - /* - * We mutate the expression, but not the resdom, by - * default. - */ - TargetEntry *targetentry = (TargetEntry *) node; - TargetEntry *newnode; - - FLATCOPY(newnode, targetentry, TargetEntry); - MUTATE(newnode->expr, targetentry->expr, Node *); - return (Node *) newnode; - } - break; case T_FromExpr: { FromExpr *from = (FromExpr *) node; diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index fa8c89862f..0d268b8e40 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.52 2002/06/20 20:29:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.53 2002/12/12 15:49:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -110,7 +110,7 @@ create_tl_element(Var *var, int resdomno) var->vartypmod, NULL, false), - (Node *) var); + (Expr *) var); } /***************************************************************************** @@ -253,5 +253,5 @@ get_sortgroupclause_expr(SortClause *sortClause, List *targetList) { TargetEntry *tle = get_sortgroupclause_tle(sortClause, targetList); - return tle->expr; + return (Node *) tle->expr; } diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 23b824dbcb..8d22aa26b9 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.40 2002/09/11 14:48:54 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.41 2002/12/12 15:49:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -65,7 +65,7 @@ static Node *flatten_join_alias_vars_mutator(Node *node, * NOTE: this is used on not-yet-planned expressions. It may therefore find * bare SubLinks, and if so it needs to recurse into them to look for uplevel * references to the desired rtable level! But when we find a completed - * SubPlan, we only need to look at the parameters passed to the subplan. + * SubPlanExpr, we only need to look at the parameters passed to the subplan. */ List * pull_varnos(Node *node) @@ -111,12 +111,12 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) * executed by the outer query. But short-circuit recursion into * the subquery itself, which would be a waste of effort. */ - Expr *expr = (Expr *) node; + SubPlanExpr *subplan = (SubPlanExpr *) node; - if (pull_varnos_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper, + if (pull_varnos_walker((Node *) subplan->sublink->oper, context)) return true; - if (pull_varnos_walker((Node *) expr->args, + if (pull_varnos_walker((Node *) subplan->args, context)) return true; return false; @@ -146,7 +146,7 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) * NOTE: this is used on not-yet-planned expressions. It may therefore find * bare SubLinks, and if so it needs to recurse into them to look for uplevel * references to the desired rtable entry! But when we find a completed - * SubPlan, we only need to look at the parameters passed to the subplan. + * SubPlanExpr, we only need to look at the parameters passed to the subplan. */ bool contain_var_reference(Node *node, int varno, int varattno, int levelsup) @@ -194,12 +194,12 @@ contain_var_reference_walker(Node *node, * executed by the outer query. But short-circuit recursion into * the subquery itself, which would be a waste of effort. */ - Expr *expr = (Expr *) node; + SubPlanExpr *subplan = (SubPlanExpr *) node; - if (contain_var_reference_walker((Node *) ((SubPlan *) expr->oper)->sublink->oper, + if (contain_var_reference_walker((Node *) subplan->sublink->oper, context)) return true; - if (contain_var_reference_walker((Node *) expr->args, + if (contain_var_reference_walker((Node *) subplan->args, context)) return true; return false; |
