mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Teach planner and executor to handle ScalarArrayOpExpr as an indexable
qualification when the underlying operator is indexable and useOr is true. That is, indexkey op ANY (ARRAY[...]) is effectively translated into an OR combination of one indexscan for each array element. This only works for bitmap index scans, of course, since regular indexscans no longer support OR'ing of scans. There are still some loose ends to clean up before changing 'x IN (list)' to translate as a ScalarArrayOpExpr; for instance predtest.c ought to be taught about it. But this gets the basic functionality in place.
This commit is contained in:
@ -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
|
||||
*/
|
||||
|
Reference in New Issue
Block a user