diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/README | 3 | ||||
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 8 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 15 | ||||
-rw-r--r-- | src/backend/optimizer/path/pathkeys.c | 5 | ||||
-rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 7 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepqual.c | 5 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 123 |
8 files changed, 79 insertions, 91 deletions
diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README index 472efbcd9cc..14e39909220 100644 --- a/src/backend/optimizer/README +++ b/src/backend/optimizer/README @@ -42,7 +42,8 @@ base rels of the query. Possible Paths for a primitive table relation include plain old sequential scan, plus index scans for any indexes that exist on the table. A subquery base relation just has one Path, a "SubqueryScan" path (which links to the -subplan that was built by a recursive invocation of the planner). +subplan that was built by a recursive invocation of the planner). Likewise +a function-RTE base relation has only one possible Path. Joins always occur using two RelOptInfos. One is outer, the other inner. Outers drive lookups of values in the inner. In a nested loop, lookups of diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 1e9074186c2..27b6d110bc9 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.84 2002/05/12 20:10:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.85 2002/05/12 23:43:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -312,8 +312,8 @@ set_subquery_pathlist(Query *root, RelOptInfo *rel, * checking that seems more work than it's worth. In any case, a * plain DISTINCT is safe to push down past.) * - * 3. If the subquery has any ITER nodes (ie, functions returning sets) - * in its target list, we do not push down any quals, since the quals + * 3. If the subquery has any functions returning sets in its target list, + * we do not push down any quals, since the quals * might refer to those tlist items, which would mean we'd introduce * functions-returning-sets into the subquery's WHERE/HAVING quals. * (It'd be sufficient to not push down quals that refer to those @@ -333,7 +333,7 @@ set_subquery_pathlist(Query *root, RelOptInfo *rel, subquery->limitOffset == NULL && subquery->limitCount == NULL && !has_distinct_on_clause(subquery) && - !contain_iter_clause((Node *) subquery->targetList)) + !expression_returns_set((Node *) subquery->targetList)) { /* OK to consider pushing down individual quals */ List *upperrestrictlist = NIL; diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 21599b08bd7..6ec1d5af8fa 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.116 2002/04/16 23:08:10 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.117 2002/05/12 23:43:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1316,7 +1316,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause) */ test_oper = makeOper(test_op, /* opno */ InvalidOid, /* opid */ - BOOLOID); /* opresulttype */ + BOOLOID, /* opresulttype */ + false); /* opretset */ replace_opid(test_oper); test_expr = make_opclause(test_oper, (Var *) clause_const, @@ -2020,7 +2021,7 @@ 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); + op = makeOper(oproid, InvalidOid, BOOLOID, false); expr = make_opclause(op, leftop, (Var *) con); result = makeList1(expr); return result; @@ -2035,7 +2036,7 @@ 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); + op = makeOper(oproid, InvalidOid, BOOLOID, false); expr = make_opclause(op, leftop, (Var *) con); result = makeList1(expr); @@ -2051,7 +2052,7 @@ prefix_quals(Var *leftop, Oid expr_op, if (oproid == InvalidOid) elog(ERROR, "prefix_quals: no < operator for type %u", datatype); con = string_to_const(greaterstr, datatype); - op = makeOper(oproid, InvalidOid, BOOLOID); + op = makeOper(oproid, InvalidOid, BOOLOID, false); expr = make_opclause(op, leftop, (Var *) con); result = lappend(result, expr); pfree(greaterstr); @@ -2116,7 +2117,7 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) opr1right = network_scan_first(rightop); - op = makeOper(opr1oid, InvalidOid, BOOLOID); + op = makeOper(opr1oid, InvalidOid, BOOLOID, false); expr = make_opclause(op, leftop, (Var *) makeConst(datatype, -1, opr1right, false, false, false, false)); @@ -2131,7 +2132,7 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) opr2right = network_scan_last(rightop); - op = makeOper(opr2oid, InvalidOid, BOOLOID); + op = makeOper(opr2oid, InvalidOid, BOOLOID, false); expr = make_opclause(op, leftop, (Var *) makeConst(datatype, -1, opr2right, false, false, false, false)); diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 60e05ca340f..a35e86375a2 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.37 2002/03/12 00:51:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.38 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -518,7 +518,8 @@ build_index_pathkeys(Query *root, List *funcargs = NIL; funcnode->funcid = index->indproc; - funcnode->functype = get_func_rettype(index->indproc); + funcnode->funcresulttype = get_func_rettype(index->indproc); + funcnode->funcretset = false; /* can never be a set */ funcnode->func_fcache = NULL; while (*indexkeys != 0) diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 2410651d683..5d35d1b230a 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.69 2002/04/28 19:54:28 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.70 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -764,9 +764,10 @@ process_implied_equality(Query *root, Node *item1, Node *item2, clause = makeNode(Expr); clause->typeOid = BOOLOID; clause->opType = OP_EXPR; - clause->oper = (Node *) makeOper(oprid(eq_operator), /* opno */ + clause->oper = (Node *) makeOper(oprid(eq_operator),/* opno */ InvalidOid, /* opid */ - BOOLOID); /* operator result type */ + BOOLOID, /* opresulttype */ + false); /* opretset */ clause->args = makeList2(item1, item2); ReleaseSysCache(eq_operator); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 5eb17f3b05c..500297f2155 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.116 2002/04/28 19:54:28 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.117 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -498,7 +498,7 @@ is_simple_subquery(Query *subquery) * set-returning functions into places where they mustn't go, * such as quals of higher queries. */ - if (contain_iter_clause((Node *) subquery->targetList)) + if (expression_returns_set((Node *) subquery->targetList)) return false; /* diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index a7773040d79..069563ec18e 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.30 2001/10/25 05:49:33 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.31 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -502,7 +502,8 @@ push_nots(Expr *qual) { Oper *op = (Oper *) makeOper(negator, InvalidOid, - oper->opresulttype); + oper->opresulttype, + oper->opretset); return make_opclause(op, get_leftop(qual), get_rightop(qual)); } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 1a278e9ca2e..972c7f94633 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.98 2002/05/12 20:10:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.99 2002/05/12 23:43:03 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -47,7 +47,7 @@ typedef struct static bool contain_agg_clause_walker(Node *node, void *context); static bool pull_agg_clause_walker(Node *node, List **listptr); -static bool contain_iter_clause_walker(Node *node, void *context); +static bool expression_returns_set_walker(Node *node, void *context); static bool contain_subplans_walker(Node *node, void *context); static bool pull_subplans_walker(Node *node, List **listptr); static bool check_subplans_for_ungrouped_vars_walker(Node *node, @@ -74,7 +74,7 @@ make_clause(int type, Node *oper, List *args) expr->typeOid = ((Oper *) oper)->opresulttype; break; case FUNC_EXPR: - expr->typeOid = ((Func *) oper)->functype; + expr->typeOid = ((Func *) oper)->funcresulttype; break; default: elog(ERROR, "make_clause: unsupported type %d", type); @@ -195,7 +195,7 @@ make_funcclause(Func *func, List *funcargs) { Expr *expr = makeNode(Expr); - expr->typeOid = func->functype; + expr->typeOid = func->funcresulttype; expr->opType = FUNC_EXPR; expr->oper = (Node *) func; expr->args = funcargs; @@ -453,36 +453,61 @@ pull_agg_clause_walker(Node *node, List **listptr) /***************************************************************************** - * Iter clause manipulation + * Support for expressions returning sets *****************************************************************************/ /* - * contain_iter_clause - * Recursively search for Iter nodes within a clause. + * expression_returns_set + * Test whethe an expression returns a set result. * - * Returns true if any Iter found. - * - * XXX Iter is a crock. It'd be better to look directly at each function - * or operator to see if it can return a set. However, that would require - * a lot of extra cycles as things presently stand. The return-type info - * for function and operator nodes should be extended to include whether - * the return is a set. + * Because we use expression_tree_walker(), this can also be applied to + * whole targetlists; it'll produce TRUE if any one of the tlist items + * returns a set. */ bool -contain_iter_clause(Node *clause) +expression_returns_set(Node *clause) { - return contain_iter_clause_walker(clause, NULL); + return expression_returns_set_walker(clause, NULL); } static bool -contain_iter_clause_walker(Node *node, void *context) +expression_returns_set_walker(Node *node, void *context) { if (node == NULL) return false; - if (IsA(node, Iter)) - return true; /* abort the tree traversal and return - * true */ - return expression_tree_walker(node, contain_iter_clause_walker, context); + if (IsA(node, Expr)) + { + Expr *expr = (Expr *) node; + + switch (expr->opType) + { + case OP_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; + } + } + /* Avoid recursion for some other cases that can't return a set */ + if (IsA(node, Aggref)) + return false; + if (IsA(node, SubLink)) + return false; + return expression_tree_walker(node, expression_returns_set_walker, + context); } /***************************************************************************** @@ -1043,7 +1068,8 @@ CommuteClause(Expr *clause) commu = makeOper(optup->t_data->t_oid, commuTup->oprcode, - commuTup->oprresult); + commuTup->oprresult, + ((Oper *) clause->oper)->opretset); ReleaseSysCache(optup); @@ -1073,8 +1099,7 @@ CommuteClause(Expr *clause) * results even with constant inputs, "nextval()" being the classic * example. Functions that are not marked "immutable" in pg_proc * will not be pre-evaluated here, although we will reduce their - * arguments as far as possible. Functions that are the arguments - * of Iter nodes are also not evaluated. + * arguments as far as possible. * * We assume that the tree has already been type-checked and contains * only operators and functions that are reasonable to try to execute. @@ -1398,37 +1423,6 @@ eval_const_expressions_mutator(Node *node, void *context) newcase->defresult = defresult; return (Node *) newcase; } - if (IsA(node, Iter)) - { - /* - * The argument of an Iter is normally a function call. We must - * not try to eliminate the function, but we can try to simplify - * its arguments. If, by chance, the arg is NOT a function then - * we go ahead and try to simplify it (by falling into - * expression_tree_mutator). Is that the right thing? - */ - Iter *iter = (Iter *) node; - - if (is_funcclause(iter->iterexpr)) - { - Expr *func = (Expr *) iter->iterexpr; - Expr *newfunc; - Iter *newiter; - - newfunc = makeNode(Expr); - newfunc->typeOid = func->typeOid; - newfunc->opType = func->opType; - newfunc->oper = func->oper; - newfunc->args = (List *) - expression_tree_mutator((Node *) func->args, - eval_const_expressions_mutator, - (void *) context); - newiter = makeNode(Iter); - newiter->iterexpr = (Node *) newfunc; - newiter->itertype = iter->itertype; - return (Node *) newiter; - } - } /* * For any node type not handled above, we recurse using @@ -1501,8 +1495,9 @@ simplify_op_or_func(Expr *expr, List *args) * Get the function procedure's OID and look to see whether it is * marked immutable. * - * XXX would it be better to take the result type from the pg_proc tuple, - * rather than the Oper or Func node? + * Note we take the result type from the Oper or Func node, not the + * pg_proc tuple; probably necessary for binary-compatibility cases. + * */ if (expr->opType == OP_EXPR) { @@ -1517,7 +1512,7 @@ simplify_op_or_func(Expr *expr, List *args) Func *func = (Func *) expr->oper; funcid = func->funcid; - result_typeid = func->functype; + result_typeid = func->funcresulttype; } /* @@ -1747,8 +1742,6 @@ expression_tree_walker(Node *node, break; case T_Aggref: return walker(((Aggref *) node)->target, context); - case T_Iter: - return walker(((Iter *) node)->iterexpr, context); case T_ArrayRef: { ArrayRef *aref = (ArrayRef *) node; @@ -2083,16 +2076,6 @@ expression_tree_mutator(Node *node, return (Node *) newnode; } break; - case T_Iter: - { - Iter *iter = (Iter *) node; - Iter *newnode; - - FLATCOPY(newnode, iter, Iter); - MUTATE(newnode->iterexpr, iter->iterexpr, Node *); - return (Node *) newnode; - } - break; case T_ArrayRef: { ArrayRef *arrayref = (ArrayRef *) node; |