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.c39
-rw-r--r--src/backend/optimizer/path/indxpath.c241
-rw-r--r--src/backend/optimizer/plan/createplan.c100
-rw-r--r--src/backend/optimizer/plan/planagg.c3
-rw-r--r--src/backend/optimizer/util/restrictinfo.c4
5 files changed, 283 insertions, 104 deletions
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index 9a4990898e9..eba6bf1d148 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.75 2005/10/15 02:49:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.76 2005/11/25 19:47:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -624,12 +624,45 @@ clause_selectivity(PlannerInfo *root,
*/
s1 = (Selectivity) 0.5;
}
- else if (IsA(clause, DistinctExpr) ||
- IsA(clause, ScalarArrayOpExpr))
+ else if (IsA(clause, DistinctExpr))
{
/* can we do better? */
s1 = (Selectivity) 0.5;
}
+ else if (IsA(clause, ScalarArrayOpExpr))
+ {
+ /* First, decide if it's a join clause, same as for OpExpr */
+ bool is_join_clause;
+
+ if (varRelid != 0)
+ {
+ /*
+ * If we are considering a nestloop join then all clauses are
+ * restriction clauses, since we are only interested in the one
+ * relation.
+ */
+ is_join_clause = false;
+ }
+ else
+ {
+ /*
+ * Otherwise, it's a join if there's more than one relation used.
+ * We can optimize this calculation if an rinfo was passed.
+ */
+ if (rinfo)
+ is_join_clause = (bms_membership(rinfo->clause_relids) ==
+ BMS_MULTIPLE);
+ else
+ is_join_clause = (NumRelids(clause) > 1);
+ }
+
+ /* Use node specific selectivity calculation function */
+ s1 = scalararraysel(root,
+ (ScalarArrayOpExpr *) clause,
+ is_join_clause,
+ varRelid,
+ jointype);
+ }
else if (IsA(clause, NullTest))
{
/* Use node specific selectivity calculation function */
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 6f3157a23f6..fde89455685 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.193 2005/11/22 18:17:12 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.194 2005/11/25 19:47:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,7 @@
#include "optimizer/paths.h"
#include "optimizer/predtest.h"
#include "optimizer/restrictinfo.h"
+#include "optimizer/var.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -40,9 +41,6 @@
*/
#define DoneMatchingIndexKeys(classes) (classes[0] == InvalidOid)
-#define is_indexable_operator(clause,opclass,indexkey_on_left) \
- (indexable_operator(clause,opclass,indexkey_on_left) != InvalidOid)
-
#define IsBooleanOpclass(opclass) \
((opclass) == BOOL_BTREE_OPS_OID || (opclass) == BOOL_HASH_OPS_OID)
@@ -50,16 +48,18 @@
static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
List *clauses, List *outer_clauses,
bool istoplevel, bool isjoininner,
- Relids outer_relids);
+ Relids outer_relids,
+ SaOpControl saop_control);
static Path *choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths);
static int bitmap_path_comparator(const void *a, const void *b);
static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths);
static bool match_clause_to_indexcol(IndexOptInfo *index,
int indexcol, Oid opclass,
RestrictInfo *rinfo,
- Relids outer_relids);
-static Oid indexable_operator(Expr *clause, Oid opclass,
- bool indexkey_on_left);
+ Relids outer_relids,
+ SaOpControl saop_control);
+static bool is_indexable_operator(Oid expr_op, Oid opclass,
+ bool indexkey_on_left);
static Relids indexable_outerrelids(RelOptInfo *rel);
static bool matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel,
Relids outer_relids);
@@ -150,7 +150,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
*/
indexpaths = find_usable_indexes(root, rel,
rel->baserestrictinfo, NIL,
- true, false, NULL);
+ true, false, NULL, SAOP_FORBID);
/*
* We can submit them all to add_path. (This generates access paths for
@@ -228,6 +228,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
* given clauses are join clauses)
* 'outer_relids' identifies the outer side of the join (pass NULL
* if not isjoininner)
+ * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used
*
* Note: check_partial_indexes() must have been run previously.
*----------
@@ -236,7 +237,8 @@ static List *
find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
List *clauses, List *outer_clauses,
bool istoplevel, bool isjoininner,
- Relids outer_relids)
+ Relids outer_relids,
+ SaOpControl saop_control)
{
List *result = NIL;
List *all_clauses = NIL; /* not computed till needed */
@@ -267,6 +269,10 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
* predOK index to an arm of an OR, which would be a legal but
* pointlessly inefficient plan. (A better plan will be generated by
* just scanning the predOK index alone, no OR.)
+ *
+ * If saop_control is SAOP_REQUIRE and istoplevel is false, the caller
+ * is only interested in indexquals involving ScalarArrayOps, so don't
+ * set useful_predicate to true.
*/
useful_predicate = false;
if (index->indpred != NIL)
@@ -292,7 +298,8 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
if (!predicate_implied_by(index->indpred, all_clauses))
continue; /* can't use it at all */
- if (!predicate_implied_by(index->indpred, outer_clauses))
+ if (saop_control != SAOP_REQUIRE &&
+ !predicate_implied_by(index->indpred, outer_clauses))
useful_predicate = true;
}
}
@@ -300,12 +307,14 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
/*
* 1. Match the index against the available restriction clauses.
* found_clause is set true only if at least one of the current
- * clauses was used.
+ * clauses was used (and, if saop_control is SAOP_REQUIRE, it
+ * has to have been a ScalarArrayOpExpr clause).
*/
restrictclauses = group_clauses_by_indexkey(index,
clauses,
outer_clauses,
outer_relids,
+ saop_control,
&found_clause);
/*
@@ -380,9 +389,9 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
/*
* generate_bitmap_or_paths
- * Look through the list of clauses to find OR clauses, and generate
- * a BitmapOrPath for each one we can handle that way. Return a list
- * of the generated BitmapOrPaths.
+ * Look through the list of clauses to find OR clauses and
+ * ScalarArrayOpExpr clauses, and generate a BitmapOrPath for each one
+ * we can handle that way. Return a list of the generated BitmapOrPaths.
*
* outer_clauses is a list of additional clauses that can be assumed true
* for the purpose of generating indexquals, but are not to be searched for
@@ -396,6 +405,7 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
{
List *result = NIL;
List *all_clauses;
+ bool have_saop = false;
ListCell *l;
/*
@@ -412,9 +422,16 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
ListCell *j;
Assert(IsA(rinfo, RestrictInfo));
- /* Ignore RestrictInfos that aren't ORs */
+ /*
+ * In this loop we ignore RestrictInfos that aren't ORs; but take
+ * note of ScalarArrayOpExpr for later.
+ */
if (!restriction_is_or_clause(rinfo))
+ {
+ if (IsA(rinfo->clause, ScalarArrayOpExpr))
+ have_saop = true;
continue;
+ }
/*
* We must be able to match at least one index to each of the arms of
@@ -436,7 +453,8 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
all_clauses,
false,
isjoininner,
- outer_relids);
+ outer_relids,
+ SAOP_ALLOW);
/* Recurse in case there are sub-ORs */
indlist = list_concat(indlist,
generate_bitmap_or_paths(root, rel,
@@ -454,7 +472,8 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
all_clauses,
false,
isjoininner,
- outer_relids);
+ outer_relids,
+ SAOP_ALLOW);
}
/*
@@ -486,6 +505,29 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
}
}
+ /*
+ * If we saw any top-level ScalarArrayOpExpr clauses, see if we can
+ * generate a bitmap index path that uses those but not any OR clauses.
+ */
+ if (have_saop)
+ {
+ List *pathlist;
+ Path *bitmapqual;
+
+ pathlist = find_usable_indexes(root, rel,
+ clauses,
+ outer_clauses,
+ false,
+ isjoininner,
+ outer_relids,
+ SAOP_REQUIRE);
+ if (pathlist != NIL)
+ {
+ bitmapqual = (Path *) create_bitmap_or_path(root, rel, pathlist);
+ result = lappend(result, bitmapqual);
+ }
+ }
+
return result;
}
@@ -526,7 +568,8 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
*
* We also make some effort to detect directly redundant input paths, as
* can happen if there are multiple possibly usable indexes. For this we
- * look only at plain IndexPath inputs, not at sub-OR clauses. And we
+ * look only at plain IndexPath and single-element BitmapOrPath inputs
+ * (the latter can arise in the presence of ScalarArrayOpExpr quals). We
* consider an index redundant if all its index conditions were already
* used by earlier indexes. (We could use predicate_implied_by to have a
* more intelligent, but much more expensive, check --- but in most cases
@@ -555,10 +598,17 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
paths = list_make1(patharray[0]);
costsofar = bitmap_and_cost_est(root, rel, paths);
+ qualsofar = NIL;
if (IsA(patharray[0], IndexPath))
qualsofar = list_copy(((IndexPath *) patharray[0])->indexclauses);
- else
- qualsofar = NIL;
+ else if (IsA(patharray[0], BitmapOrPath))
+ {
+ List *orquals = ((BitmapOrPath *) patharray[0])->bitmapquals;
+
+ if (list_length(orquals) == 1 &&
+ IsA(linitial(orquals), IndexPath))
+ qualsofar = list_copy(((IndexPath *) linitial(orquals))->indexclauses);
+ }
lastcell = list_head(paths); /* for quick deletions */
for (i = 1; i < npaths; i++)
@@ -573,6 +623,16 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
if (list_difference_ptr(newqual, qualsofar) == NIL)
continue; /* redundant */
}
+ else if (IsA(newpath, BitmapOrPath))
+ {
+ List *orquals = ((BitmapOrPath *) newpath)->bitmapquals;
+
+ if (list_length(orquals) == 1 &&
+ IsA(linitial(orquals), IndexPath))
+ newqual = ((IndexPath *) linitial(orquals))->indexclauses;
+ if (list_difference_ptr(newqual, qualsofar) == NIL)
+ continue; /* redundant */
+ }
paths = lappend(paths, newpath);
newcost = bitmap_and_cost_est(root, rel, paths);
@@ -665,6 +725,10 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
* outer_relids determines what Vars will be allowed on the other side
* of a possible index qual; see match_clause_to_indexcol().
*
+ * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used.
+ * When it's SAOP_REQUIRE, *found_clause is set TRUE only if we used at least
+ * one ScalarArrayOpExpr from the current clauses list.
+ *
* If the index has amoptionalkey = false, we give up and return NIL when
* there are no restriction clauses matching the first index key. Otherwise,
* we return NIL if there are no restriction clauses matching any index key.
@@ -682,6 +746,7 @@ List *
group_clauses_by_indexkey(IndexOptInfo *index,
List *clauses, List *outer_clauses,
Relids outer_relids,
+ SaOpControl saop_control,
bool *found_clause)
{
List *clausegroup_list = NIL;
@@ -710,10 +775,13 @@ group_clauses_by_indexkey(IndexOptInfo *index,
indexcol,
curClass,
rinfo,
- outer_relids))
+ outer_relids,
+ saop_control))
{
clausegroup = list_append_unique_ptr(clausegroup, rinfo);
- *found_clause = true;
+ if (saop_control != SAOP_REQUIRE ||
+ IsA(rinfo->clause, ScalarArrayOpExpr))
+ *found_clause = true;
}
}
@@ -727,7 +795,8 @@ group_clauses_by_indexkey(IndexOptInfo *index,
indexcol,
curClass,
rinfo,
- outer_relids))
+ outer_relids,
+ saop_control))
{
clausegroup = list_append_unique_ptr(clausegroup, rinfo);
found_outer_clause = true;
@@ -785,6 +854,11 @@ group_clauses_by_indexkey(IndexOptInfo *index,
* We do not actually do the commuting here, but we check whether a
* suitable commutator operator is available.
*
+ * It is also possible to match ScalarArrayOpExpr clauses to indexes, when
+ * the clause is of the form "indexkey op ANY (arrayconst)". Since the
+ * executor can only handle these in the context of bitmap index scans,
+ * our caller specifies whether to allow these or not.
+ *
* For boolean indexes, it is also possible to match the clause directly
* to the indexkey; or perhaps the clause is (NOT indexkey).
*
@@ -792,6 +866,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
* 'indexcol' is a column number of 'index' (counting from 0).
* 'opclass' is the corresponding operator class.
* 'rinfo' is the clause to be tested (as a RestrictInfo node).
+ * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used.
*
* Returns true if the clause can be used with this index key.
*
@@ -803,11 +878,16 @@ match_clause_to_indexcol(IndexOptInfo *index,
int indexcol,
Oid opclass,
RestrictInfo *rinfo,
- Relids outer_relids)
+ Relids outer_relids,
+ SaOpControl saop_control)
{
Expr *clause = rinfo->clause;
Node *leftop,
*rightop;
+ Relids left_relids;
+ Relids right_relids;
+ Oid expr_op;
+ bool plain_op;
/* First check for boolean-index cases. */
if (IsBooleanOpclass(opclass))
@@ -816,12 +896,37 @@ match_clause_to_indexcol(IndexOptInfo *index,
return true;
}
- /* Else clause must be a binary opclause. */
- if (!is_opclause(clause))
- return false;
- leftop = get_leftop(clause);
- rightop = get_rightop(clause);
- if (!leftop || !rightop)
+ /*
+ * Clause must be a binary opclause, or possibly a ScalarArrayOpExpr
+ * (which is always binary, by definition).
+ */
+ if (is_opclause(clause))
+ {
+ leftop = get_leftop(clause);
+ rightop = get_rightop(clause);
+ if (!leftop || !rightop)
+ return false;
+ left_relids = rinfo->left_relids;
+ right_relids = rinfo->right_relids;
+ expr_op = ((OpExpr *) clause)->opno;
+ plain_op = true;
+ }
+ else if (saop_control != SAOP_FORBID &&
+ clause && IsA(clause, ScalarArrayOpExpr))
+ {
+ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
+
+ /* We only accept ANY clauses, not ALL */
+ if (!saop->useOr)
+ return false;
+ leftop = (Node *) linitial(saop->args);
+ rightop = (Node *) lsecond(saop->args);
+ left_relids = NULL; /* not actually needed */
+ right_relids = pull_varnos(rightop);
+ expr_op = saop->opno;
+ plain_op = false;
+ }
+ else
return false;
/*
@@ -829,26 +934,28 @@ match_clause_to_indexcol(IndexOptInfo *index,
* (constant operator indexkey). See above notes about const-ness.
*/
if (match_index_to_operand(leftop, indexcol, index) &&
- bms_is_subset(rinfo->right_relids, outer_relids) &&
+ bms_is_subset(right_relids, outer_relids) &&
!contain_volatile_functions(rightop))
{
- if (is_indexable_operator(clause, opclass, true))
+ if (is_indexable_operator(expr_op, opclass, true))
return true;
/*
* If we didn't find a member of the index's opclass, see whether it
* is a "special" indexable operator.
*/
- if (match_special_index_operator(clause, opclass, true))
+ if (plain_op &&
+ match_special_index_operator(clause, opclass, true))
return true;
return false;
}
- if (match_index_to_operand(rightop, indexcol, index) &&
- bms_is_subset(rinfo->left_relids, outer_relids) &&
+ if (plain_op &&
+ match_index_to_operand(rightop, indexcol, index) &&
+ bms_is_subset(left_relids, outer_relids) &&
!contain_volatile_functions(leftop))
{
- if (is_indexable_operator(clause, opclass, false))
+ if (is_indexable_operator(expr_op, opclass, false))
return true;
/*
@@ -864,36 +971,26 @@ match_clause_to_indexcol(IndexOptInfo *index,
}
/*
- * indexable_operator
- * Does a binary opclause contain an operator matching the index opclass?
+ * is_indexable_operator
+ * Does the operator match the specified index opclass?
*
* If the indexkey is on the right, what we actually want to know
* is whether the operator has a commutator operator that matches
- * the index's opclass.
- *
- * Returns the OID of the matching operator, or InvalidOid if no match.
- * (Formerly, this routine might return a binary-compatible operator
- * rather than the original one, but that kluge is history.)
+ * the opclass.
*/
-static Oid
-indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
+static bool
+is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
{
- Oid expr_op = ((OpExpr *) clause)->opno;
- Oid commuted_op;
-
/* Get the commuted operator if necessary */
- if (indexkey_on_left)
- commuted_op = expr_op;
- else
- commuted_op = get_commutator(expr_op);
- if (commuted_op == InvalidOid)
- return InvalidOid;
+ if (!indexkey_on_left)
+ {
+ expr_op = get_commutator(expr_op);
+ if (expr_op == InvalidOid)
+ return false;
+ }
/* OK if the (commuted) operator is a member of the index's opclass */
- if (op_in_opclass(commuted_op, opclass))
- return expr_op;
-
- return InvalidOid;
+ return op_in_opclass(expr_op, opclass);
}
/****************************************************************************
@@ -1031,7 +1128,8 @@ matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids)
indexcol,
curClass,
rinfo,
- outer_relids))
+ outer_relids,
+ SAOP_ALLOW))
return true;
indexcol++;
@@ -1137,16 +1235,17 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
/*
* Find all the index paths that are usable for this join, except for
- * stuff involving OR clauses.
+ * stuff involving OR and ScalarArrayOpExpr clauses.
*/
indexpaths = find_usable_indexes(root, rel,
clause_list, NIL,
false, true,
- outer_relids);
+ outer_relids,
+ SAOP_FORBID);
/*
- * Generate BitmapOrPaths for any suitable OR-clauses present in the
- * clause list.
+ * Generate BitmapOrPaths for any suitable OR-clauses or ScalarArrayOpExpr
+ * clauses present in the clause list.
*/
bitindexpaths = generate_bitmap_or_paths(root, rel,
clause_list, NIL,
@@ -1384,7 +1483,10 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
bool varonleft;
bool ispc;
- /* We know this clause passed match_clause_to_indexcol */
+ /*
+ * We know this clause passed match_clause_to_indexcol as a
+ * toplevel clause; so it's not a ScalarArrayOp.
+ */
/* First check for boolean-index cases. */
if (IsBooleanOpclass(opclass))
@@ -1923,6 +2025,13 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
}
}
+ /* Next check for ScalarArrayOp cases */
+ if (IsA(rinfo->clause, ScalarArrayOpExpr))
+ {
+ resultquals = lappend(resultquals, rinfo);
+ continue;
+ }
+
resultquals = list_concat(resultquals,
expand_indexqual_condition(rinfo,
curClass));
@@ -2001,7 +2110,7 @@ expand_boolean_index_clause(Node *clause,
/*
* expand_indexqual_condition --- expand a single indexqual condition
- * (other than a boolean-qual case)
+ * (other than a boolean-qual or ScalarArrayOp case)
*
* The input is a single RestrictInfo, the output a list of RestrictInfos
*/
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 978419842e3..3bd760fda3a 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.203 2005/11/22 18:17:12 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.204 2005/11/25 19:47:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1069,17 +1069,28 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
subindexquals = lappend(subindexquals,
make_ands_explicit(subindexqual));
}
- plan = (Plan *) make_bitmap_or(subplans);
- plan->startup_cost = opath->path.startup_cost;
- plan->total_cost = opath->path.total_cost;
- plan->plan_rows =
- clamp_row_est(opath->bitmapselectivity * opath->path.parent->tuples);
- plan->plan_width = 0; /* meaningless */
+ /*
+ * In the presence of ScalarArrayOpExpr quals, we might have built
+ * BitmapOrPaths with just one subpath; don't add an OR step.
+ */
+ if (list_length(subplans) == 1)
+ {
+ plan = (Plan *) linitial(subplans);
+ }
+ else
+ {
+ plan = (Plan *) make_bitmap_or(subplans);
+ plan->startup_cost = opath->path.startup_cost;
+ plan->total_cost = opath->path.total_cost;
+ plan->plan_rows =
+ clamp_row_est(opath->bitmapselectivity * opath->path.parent->tuples);
+ plan->plan_width = 0; /* meaningless */
+ }
/*
* If there were constant-TRUE subquals, the OR reduces to constant
* TRUE. Also, avoid generating one-element ORs, which could happen
- * due to redundancy elimination.
+ * due to redundancy elimination or ScalarArrayOpExpr quals.
*/
if (const_true_subqual)
*qual = NIL;
@@ -1531,18 +1542,14 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
foreach(l, indexquals)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
- OpExpr *clause;
- OpExpr *newclause;
+ Expr *clause;
+ Oid clause_op;
Oid opclass;
int stratno;
Oid stratsubtype;
bool recheck;
Assert(IsA(rinfo, RestrictInfo));
- clause = (OpExpr *) rinfo->clause;
- if (!IsA(clause, OpExpr) ||
- list_length(clause->args) != 2)
- elog(ERROR, "indexqual clause is not binary opclause");
/*
* Make a copy that will become the fixed clause.
@@ -1551,33 +1558,62 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
* is a subplan in the arguments of the opclause. So just do a full
* copy.
*/
- newclause = (OpExpr *) copyObject((Node *) clause);
+ clause = (Expr *) copyObject((Node *) rinfo->clause);
- /*
- * Check to see if the indexkey is on the right; if so, commute the
- * clause. The indexkey should be the side that refers to (only) the
- * base relation.
- */
- if (!bms_equal(rinfo->left_relids, index->rel->relids))
- CommuteClause(newclause);
+ if (IsA(clause, OpExpr))
+ {
+ OpExpr *op = (OpExpr *) clause;
- /*
- * Now, determine which index attribute this is, change the indexkey
- * operand as needed, and get the index opclass.
- */
- linitial(newclause->args) =
- fix_indexqual_operand(linitial(newclause->args),
- index,
- &opclass);
+ if (list_length(op->args) != 2)
+ elog(ERROR, "indexqual clause is not binary opclause");
+
+ /*
+ * Check to see if the indexkey is on the right; if so, commute
+ * the clause. The indexkey should be the side that refers to
+ * (only) the base relation.
+ */
+ if (!bms_equal(rinfo->left_relids, index->rel->relids))
+ CommuteClause(op);
+
+ /*
+ * Now, determine which index attribute this is, change the
+ * indexkey operand as needed, and get the index opclass.
+ */
+ linitial(op->args) = fix_indexqual_operand(linitial(op->args),
+ index,
+ &opclass);
+ clause_op = op->opno;
+ }
+ else if (IsA(clause, ScalarArrayOpExpr))
+ {
+ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
+
+ /* Never need to commute... */
+
+ /*
+ * Now, determine which index attribute this is, change the
+ * indexkey operand as needed, and get the index opclass.
+ */
+ linitial(saop->args) = fix_indexqual_operand(linitial(saop->args),
+ index,
+ &opclass);
+ clause_op = saop->opno;
+ }
+ else
+ {
+ elog(ERROR, "unsupported indexqual type: %d",
+ (int) nodeTag(clause));
+ continue; /* keep compiler quiet */
+ }
- *fixed_indexquals = lappend(*fixed_indexquals, newclause);
+ *fixed_indexquals = lappend(*fixed_indexquals, clause);
/*
* Look up the (possibly commuted) operator in the operator class to
* get its strategy numbers and the recheck indicator. This also
* double-checks that we found an operator matching the index.
*/
- get_op_opclass_properties(newclause->opno, opclass,
+ get_op_opclass_properties(clause_op, opclass,
&stratno, &stratsubtype, &recheck);
*indexstrategy = lappend_int(*indexstrategy, stratno);
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index f3a49b30063..f4a3c605c35 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.11 2005/11/22 18:17:13 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.12 2005/11/25 19:47:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -347,6 +347,7 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
index->rel->baserestrictinfo,
NIL,
NULL,
+ SAOP_FORBID,
&found_clause);
if (list_length(restrictclauses) < indexcol)
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index dc135ae9b34..a14117032b9 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.44 2005/11/22 18:17:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.45 2005/11/25 19:47:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -171,7 +171,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
/*
* Avoid generating one-element ORs, which could happen due to
- * redundancy elimination.
+ * redundancy elimination or ScalarArrayOpExpr quals.
*/
if (list_length(withris) <= 1)
result = withris;