aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/clausesel.c23
-rw-r--r--src/backend/optimizer/plan/planner.c18
-rw-r--r--src/backend/optimizer/util/clauses.c160
3 files changed, 159 insertions, 42 deletions
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index e736c6e309e..996c98cc469 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.67 2004/05/30 23:40:28 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.68 2004/06/11 01:08:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -487,16 +487,27 @@ clause_selectivity(Query *root,
}
}
}
- else if (IsA(clause, Param))
- {
- /* XXX any way to do better? */
- s1 = 1.0;
- }
else if (IsA(clause, Const))
{
/* bool constant is pretty easy... */
s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
}
+ else if (IsA(clause, Param))
+ {
+ /* see if we can replace the Param */
+ Node *subst = estimate_expression_value(clause);
+
+ if (IsA(subst, Const))
+ {
+ /* bool constant is pretty easy... */
+ s1 = ((bool) ((Const *) subst)->constvalue) ? 1.0 : 0.0;
+ }
+ else
+ {
+ /* XXX any way to do better? */
+ s1 = (Selectivity) 0.5;
+ }
+ }
else if (not_clause(clause))
{
/* inverse of the selectivity of the underlying clause */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 064981b5af0..2fc82556c32 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.171 2004/05/30 23:40:29 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.172 2004/06/11 01:08:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,6 +43,9 @@
#include "utils/syscache.h"
+ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
+
+
/* Expression kind codes for preprocess_expression */
#define EXPRKIND_QUAL 0
#define EXPRKIND_TARGET 1
@@ -71,20 +74,24 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
*
*****************************************************************************/
Plan *
-planner(Query *parse, bool isCursor, int cursorOptions)
+planner(Query *parse, bool isCursor, int cursorOptions,
+ ParamListInfo boundParams)
{
double tuple_fraction;
Plan *result_plan;
Index save_PlannerQueryLevel;
List *save_PlannerParamList;
+ ParamListInfo save_PlannerBoundParamList;
/*
* The planner can be called recursively (an example is when
* eval_const_expressions tries to pre-evaluate an SQL function). So,
* these global state variables must be saved and restored.
*
- * These vars cannot be moved into the Query structure since their whole
- * purpose is communication across multiple sub-Queries.
+ * Query level and the param list cannot be moved into the Query structure
+ * since their whole purpose is communication across multiple sub-Queries.
+ * Also, boundParams is explicitly info from outside the Query, and so
+ * is likewise better handled as a global variable.
*
* 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
@@ -93,10 +100,12 @@ planner(Query *parse, bool isCursor, int cursorOptions)
*/
save_PlannerQueryLevel = PlannerQueryLevel;
save_PlannerParamList = PlannerParamList;
+ save_PlannerBoundParamList = PlannerBoundParamList;
/* Initialize state for handling outer-level references and params */
PlannerQueryLevel = 0; /* will be 1 in top-level subquery_planner */
PlannerParamList = NIL;
+ PlannerBoundParamList = boundParams;
/* Determine what fraction of the plan is likely to be scanned */
if (isCursor)
@@ -139,6 +148,7 @@ planner(Query *parse, bool isCursor, int cursorOptions)
/* restore state for outer planner, if any */
PlannerQueryLevel = save_PlannerQueryLevel;
PlannerParamList = save_PlannerParamList;
+ PlannerBoundParamList = save_PlannerBoundParamList;
return result_plan;
}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a3a2ddfbd83..e7088d2b761 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.175 2004/06/09 19:08:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.176 2004/06/11 01:08:54 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -28,6 +28,7 @@
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/planmain.h"
+#include "optimizer/planner.h"
#include "optimizer/var.h"
#include "parser/analyze.h"
#include "parser/parse_clause.h"
@@ -43,6 +44,12 @@
typedef struct
{
+ List *active_fns;
+ bool estimate;
+} eval_const_expressions_context;
+
+typedef struct
+{
int nargs;
List *args;
int *usecounts;
@@ -57,17 +64,20 @@ 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 bool set_coercionform_dontcare_walker(Node *node, void *context);
-static Node *eval_const_expressions_mutator(Node *node, List *active_fns);
+static Node *eval_const_expressions_mutator(Node *node,
+ eval_const_expressions_context *context);
static List *simplify_or_arguments(List *args,
bool *haveNull, bool *forceTrue);
static List *simplify_and_arguments(List *args,
bool *haveNull, bool *forceFalse);
static Expr *simplify_function(Oid funcid, Oid result_type, List *args,
- bool allow_inline, List *active_fns);
+ bool allow_inline,
+ eval_const_expressions_context *context);
static Expr *evaluate_function(Oid funcid, Oid result_type, List *args,
HeapTuple func_tuple);
static Expr *inline_function(Oid funcid, Oid result_type, List *args,
- HeapTuple func_tuple, List *active_fns);
+ HeapTuple func_tuple,
+ eval_const_expressions_context *context);
static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
int *usecounts);
static Node *substitute_actual_parameters_mutator(Node *node,
@@ -1070,18 +1080,101 @@ set_coercionform_dontcare_walker(Node *node, void *context)
Node *
eval_const_expressions(Node *node)
{
- /*
- * The context for the mutator is a list of SQL functions being
- * recursively simplified, so we start with an empty list.
- */
- return eval_const_expressions_mutator(node, NIL);
+ eval_const_expressions_context context;
+
+ context.active_fns = NIL; /* nothing being recursively simplified */
+ context.estimate = false; /* safe transformations only */
+ return eval_const_expressions_mutator(node, &context);
+}
+
+/*
+ * estimate_expression_value
+ *
+ * This function attempts to estimate the value of an expression for
+ * planning purposes. It is in essence a more aggressive version of
+ * eval_const_expressions(): we will perform constant reductions that are
+ * not necessarily 100% safe, but are reasonable for estimation purposes.
+ *
+ * Currently the only such transform is to substitute values for Params,
+ * when a bound Param value has been made available by the caller of planner().
+ * In future we might consider other things, such as reducing now() to current
+ * time. (XXX seems like there could be a lot of scope for ideas here...
+ * but we might need more volatility classifications ...)
+ */
+Node *
+estimate_expression_value(Node *node)
+{
+ eval_const_expressions_context context;
+
+ context.active_fns = NIL; /* nothing being recursively simplified */
+ context.estimate = true; /* unsafe transformations OK */
+ return eval_const_expressions_mutator(node, &context);
}
static Node *
-eval_const_expressions_mutator(Node *node, List *active_fns)
+eval_const_expressions_mutator(Node *node,
+ eval_const_expressions_context *context)
{
if (node == NULL)
return NULL;
+ if (IsA(node, Param))
+ {
+ Param *param = (Param *) node;
+ int thisParamKind = param->paramkind;
+
+ /* OK to try to substitute value? */
+ if (context->estimate && thisParamKind != PARAM_EXEC &&
+ PlannerBoundParamList != NULL)
+ {
+ ParamListInfo paramList = PlannerBoundParamList;
+ bool matchFound = false;
+
+ /* Search to see if we've been given a value for this Param */
+ while (paramList->kind != PARAM_INVALID && !matchFound)
+ {
+ if (thisParamKind == paramList->kind)
+ {
+ switch (thisParamKind)
+ {
+ case PARAM_NAMED:
+ if (strcmp(paramList->name, param->paramname) == 0)
+ matchFound = true;
+ break;
+ case PARAM_NUM:
+ if (paramList->id == param->paramid)
+ matchFound = true;
+ break;
+ default:
+ elog(ERROR, "unrecognized paramkind: %d",
+ thisParamKind);
+ }
+ }
+ if (!matchFound)
+ paramList++;
+ }
+ if (matchFound)
+ {
+ /*
+ * Found it, so return a Const representing the param value.
+ * Note that we don't copy pass-by-ref datatypes, so the
+ * Const will only be valid as long as the bound parameter
+ * list exists. This is okay for intended uses of
+ * estimate_expression_value().
+ */
+ int16 typLen;
+ bool typByVal;
+
+ get_typlenbyval(param->paramtype, &typLen, &typByVal);
+ return (Node *) makeConst(param->paramtype,
+ (int) typLen,
+ paramList->value,
+ paramList->isnull,
+ typByVal);
+ }
+ }
+ /* Not replaceable, so just copy the Param (no need to recurse) */
+ return (Node *) copyObject(param);
+ }
if (IsA(node, FuncExpr))
{
FuncExpr *expr = (FuncExpr *) node;
@@ -1096,14 +1189,14 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
/*
* Code for op/func reduction is pretty bulky, so split it out as
* a separate function.
*/
simple = simplify_function(expr->funcid, expr->funcresulttype, args,
- true, active_fns);
+ true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
@@ -1134,7 +1227,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
/*
* Need to get OID of underlying function. Okay to scribble on
@@ -1147,7 +1240,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype, args,
- true, active_fns);
+ true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
@@ -1182,7 +1275,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
/*
* We must do our own check for NULLs because DistinctExpr has
@@ -1226,7 +1319,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* as a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype,
- args, false, active_fns);
+ args, false, context);
if (simple) /* successfully simplified it */
{
/*
@@ -1267,7 +1360,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
switch (expr->boolop)
{
@@ -1360,7 +1453,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
Node *arg;
arg = eval_const_expressions_mutator((Node *) relabel->arg,
- active_fns);
+ context);
/*
* If we find stacked RelabelTypes (eg, from foo :: int :: oid) we
@@ -1424,7 +1517,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
/* Simplify the test expression, if any */
newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
- active_fns);
+ context);
/* Simplify the WHEN clauses */
newargs = NIL;
@@ -1434,7 +1527,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
CaseWhen *casewhen = (CaseWhen *)
expression_tree_mutator((Node *) lfirst(arg),
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
Assert(IsA(casewhen, CaseWhen));
if (casewhen->expr == NULL ||
@@ -1464,7 +1557,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
/* Simplify the default result */
defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,
- active_fns);
+ context);
/*
* If no non-FALSE alternatives, CASE reduces to the default
@@ -1494,7 +1587,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(element),
- active_fns);
+ context);
if (!IsA(e, Const))
all_const = false;
newelems = lappend(newelems, e);
@@ -1525,7 +1618,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(arg),
- active_fns);
+ context);
/*
* We can remove null constants from the list. For a non-null
@@ -1561,7 +1654,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
Node *arg;
arg = eval_const_expressions_mutator((Node *) fselect->arg,
- active_fns);
+ context);
if (arg && IsA(arg, Var) &&
((Var *) arg)->varattno == InvalidAttrNumber)
{
@@ -1595,7 +1688,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* simplify constant expressions in its subscripts.
*/
return expression_tree_mutator(node, eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
}
/*
@@ -1726,14 +1819,15 @@ simplify_and_arguments(List *args, bool *haveNull, bool *forceFalse)
*
* Inputs are the function OID, actual result type OID (which is needed for
* polymorphic functions), and the pre-simplified argument list;
- * also a list of already-active inline function expansions.
+ * also the context data for eval_const_expressions.
*
* Returns a simplified expression if successful, or NULL if cannot
* simplify the function call.
*/
static Expr *
simplify_function(Oid funcid, Oid result_type, List *args,
- bool allow_inline, List *active_fns)
+ bool allow_inline,
+ eval_const_expressions_context *context)
{
HeapTuple func_tuple;
Expr *newexpr;
@@ -1756,7 +1850,7 @@ simplify_function(Oid funcid, Oid result_type, List *args,
if (!newexpr && allow_inline)
newexpr = inline_function(funcid, result_type, args,
- func_tuple, active_fns);
+ func_tuple, context);
ReleaseSysCache(func_tuple);
@@ -1860,7 +1954,8 @@ evaluate_function(Oid funcid, Oid result_type, List *args,
*/
static Expr *
inline_function(Oid funcid, Oid result_type, List *args,
- HeapTuple func_tuple, List *active_fns)
+ HeapTuple func_tuple,
+ eval_const_expressions_context *context)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
bool polymorphic = false;
@@ -1890,7 +1985,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
return NULL;
/* Check for recursive function, and give up trying to expand if so */
- if (list_member_oid(active_fns, funcid))
+ if (list_member_oid(context->active_fns, funcid))
return NULL;
/* Check permission to call function (fail later, if not) */
@@ -2083,8 +2178,9 @@ inline_function(Oid funcid, Oid result_type, List *args,
* Recursively try to simplify the modified expression. Here we must
* add the current function to the context list of active functions.
*/
- newexpr = eval_const_expressions_mutator(newexpr,
- lcons_oid(funcid, active_fns));
+ context->active_fns = lcons_oid(funcid, context->active_fns);
+ newexpr = eval_const_expressions_mutator(newexpr, context);
+ context->active_fns = list_delete_first(context->active_fns);
error_context_stack = sqlerrcontext.previous;