aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r--src/backend/optimizer/plan/createplan.c114
-rw-r--r--src/backend/optimizer/plan/planner.c92
-rw-r--r--src/backend/optimizer/plan/subselect.c41
3 files changed, 176 insertions, 71 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 8f1d8e81cc4..9a8204392a1 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.220 2007/01/09 02:14:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.221 2007/01/10 18:06:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -113,7 +113,10 @@ static HashJoin *make_hashjoin(List *tlist,
static Hash *make_hash(Plan *lefttree);
static MergeJoin *make_mergejoin(List *tlist,
List *joinclauses, List *otherclauses,
- List *mergeclauses, List *mergefamilies, List *mergestrategies,
+ List *mergeclauses,
+ Oid *mergefamilies,
+ int *mergestrategies,
+ bool *mergenullsfirst,
Plan *lefttree, Plan *righttree,
JoinType jointype);
static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
@@ -595,6 +598,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
Plan *plan;
Plan *subplan;
List *uniq_exprs;
+ List *in_operators;
List *newtlist;
int nextresno;
bool newitems;
@@ -626,10 +630,12 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
* To find the correct list of values to unique-ify, we look in the
* information saved for IN expressions. If this code is ever used in
* other scenarios, some other way of finding what to unique-ify will
- * be needed.
+ * be needed. The IN clause's operators are needed too, since they
+ * determine what the meaning of "unique" is in this context.
*----------
*/
uniq_exprs = NIL; /* just to keep compiler quiet */
+ in_operators = NIL;
foreach(l, root->in_info_list)
{
InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);
@@ -637,6 +643,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
if (bms_equal(ininfo->righthand, best_path->path.parent->relids))
{
uniq_exprs = ininfo->sub_targetlist;
+ in_operators = ininfo->in_operators;
break;
}
}
@@ -687,8 +694,8 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
newtlist = subplan->targetlist;
numGroupCols = list_length(uniq_exprs);
groupColIdx = (AttrNumber *) palloc(numGroupCols * sizeof(AttrNumber));
- groupColPos = 0;
+ groupColPos = 0;
foreach(l, uniq_exprs)
{
Node *uniqexpr = lfirst(l);
@@ -703,10 +710,31 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
if (best_path->umethod == UNIQUE_PATH_HASH)
{
long numGroups;
+ Oid *groupOperators;
numGroups = (long) Min(best_path->rows, (double) LONG_MAX);
/*
+ * Get the (presumed hashable) equality operators for the Agg node
+ * to use. Normally these are the same as the IN clause operators,
+ * but if those are cross-type operators then the equality operators
+ * are the ones for the IN clause operators' RHS datatype.
+ */
+ groupOperators = (Oid *) palloc(numGroupCols * sizeof(Oid));
+ groupColPos = 0;
+ foreach(l, in_operators)
+ {
+ Oid in_oper = lfirst_oid(l);
+ Oid eq_oper;
+
+ eq_oper = get_compatible_hash_operator(in_oper, false);
+ if (!OidIsValid(eq_oper)) /* shouldn't happen */
+ elog(ERROR, "could not find compatible hash operator for operator %u",
+ in_oper);
+ groupOperators[groupColPos++] = eq_oper;
+ }
+
+ /*
* Since the Agg node is going to project anyway, we can give it the
* minimum output tlist, without any stuff we might have added to the
* subplan tlist.
@@ -717,6 +745,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
AGG_HASHED,
numGroupCols,
groupColIdx,
+ groupOperators,
numGroups,
0,
subplan);
@@ -725,18 +754,29 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
{
List *sortList = NIL;
- for (groupColPos = 0; groupColPos < numGroupCols; groupColPos++)
+ /* Create an ORDER BY list to sort the input compatibly */
+ groupColPos = 0;
+ foreach(l, in_operators)
{
+ Oid in_oper = lfirst_oid(l);
+ Oid sortop;
TargetEntry *tle;
+ SortClause *sortcl;
+ sortop = get_ordering_op_for_equality_op(in_oper, false);
+ if (!OidIsValid(sortop)) /* shouldn't happen */
+ elog(ERROR, "could not find ordering operator for equality operator %u",
+ in_oper);
tle = get_tle_by_resno(subplan->targetlist,
groupColIdx[groupColPos]);
Assert(tle != NULL);
- sortList = addTargetToSortList(NULL, tle,
- sortList, subplan->targetlist,
- SORTBY_DEFAULT,
- SORTBY_NULLS_DEFAULT,
- NIL, false);
+ sortcl = makeNode(SortClause);
+ sortcl->tleSortGroupRef = assignSortGroupRef(tle,
+ subplan->targetlist);
+ sortcl->sortop = sortop;
+ sortcl->nulls_first = false;
+ sortList = lappend(sortList, sortcl);
+ groupColPos++;
}
plan = (Plan *) make_sort_from_sortclauses(root, sortList, subplan);
plan = (Plan *) make_unique(plan, sortList);
@@ -1542,8 +1582,9 @@ create_mergejoin_plan(PlannerInfo *root,
joinclauses,
otherclauses,
mergeclauses,
- best_path->path_mergefamilies,
- best_path->path_mergestrategies,
+ best_path->path_mergeFamilies,
+ best_path->path_mergeStrategies,
+ best_path->path_mergeNullsFirst,
outer_plan,
inner_plan,
best_path->jpath.jointype);
@@ -2335,8 +2376,9 @@ make_mergejoin(List *tlist,
List *joinclauses,
List *otherclauses,
List *mergeclauses,
- List *mergefamilies,
- List *mergestrategies,
+ Oid *mergefamilies,
+ int *mergestrategies,
+ bool *mergenullsfirst,
Plan *lefttree,
Plan *righttree,
JoinType jointype)
@@ -2350,8 +2392,9 @@ make_mergejoin(List *tlist,
plan->lefttree = lefttree;
plan->righttree = righttree;
node->mergeclauses = mergeclauses;
- node->mergefamilies = mergefamilies;
- node->mergestrategies = mergestrategies;
+ node->mergeFamilies = mergefamilies;
+ node->mergeStrategies = mergestrategies;
+ node->mergeNullsFirst = mergenullsfirst;
node->join.jointype = jointype;
node->join.joinqual = joinclauses;
@@ -2613,7 +2656,7 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
* This might look like it could be merged with make_sort_from_sortclauses,
* but presently we *must* use the grpColIdx[] array to locate sort columns,
* because the child plan's tlist is not marked with ressortgroupref info
- * appropriate to the grouping node. So, only the sort direction info
+ * appropriate to the grouping node. So, only the sort ordering info
* is used from the GroupClause entries.
*/
Sort *
@@ -2716,7 +2759,7 @@ materialize_finished_plan(Plan *subplan)
Agg *
make_agg(PlannerInfo *root, List *tlist, List *qual,
AggStrategy aggstrategy,
- int numGroupCols, AttrNumber *grpColIdx,
+ int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators,
long numGroups, int numAggs,
Plan *lefttree)
{
@@ -2728,6 +2771,7 @@ make_agg(PlannerInfo *root, List *tlist, List *qual,
node->aggstrategy = aggstrategy;
node->numCols = numGroupCols;
node->grpColIdx = grpColIdx;
+ node->grpOperators = grpOperators;
node->numGroups = numGroups;
copy_plan_costsize(plan, lefttree); /* only care about copying size */
@@ -2784,6 +2828,7 @@ make_group(PlannerInfo *root,
List *qual,
int numGroupCols,
AttrNumber *grpColIdx,
+ Oid *grpOperators,
double numGroups,
Plan *lefttree)
{
@@ -2794,6 +2839,7 @@ make_group(PlannerInfo *root,
node->numCols = numGroupCols;
node->grpColIdx = grpColIdx;
+ node->grpOperators = grpOperators;
copy_plan_costsize(plan, lefttree); /* only care about copying size */
cost_group(&group_path, root,
@@ -2841,7 +2887,8 @@ make_group(PlannerInfo *root,
/*
* distinctList is a list of SortClauses, identifying the targetlist items
- * that should be considered by the Unique filter.
+ * that should be considered by the Unique filter. The input path must
+ * already be sorted accordingly.
*/
Unique *
make_unique(Plan *lefttree, List *distinctList)
@@ -2851,6 +2898,7 @@ make_unique(Plan *lefttree, List *distinctList)
int numCols = list_length(distinctList);
int keyno = 0;
AttrNumber *uniqColIdx;
+ Oid *uniqOperators;
ListCell *slitem;
copy_plan_costsize(plan, lefttree);
@@ -2874,28 +2922,37 @@ make_unique(Plan *lefttree, List *distinctList)
plan->righttree = NULL;
/*
- * convert SortClause list into array of attr indexes, as wanted by exec
+ * convert SortClause list into arrays of attr indexes and equality
+ * operators, as wanted by executor
*/
Assert(numCols > 0);
uniqColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
+ uniqOperators = (Oid *) palloc(sizeof(Oid) * numCols);
foreach(slitem, distinctList)
{
SortClause *sortcl = (SortClause *) lfirst(slitem);
TargetEntry *tle = get_sortgroupclause_tle(sortcl, plan->targetlist);
- uniqColIdx[keyno++] = tle->resno;
+ uniqColIdx[keyno] = tle->resno;
+ uniqOperators[keyno] = get_equality_op_for_ordering_op(sortcl->sortop);
+ if (!OidIsValid(uniqOperators[keyno])) /* shouldn't happen */
+ elog(ERROR, "could not find equality operator for ordering operator %u",
+ sortcl->sortop);
+ keyno++;
}
node->numCols = numCols;
node->uniqColIdx = uniqColIdx;
+ node->uniqOperators = uniqOperators;
return node;
}
/*
* distinctList is a list of SortClauses, identifying the targetlist items
- * that should be considered by the SetOp filter.
+ * that should be considered by the SetOp filter. The input path must
+ * already be sorted accordingly.
*/
SetOp *
make_setop(SetOpCmd cmd, Plan *lefttree,
@@ -2906,6 +2963,7 @@ make_setop(SetOpCmd cmd, Plan *lefttree,
int numCols = list_length(distinctList);
int keyno = 0;
AttrNumber *dupColIdx;
+ Oid *dupOperators;
ListCell *slitem;
copy_plan_costsize(plan, lefttree);
@@ -2930,22 +2988,30 @@ make_setop(SetOpCmd cmd, Plan *lefttree,
plan->righttree = NULL;
/*
- * convert SortClause list into array of attr indexes, as wanted by exec
+ * convert SortClause list into arrays of attr indexes and equality
+ * operators, as wanted by executor
*/
Assert(numCols > 0);
dupColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
+ dupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
foreach(slitem, distinctList)
{
SortClause *sortcl = (SortClause *) lfirst(slitem);
TargetEntry *tle = get_sortgroupclause_tle(sortcl, plan->targetlist);
- dupColIdx[keyno++] = tle->resno;
+ dupColIdx[keyno] = tle->resno;
+ dupOperators[keyno] = get_equality_op_for_ordering_op(sortcl->sortop);
+ if (!OidIsValid(dupOperators[keyno])) /* shouldn't happen */
+ elog(ERROR, "could not find equality operator for ordering operator %u",
+ sortcl->sortop);
+ keyno++;
}
node->cmd = cmd;
node->numCols = numCols;
node->dupColIdx = dupColIdx;
+ node->dupOperators = dupOperators;
node->flagColIdx = flagColIdx;
return node;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a4de2dd36a5..5fcfc58bf9b 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.210 2007/01/05 22:19:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.211 2007/01/10 18:06:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,6 +38,7 @@
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parsetree.h"
+#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -62,10 +63,11 @@ static bool is_dummy_plan(Plan *plan);
static double preprocess_limit(PlannerInfo *root,
double tuple_fraction,
int64 *offset_est, int64 *count_est);
+static Oid *extract_grouping_ops(List *groupClause);
static bool choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
Path *cheapest_path, Path *sorted_path,
- double dNumGroups, AggClauseCounts *agg_counts);
-static bool hash_safe_grouping(PlannerInfo *root);
+ Oid *groupOperators, double dNumGroups,
+ AggClauseCounts *agg_counts);
static List *make_subplanTargetList(PlannerInfo *root, List *tlist,
AttrNumber **groupColIdx, bool *need_tlist_eval);
static void locate_grouping_columns(PlannerInfo *root,
@@ -750,6 +752,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
List *sub_tlist;
List *group_pathkeys;
AttrNumber *groupColIdx = NULL;
+ Oid *groupOperators = NULL;
bool need_tlist_eval = true;
QualCost tlist_cost;
Path *cheapest_path;
@@ -829,14 +832,17 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
sort_pathkeys = root->sort_pathkeys;
/*
- * If grouping, decide whether we want to use hashed grouping.
+ * If grouping, extract the grouping operators and decide whether we
+ * want to use hashed grouping.
*/
if (parse->groupClause)
{
+ groupOperators = extract_grouping_ops(parse->groupClause);
use_hashed_grouping =
choose_hashed_grouping(root, tuple_fraction,
cheapest_path, sorted_path,
- dNumGroups, &agg_counts);
+ groupOperators, dNumGroups,
+ &agg_counts);
/* Also convert # groups to long int --- but 'ware overflow! */
numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
@@ -956,6 +962,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
AGG_HASHED,
numGroupCols,
groupColIdx,
+ groupOperators,
numGroups,
agg_counts.numAggs,
result_plan);
@@ -999,6 +1006,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
aggstrategy,
numGroupCols,
groupColIdx,
+ groupOperators,
numGroups,
agg_counts.numAggs,
result_plan);
@@ -1027,6 +1035,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
(List *) parse->havingQual,
numGroupCols,
groupColIdx,
+ groupOperators,
dNumGroups,
result_plan);
/* The Group node won't change sort ordering */
@@ -1338,12 +1347,41 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
}
/*
+ * extract_grouping_ops - make an array of the equality operator OIDs
+ * for the GROUP BY clause
+ */
+static Oid *
+extract_grouping_ops(List *groupClause)
+{
+ int numCols = list_length(groupClause);
+ int colno = 0;
+ Oid *groupOperators;
+ ListCell *glitem;
+
+ groupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
+
+ foreach(glitem, groupClause)
+ {
+ GroupClause *groupcl = (GroupClause *) lfirst(glitem);
+
+ groupOperators[colno] = get_equality_op_for_ordering_op(groupcl->sortop);
+ if (!OidIsValid(groupOperators[colno])) /* shouldn't happen */
+ elog(ERROR, "could not find equality operator for ordering operator %u",
+ groupcl->sortop);
+ colno++;
+ }
+
+ return groupOperators;
+}
+
+/*
* choose_hashed_grouping - should we use hashed grouping?
*/
static bool
choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
Path *cheapest_path, Path *sorted_path,
- double dNumGroups, AggClauseCounts *agg_counts)
+ Oid *groupOperators, double dNumGroups,
+ AggClauseCounts *agg_counts)
{
int numGroupCols = list_length(root->parse->groupClause);
double cheapest_path_rows;
@@ -1352,10 +1390,13 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
List *current_pathkeys;
Path hashed_p;
Path sorted_p;
+ int i;
/*
* Check can't-do-it conditions, including whether the grouping operators
- * are hashjoinable.
+ * are hashjoinable. (We assume hashing is OK if they are marked
+ * oprcanhash. If there isn't actually a supporting hash function,
+ * the executor will complain at runtime.)
*
* Executor doesn't support hashed aggregation with DISTINCT aggregates.
* (Doing so would imply storing *all* the input values in the hash table,
@@ -1365,8 +1406,11 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
return false;
if (agg_counts->numDistinctAggs != 0)
return false;
- if (!hash_safe_grouping(root))
- return false;
+ for (i = 0; i < numGroupCols; i++)
+ {
+ if (!op_hashjoinable(groupOperators[i]))
+ return false;
+ }
/*
* Don't do it if it doesn't look like the hashtable will fit into
@@ -1471,36 +1515,6 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
return false;
}
-/*
- * hash_safe_grouping - are grouping operators hashable?
- *
- * We assume hashed aggregation will work if the datatype's equality operator
- * is marked hashjoinable.
- */
-static bool
-hash_safe_grouping(PlannerInfo *root)
-{
- ListCell *gl;
-
- foreach(gl, root->parse->groupClause)
- {
- GroupClause *grpcl = (GroupClause *) lfirst(gl);
- TargetEntry *tle = get_sortgroupclause_tle(grpcl,
- root->parse->targetList);
- Operator optup;
- bool oprcanhash;
-
- optup = equality_oper(exprType((Node *) tle->expr), true);
- if (!optup)
- return false;
- oprcanhash = ((Form_pg_operator) GETSTRUCT(optup))->oprcanhash;
- ReleaseSysCache(optup);
- if (!oprcanhash)
- return false;
- }
- return true;
-}
-
/*---------------
* make_subplanTargetList
* Generate appropriate target list when grouping is required.
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index ed76612dc0a..7339445e046 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
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.116 2007/01/05 22:19:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.117 2007/01/10 18:06:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -671,11 +671,13 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
{
Query *parse = root->parse;
Query *subselect = (Query *) sublink->subselect;
+ List *in_operators;
Relids left_varnos;
int rtindex;
RangeTblEntry *rte;
RangeTblRef *rtr;
InClauseInfo *ininfo;
+ Node *result;
/*
* The sublink type must be "= ANY" --- that is, an IN operator. We
@@ -689,15 +691,31 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
return NULL;
if (sublink->testexpr && IsA(sublink->testexpr, OpExpr))
{
+ Oid opno = ((OpExpr *) sublink->testexpr)->opno;
List *opfamilies;
List *opstrats;
- get_op_btree_interpretation(((OpExpr *) sublink->testexpr)->opno,
- &opfamilies, &opstrats);
+ get_op_btree_interpretation(opno, &opfamilies, &opstrats);
if (!list_member_int(opstrats, ROWCOMPARE_EQ))
return NULL;
+ in_operators = list_make1_oid(opno);
+ }
+ else if (and_clause(sublink->testexpr))
+ {
+ ListCell *lc;
+
+ /* OK, but we need to extract the per-column operator OIDs */
+ in_operators = NIL;
+ foreach(lc, ((BoolExpr *) sublink->testexpr)->args)
+ {
+ OpExpr *op = (OpExpr *) lfirst(lc);
+
+ if (!IsA(op, OpExpr)) /* probably shouldn't happen */
+ return NULL;
+ in_operators = lappend_oid(in_operators, op->opno);
+ }
}
- else if (!and_clause(sublink->testexpr))
+ else
return NULL;
/*
@@ -745,16 +763,23 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
ininfo = makeNode(InClauseInfo);
ininfo->lefthand = left_varnos;
ininfo->righthand = bms_make_singleton(rtindex);
- root->in_info_list = lappend(root->in_info_list, ininfo);
+ ininfo->in_operators = in_operators;
/*
* Build the result qual expression. As a side effect,
* ininfo->sub_targetlist is filled with a list of Vars representing the
* subselect outputs.
*/
- return convert_testexpr(sublink->testexpr,
- rtindex,
- &ininfo->sub_targetlist);
+ result = convert_testexpr(sublink->testexpr,
+ rtindex,
+ &ininfo->sub_targetlist);
+
+ Assert(list_length(in_operators) == list_length(ininfo->sub_targetlist));
+
+ /* Add the completed node to the query's list */
+ root->in_info_list = lappend(root->in_info_list, ininfo);
+
+ return result;
}
/*