summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-04-04 01:21:48 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-04-04 01:21:48 +0000
commit1c72a8a37a446eebb09bcfb5eb6bad7ddd1655c8 (patch)
treea886d5b14699e0a3a271cc2b2ccd5a1e5dff8b2a /src/backend/optimizer/util
parent8cdabf074118ab0c86423891cc0b85c9c94939e7 (diff)
Fix extremely nasty little bug observed when a sub-SELECT appears in
WHERE in a place where it can be part of a nestloop inner indexqual. As the code stood, it put the same physical sub-Plan node into both indxqual and indxqualorig of the IndexScan plan node. That confused later processing in the optimizer (which expected that tracing the subPlan list would visit each subplan node exactly once), and would probably have blown up in the executor if the planner hadn't choked first. Fix by making the 'fixed' indexqual be a complete deep copy of the original indexqual, rather than trying to share nodes below the topmost operator node. This had further ramifications though, because we were making the aforesaid list of sub-Plan nodes during SS_process_sublinks which is run before construction of the 'fixed' indexqual, meaning that the copy of the sub-Plan didn't show up in that list. Fix by rearranging logic so that the sub-Plan list is built by the final set_plan_references pass, not in SS_process_sublinks. This may sound like a mess, but it's actually a good deal cleaner now than it was before, because we are no longer dependent on the assumption that planning will never make a copy of a sub-Plan node.
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/clauses.c136
1 files changed, 103 insertions, 33 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8d4dae486ac..d429db93a03 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.63 2000/03/21 05:12:12 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.64 2000/04/04 01:21:46 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -43,6 +43,8 @@
static bool contain_agg_clause_walker(Node *node, void *context);
static bool pull_agg_clause_walker(Node *node, List **listptr);
+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,
Query *context);
static int is_single_func(Node *node);
@@ -358,39 +360,9 @@ make_ands_implicit(Expr *clause)
/*****************************************************************************
- * *
- * General clause-manipulating routines *
- * *
+ * Aggregate-function clause manipulation
*****************************************************************************/
-
-/*
- * pull_constant_clauses
- * Scans through a list of qualifications and find those that
- * contain no variables (of the current query level).
- *
- * Returns a list of the constant clauses in constantQual and the remaining
- * quals as the return value.
- *
- */
-List *
-pull_constant_clauses(List *quals, List **constantQual)
-{
- List *q;
- List *constqual = NIL;
- List *restqual = NIL;
-
- foreach(q, quals)
- {
- if (!contain_var_clause(lfirst(q)))
- constqual = lcons(lfirst(q), constqual);
- else
- restqual = lcons(lfirst(q), restqual);
- }
- *constantQual = constqual;
- return restqual;
-}
-
/*
* contain_agg_clause
* Recursively search for Aggref nodes within a clause.
@@ -454,6 +426,68 @@ pull_agg_clause_walker(Node *node, List **listptr)
(void *) listptr);
}
+
+/*****************************************************************************
+ * Subplan clause manipulation
+ *****************************************************************************/
+
+/*
+ * contain_subplans
+ * Recursively search for subplan nodes within a clause.
+ *
+ * If we see a SubLink node, we will return TRUE. This is only possible if
+ * the expression tree hasn't yet been transformed by subselect.c. We do not
+ * know whether the node will produce a true subplan or just an initplan,
+ * but we make the conservative assumption that it will be a subplan.
+ *
+ * Returns true if any subplan found.
+ */
+bool
+contain_subplans(Node *clause)
+{
+ return contain_subplans_walker(clause, NULL);
+}
+
+static bool
+contain_subplans_walker(Node *node, void *context)
+{
+ if (node == NULL)
+ return false;
+ if (is_subplan(node) || IsA(node, SubLink))
+ return true; /* abort the tree traversal and return true */
+ return expression_tree_walker(node, contain_subplans_walker, 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.
+ */
+List *
+pull_subplans(Node *clause)
+{
+ List *result = NIL;
+
+ pull_subplans_walker(clause, &result);
+ return result;
+}
+
+static bool
+pull_subplans_walker(Node *node, List **listptr)
+{
+ if (node == NULL)
+ return false;
+ if (is_subplan(node))
+ {
+ *listptr = lappend(*listptr, ((Expr *) node)->oper);
+ /* fall through to check args to subplan */
+ }
+ return expression_tree_walker(node, pull_subplans_walker,
+ (void *) listptr);
+}
+
/*
* check_subplans_for_ungrouped_vars
* Check for subplans that are being passed ungrouped variables as
@@ -556,6 +590,41 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
}
+/*****************************************************************************
+ * *
+ * General clause-manipulating routines *
+ * *
+ *****************************************************************************/
+
+
+/*
+ * pull_constant_clauses
+ * Scans through a list of qualifications and find those that
+ * contain no variables (of the current query level).
+ *
+ * Returns a list of the constant clauses in constantQual and the remaining
+ * quals as the return value.
+ *
+ */
+List *
+pull_constant_clauses(List *quals, List **constantQual)
+{
+ List *q;
+ List *constqual = NIL;
+ List *restqual = NIL;
+
+ foreach(q, quals)
+ {
+ if (!contain_var_clause(lfirst(q)))
+ constqual = lcons(lfirst(q), constqual);
+ else
+ restqual = lcons(lfirst(q), restqual);
+ }
+ *constantQual = constqual;
+ return restqual;
+}
+
+
/*
* clause_relids_vars
* Retrieves distinct relids and vars appearing within a clause.
@@ -726,7 +795,8 @@ default_results:
* If the given expression is a function of a single relation,
* return the relation number; else return 0
*/
-static int is_single_func(Node *node)
+static int
+is_single_func(Node *node)
{
if (is_funcclause(node))
{