Commit 290166f9 authored by Tom Lane's avatar Tom Lane

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.
parent dab52ab1
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.11 2005/11/22 18:17:10 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.12 2005/11/25 19:47:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -43,6 +43,7 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
ItemPointerData tids[MAX_TIDS];
int32 ntids;
double nTuples = 0;
bool doscan;
/* must provide our own instrumentation support */
if (node->ss.ps.instrument)
......@@ -55,9 +56,18 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
/*
* If we have runtime keys and they've not already been set up, do it now.
* Array keys are also treated as runtime keys; note that if ExecReScan
* returns with biss_RuntimeKeysReady still false, then there is an
* empty array key so we should do nothing.
*/
if (node->biss_RuntimeKeyInfo && !node->biss_RuntimeKeysReady)
if (!node->biss_RuntimeKeysReady &&
(node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
{
ExecReScan((PlanState *) node, NULL);
doscan = node->biss_RuntimeKeysReady;
}
else
doscan = true;
/*
* Prepare the result bitmap. Normally we just create a new one to pass
......@@ -79,7 +89,7 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
/*
* Get TIDs from index and insert into bitmap
*/
for (;;)
while (doscan)
{
bool more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids);
......@@ -89,10 +99,15 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
nTuples += ntids;
}
if (!more)
break;
CHECK_FOR_INTERRUPTS();
if (!more)
{
doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
node->biss_NumArrayKeys);
if (doscan) /* reset index scan */
index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
}
}
/* must provide our own instrumentation support */
......@@ -113,10 +128,8 @@ void
ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
{
ExprContext *econtext;
ExprState **runtimeKeyInfo;
econtext = node->biss_RuntimeContext; /* context for runtime keys */
runtimeKeyInfo = node->biss_RuntimeKeyInfo;
if (econtext)
{
......@@ -137,19 +150,27 @@ ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
/*
* If we are doing runtime key calculations (ie, the index keys depend on
* data from an outer scan), compute the new key values
* data from an outer scan), compute the new key values.
*
* Array keys are also treated as runtime keys; note that if we
* return with biss_RuntimeKeysReady still false, then there is an
* empty array key so no index scan is needed.
*/
if (runtimeKeyInfo)
{
if (node->biss_NumRuntimeKeys != 0)
ExecIndexEvalRuntimeKeys(econtext,
runtimeKeyInfo,
node->biss_ScanKeys,
node->biss_NumScanKeys);
node->biss_RuntimeKeys,
node->biss_NumRuntimeKeys);
if (node->biss_NumArrayKeys != 0)
node->biss_RuntimeKeysReady =
ExecIndexEvalArrayKeys(econtext,
node->biss_ArrayKeys,
node->biss_NumArrayKeys);
else
node->biss_RuntimeKeysReady = true;
}
/* reset index scan */
index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
if (node->biss_RuntimeKeysReady)
index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
}
/* ----------------------------------------------------------------
......@@ -193,10 +214,6 @@ BitmapIndexScanState *
ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
{
BitmapIndexScanState *indexstate;
ScanKey scanKeys;
int numScanKeys;
ExprState **runtimeKeyInfo;
bool have_runtime_keys;
/*
* create state structure
......@@ -236,26 +253,25 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
/*
* build the index scan keys from the index qualification
*/
have_runtime_keys =
ExecIndexBuildScanKeys((PlanState *) indexstate,
node->indexqual,
node->indexstrategy,
node->indexsubtype,
&runtimeKeyInfo,
&scanKeys,
&numScanKeys);
indexstate->biss_RuntimeKeyInfo = runtimeKeyInfo;
indexstate->biss_ScanKeys = scanKeys;
indexstate->biss_NumScanKeys = numScanKeys;
ExecIndexBuildScanKeys((PlanState *) indexstate,
node->indexqual,
node->indexstrategy,
node->indexsubtype,
&indexstate->biss_ScanKeys,
&indexstate->biss_NumScanKeys,
&indexstate->biss_RuntimeKeys,
&indexstate->biss_NumRuntimeKeys,
&indexstate->biss_ArrayKeys,
&indexstate->biss_NumArrayKeys);
/*
* If we have runtime keys, we need an ExprContext to evaluate them. We
* could just create a "standard" plan node exprcontext, but to keep the
* code looking similar to nodeIndexscan.c, it seems better to stick with
* the approach of using a separate ExprContext.
* If we have runtime keys or array keys, we need an ExprContext to
* evaluate them. We could just create a "standard" plan node exprcontext,
* but to keep the code looking similar to nodeIndexscan.c, it seems
* better to stick with the approach of using a separate ExprContext.
*/
if (have_runtime_keys)
if (indexstate->biss_NumRuntimeKeys != 0 ||
indexstate->biss_NumArrayKeys != 0)
{
ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
......@@ -286,8 +302,8 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
indexstate->biss_ScanDesc =
index_beginscan_multi(indexstate->biss_RelationDesc,
estate->es_snapshot,
numScanKeys,
scanKeys);
indexstate->biss_NumScanKeys,
indexstate->biss_ScanKeys);
/*
* all done.
......
This diff is collapsed.
......@@ -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 */
......
This diff is collapsed.
......@@ -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);
......
......@@ -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)
......
......@@ -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;
......
......@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.193 2005/11/22 18:17:23 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.194 2005/11/25 19:47:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1299,6 +1299,173 @@ nulltestsel(PlannerInfo *root, NullTestType nulltesttype,
return (Selectivity) selec;
}
/*
* scalararraysel - Selectivity of ScalarArrayOpExpr Node.
*/
Selectivity
scalararraysel(PlannerInfo *root,
ScalarArrayOpExpr *clause,
bool is_join_clause,
int varRelid, JoinType jointype)
{
Oid operator = clause->opno;
bool useOr = clause->useOr;
Node *leftop;
Node *rightop;
RegProcedure oprsel;
FmgrInfo oprselproc;
Datum selarg4;
Selectivity s1;
/*
* First, look up the underlying operator's selectivity estimator.
* Punt if it hasn't got one.
*/
if (is_join_clause)
{
oprsel = get_oprjoin(operator);
selarg4 = Int16GetDatum(jointype);
}
else
{
oprsel = get_oprrest(operator);
selarg4 = Int32GetDatum(varRelid);
}
if (!oprsel)
return (Selectivity) 0.5;
fmgr_info(oprsel, &oprselproc);
/*
* We consider three cases:
*
* 1. rightop is an Array constant: deconstruct the array, apply the
* operator's selectivity function for each array element, and merge
* the results in the same way that clausesel.c does for AND/OR
* combinations.
*
* 2. rightop is an ARRAY[] construct: apply the operator's selectivity
* function for each element of the ARRAY[] construct, and merge.
*
* 3. otherwise, make a guess ...
*/
Assert(list_length(clause->args) == 2);
leftop = (Node *) linitial(clause->args);
rightop = (Node *) lsecond(clause->args);
if (rightop && IsA(rightop, Const))
{
Datum arraydatum = ((Const *) rightop)->constvalue;
bool arrayisnull = ((Const *) rightop)->constisnull;
ArrayType *arrayval;
int16 elmlen;
bool elmbyval;
char elmalign;
int num_elems;
Datum *elem_values;
bool *elem_nulls;
int i;
if (arrayisnull) /* qual can't succeed if null array */
return (Selectivity) 0.0;
arrayval = DatumGetArrayTypeP(arraydatum);
get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
&elmlen, &elmbyval, &elmalign);
deconstruct_array(arrayval,
ARR_ELEMTYPE(arrayval),
elmlen, elmbyval, elmalign,
&elem_values, &elem_nulls, &num_elems);
s1 = useOr ? 0.0 : 1.0;
for (i = 0; i < num_elems; i++)
{
List *args;
Selectivity s2;
args = list_make2(leftop,
makeConst(ARR_ELEMTYPE(arrayval),
elmlen,
elem_values[i],
elem_nulls[i],
elmbyval));
s2 = DatumGetFloat8(FunctionCall4(&oprselproc,
PointerGetDatum(root),
ObjectIdGetDatum(operator),
PointerGetDatum(args),
selarg4));
if (useOr)
s1 = s1 + s2 - s1 * s2;
else
s1 = s1 * s2;
}
}
else if (rightop && IsA(rightop, ArrayExpr) &&
!((ArrayExpr *) rightop)->multidims)
{
ArrayExpr *arrayexpr = (ArrayExpr *) rightop;
int16 elmlen;
bool elmbyval;
ListCell *l;
get_typlenbyval(arrayexpr->element_typeid,
&elmlen, &elmbyval);
s1 = useOr ? 0.0 : 1.0;
foreach(l, arrayexpr->elements)
{
List *args;
Selectivity s2;
args = list_make2(leftop, lfirst(l));
s2 = DatumGetFloat8(FunctionCall4(&oprselproc,
PointerGetDatum(root),
ObjectIdGetDatum(operator),
PointerGetDatum(args),
selarg4));
if (useOr)
s1 = s1 + s2 - s1 * s2;
else
s1 = s1 * s2;
}
}
else
{
CaseTestExpr *dummyexpr;
List *args;
Selectivity s2;
int i;
/*
* We need a dummy rightop to pass to the operator selectivity
* routine. It can be pretty much anything that doesn't look like
* a constant; CaseTestExpr is a convenient choice.
*/
dummyexpr = makeNode(CaseTestExpr);
dummyexpr->typeId = get_element_type(exprType(rightop));
dummyexpr->typeMod = -1;
args = list_make2(leftop, dummyexpr);
s2 = DatumGetFloat8(FunctionCall4(&oprselproc,
PointerGetDatum(root),
ObjectIdGetDatum(operator),
PointerGetDatum(args),
selarg4));
s1 = useOr ? 0.0 : 1.0;
/*
* Arbitrarily assume 10 elements in the eventual array value
*/
for (i = 0; i < 10; i++)
{
if (useOr)
s1 = s1 + s2 - s1 * s2;
else
s1 = s1 * s2;
}
}
/* result should be in range, but make sure... */
CLAMP_PROBABILITY(s1);
return s1;
}
/*
* eqjoinsel - Join selectivity of "="
*/
......@@ -4330,6 +4497,7 @@ btcostestimate(PG_FUNCTION_ARGS)
List *indexBoundQuals;
int indexcol;
bool eqQualHere;
bool found_saop;
ListCell *l;
/*
......@@ -4341,26 +4509,52 @@ btcostestimate(PG_FUNCTION_ARGS)
* for estimating numIndexTuples. So we must examine the given indexQuals
* to find out which ones count as boundary quals. We rely on the
* knowledge that they are given in index column order.
*
* If there's a ScalarArrayOpExpr in the quals, we'll actually perform
* N index scans not one, but the ScalarArrayOpExpr's operator can be
* considered to act the same as it normally does.
*/
indexBoundQuals = NIL;
indexcol = 0;
eqQualHere = false;
found_saop = false;
foreach(l, indexQuals)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
Expr *clause;
Node *leftop,
*rightop;
Oid clause_op;
int op_strategy;
Assert(IsA(rinfo, RestrictInfo));
clause = rinfo->clause;
Assert(IsA(clause, OpExpr));
clause_op = ((OpExpr *) clause)->opno;
if (match_index_to_operand(get_leftop(clause), indexcol, index))
if (IsA(clause, OpExpr))
{
leftop = get_leftop(clause);
rightop = get_rightop(clause);
clause_op = ((OpExpr *) clause)->opno;
}
else if (IsA(clause, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
leftop = (Node *) linitial(saop->args);
rightop = (Node *) lsecond(saop->args);
clause_op = saop->opno;
found_saop = true;
}
else
{
elog(ERROR, "unsupported indexqual type: %d",
(int) nodeTag(clause));
continue; /* keep compiler quiet */
}
if (match_index_to_operand(leftop, indexcol, index))
{
/* clause_op is correct */
}
else if (match_index_to_operand(get_rightop(clause), indexcol, index))
else if (match_index_to_operand(rightop, indexcol, index))
{
/* Must flip operator to get the opclass member */
clause_op = get_commutator(clause_op);
......@@ -4372,12 +4566,11 @@ btcostestimate(PG_FUNCTION_ARGS)
break; /* done if no '=' qual for indexcol */
indexcol++;
eqQualHere = false;
if (match_index_to_operand(get_leftop(clause), indexcol, index))
if (match_index_to_operand(leftop, indexcol, index))
{
/* clause_op is correct */
}
else if (match_index_to_operand(get_rightop(clause),
indexcol, index))
else if (match_index_to_operand(rightop, indexcol, index))
{
/* Must flip operator to get the opclass member */
clause_op = get_commutator(clause_op);
......@@ -4401,7 +4594,10 @@ btcostestimate(PG_FUNCTION_ARGS)
* just assume numIndexTuples = 1 and skip the expensive
* clauselist_selectivity calculations.
*/
if (index->unique && indexcol == index->ncolumns - 1 && eqQualHere)
if (index->unique &&
indexcol == index->ncolumns - 1 &&
eqQualHere &&
!found_saop)
numIndexTuples = 1.0;
else
{
......@@ -4424,7 +4620,14 @@ btcostestimate(PG_FUNCTION_ARGS)
* is that multiple columns dilute the importance of the first column's
* ordering, but don't negate it entirely. Before 8.0 we divided the
* correlation by the number of columns, but that seems too strong.)
*
* We can skip all this if we found a ScalarArrayOpExpr, because then
* the call must be for a bitmap index scan, and the caller isn't going
* to care what the index correlation is.
*/
if (found_saop)
PG_RETURN_VOID();
if (index->indexkeys[0] != 0)
{
/* Simple variable --- look to stats for the underlying table */
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.24 2005/10/15 02:49:44 momjian Exp $
* $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.25 2005/11/25 19:47:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -25,13 +25,15 @@ extern void ExecIndexRestrPos(IndexScanState *node);
extern void ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt);
/* routines exported to share code with nodeBitmapIndexscan.c */
extern bool ExecIndexBuildScanKeys(PlanState *planstate, List *quals,
extern void ExecIndexBuildScanKeys(PlanState *planstate, List *quals,
List *strategies, List *subtypes,
ExprState ***runtimeKeyInfo,
ScanKey *scanKeys, int *numScanKeys);
ScanKey *scanKeys, int *numScanKeys,
IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys,
IndexArrayKeyInfo **arrayKeys, int *numArrayKeys);
extern void ExecIndexEvalRuntimeKeys(ExprContext *econtext,
ExprState **run_keys,
ScanKey scan_keys,
int n_keys);
IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys);
extern bool ExecIndexEvalArrayKeys(ExprContext *econtext,
IndexArrayKeyInfo *arrayKeys, int numArrayKeys);
extern bool ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys);
#endif /* NODEINDEXSCAN_H */
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.141 2005/11/22 18:17:30 momjian Exp $
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.142 2005/11/25 19:47:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -871,16 +871,37 @@ typedef struct ScanState
*/
typedef ScanState SeqScanState;
/*
* These structs store information about index quals that don't have simple
* constant right-hand sides. See comments for ExecIndexBuildScanKeys()
* for discussion.
*/
typedef struct
{
ScanKey scan_key; /* scankey to put value into */
ExprState *key_expr; /* expr to evaluate to get value */
} IndexRuntimeKeyInfo;
typedef struct
{
ScanKey scan_key; /* scankey to put value into */
ExprState *array_expr; /* expr to evaluate to get array value */
int next_elem; /* next array element to use */
int num_elems; /* number of elems in current array value */
Datum *elem_values; /* array of num_elems Datums */
bool *elem_nulls; /* array of num_elems is-null flags */
} IndexArrayKeyInfo;
/* ----------------
* IndexScanState information
*
* indexqualorig execution state for indexqualorig expressions
* ScanKeys Skey structures to scan index rel
* NumScanKeys number of Skey structs
* RuntimeKeyInfo array of exprstates for Skeys
* that will be evaluated at runtime
* RuntimeContext expr context for evaling runtime Skeys
* RuntimeKeys info about Skeys that must be evaluated at runtime
* NumRuntimeKeys number of RuntimeKeys structs
* RuntimeKeysReady true if runtime Skeys have been computed
* RuntimeContext expr context for evaling runtime Skeys
* RelationDesc index relation descriptor
* ScanDesc index scan descriptor
* ----------------
......@@ -891,9 +912,10 @@ typedef struct IndexScanState
List *indexqualorig;
ScanKey iss_ScanKeys;
int iss_NumScanKeys;
ExprState **iss_RuntimeKeyInfo;
ExprContext *iss_RuntimeContext;
IndexRuntimeKeyInfo *iss_RuntimeKeys;
int iss_NumRuntimeKeys;
bool iss_RuntimeKeysReady;
ExprContext *iss_RuntimeContext;
Relation iss_RelationDesc;
IndexScanDesc iss_ScanDesc;
} IndexScanState;
......@@ -904,10 +926,12 @@ typedef struct IndexScanState
* result bitmap to return output into, or NULL
* ScanKeys Skey structures to scan index rel
* NumScanKeys number of Skey structs
* RuntimeKeyInfo array of exprstates for Skeys
* that will be evaluated at runtime
* RuntimeContext expr context for evaling runtime Skeys
* RuntimeKeys info about Skeys that must be evaluated at runtime
* NumRuntimeKeys number of RuntimeKeys structs
* ArrayKeys info about Skeys that come from ScalarArrayOpExprs
* NumArrayKeys number of ArrayKeys structs
* RuntimeKeysReady true if runtime Skeys have been computed
* RuntimeContext expr context for evaling runtime Skeys
* RelationDesc index relation descriptor
* ScanDesc index scan descriptor
* ----------------
......@@ -918,9 +942,12 @@ typedef struct BitmapIndexScanState
TIDBitmap *biss_result;
ScanKey biss_ScanKeys;
int biss_NumScanKeys;
ExprState **biss_RuntimeKeyInfo;
ExprContext *biss_RuntimeContext;
IndexRuntimeKeyInfo *biss_RuntimeKeys;
int biss_NumRuntimeKeys;
IndexArrayKeyInfo *biss_ArrayKeys;
int biss_NumArrayKeys;
bool biss_RuntimeKeysReady;
ExprContext *biss_RuntimeContext;
Relation biss_RelationDesc;
IndexScanDesc biss_ScanDesc;
} BitmapIndexScanState;
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.88 2005/10/15 02:49:45 momjian Exp $
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.89 2005/11/25 19:47:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -34,6 +34,14 @@ extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
* indxpath.c
* routines to generate index paths
*/
typedef enum
{
/* Whether to use ScalarArrayOpExpr to build index qualifications */
SAOP_FORBID, /* Do not use ScalarArrayOpExpr */
SAOP_ALLOW, /* OK to use ScalarArrayOpExpr */
SAOP_REQUIRE /* Require ScalarArrayOpExpr */
} SaOpControl;
extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel);
extern List *generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
List *clauses, List *outer_clauses,
......@@ -44,6 +52,7 @@ extern Path *best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
extern List *group_clauses_by_indexkey(IndexOptInfo *index,
List *clauses, List *outer_clauses,
Relids outer_relids,
SaOpControl saop_control,
bool *found_clause);
extern bool match_index_to_operand(Node *operand, int indexcol,
IndexOptInfo *index);
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.25 2005/11/07 17:36:47 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.26 2005/11/25 19:47:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -112,6 +112,10 @@ extern Selectivity booltestsel(PlannerInfo *root, BoolTestType booltesttype,
Node *arg, int varRelid, JoinType jointype);
extern Selectivity nulltestsel(PlannerInfo *root, NullTestType nulltesttype,
Node *arg, int varRelid);
extern Selectivity scalararraysel(PlannerInfo *root,
ScalarArrayOpExpr *clause,
bool is_join_clause,
int varRelid, JoinType jointype);
extern void mergejoinscansel(PlannerInfo *root, Node *clause,
Selectivity *leftscan,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment