Commit 5b051852 authored by Tom Lane's avatar Tom Lane

Remove support for OR'd indexscans internal to a single IndexScan plan

node, as this behavior is now better done as a bitmap OR indexscan.
This allows considerable simplification in nodeIndexscan.c itself as
well as several planner modules concerned with indexscan plan generation.
Also we can improve the sharing of code between regular and bitmap
indexscans, since they are now working with nigh-identical Plan nodes.
parent 186655e9
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.134 2005/04/22 21:58:31 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.135 2005/04/25 01:30:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -52,7 +52,7 @@ static void explain_outNode(StringInfo str, ...@@ -52,7 +52,7 @@ static void explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate, Plan *plan, PlanState *planstate,
Plan *outer_plan, Plan *outer_plan,
int indent, ExplainState *es); int indent, ExplainState *es);
static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel, static void show_scan_qual(List *qual, const char *qlabel,
int scanrelid, Plan *outer_plan, int scanrelid, Plan *outer_plan,
StringInfo str, int indent, ExplainState *es); StringInfo str, int indent, ExplainState *es);
static void show_upper_qual(List *qual, const char *qlabel, static void show_upper_qual(List *qual, const char *qlabel,
...@@ -62,7 +62,6 @@ static void show_upper_qual(List *qual, const char *qlabel, ...@@ -62,7 +62,6 @@ static void show_upper_qual(List *qual, const char *qlabel,
static void show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols, static void show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
const char *qlabel, const char *qlabel,
StringInfo str, int indent, ExplainState *es); StringInfo str, int indent, ExplainState *es);
static Node *make_ors_ands_explicit(List *orclauses);
/* /*
* ExplainQuery - * ExplainQuery -
...@@ -405,7 +404,6 @@ explain_outNode(StringInfo str, ...@@ -405,7 +404,6 @@ explain_outNode(StringInfo str,
Plan *outer_plan, Plan *outer_plan,
int indent, ExplainState *es) int indent, ExplainState *es)
{ {
ListCell *l;
char *pname; char *pname;
int i; int i;
...@@ -583,19 +581,10 @@ explain_outNode(StringInfo str, ...@@ -583,19 +581,10 @@ explain_outNode(StringInfo str,
switch (nodeTag(plan)) switch (nodeTag(plan))
{ {
case T_IndexScan: case T_IndexScan:
if (ScanDirectionIsBackward(((IndexScan *) plan)->indxorderdir)) if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))
appendStringInfoString(str, " Backward"); appendStringInfoString(str, " Backward");
appendStringInfoString(str, " using "); appendStringInfo(str, " using %s",
i = 0; quote_identifier(get_rel_name(((IndexScan *) plan)->indexid)));
foreach(l, ((IndexScan *) plan)->indxid)
{
char *indname;
indname = get_rel_name(lfirst_oid(l));
appendStringInfo(str, "%s%s",
(++i > 1) ? ", " : "",
quote_identifier(indname));
}
/* FALL THRU */ /* FALL THRU */
case T_SeqScan: case T_SeqScan:
case T_BitmapHeapScan: case T_BitmapHeapScan:
...@@ -621,7 +610,7 @@ explain_outNode(StringInfo str, ...@@ -621,7 +610,7 @@ explain_outNode(StringInfo str,
break; break;
case T_BitmapIndexScan: case T_BitmapIndexScan:
appendStringInfo(str, " on %s", appendStringInfo(str, " on %s",
quote_identifier(get_rel_name(((BitmapIndexScan *) plan)->indxid))); quote_identifier(get_rel_name(((BitmapIndexScan *) plan)->indexid)));
break; break;
case T_SubqueryScan: case T_SubqueryScan:
if (((Scan *) plan)->scanrelid > 0) if (((Scan *) plan)->scanrelid > 0)
...@@ -702,19 +691,19 @@ explain_outNode(StringInfo str, ...@@ -702,19 +691,19 @@ explain_outNode(StringInfo str,
switch (nodeTag(plan)) switch (nodeTag(plan))
{ {
case T_IndexScan: case T_IndexScan:
show_scan_qual(((IndexScan *) plan)->indxqualorig, true, show_scan_qual(((IndexScan *) plan)->indexqualorig,
"Index Cond", "Index Cond",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan,
str, indent, es); str, indent, es);
show_scan_qual(plan->qual, false, show_scan_qual(plan->qual,
"Filter", "Filter",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan,
str, indent, es); str, indent, es);
break; break;
case T_BitmapIndexScan: case T_BitmapIndexScan:
show_scan_qual(((BitmapIndexScan *) plan)->indxqualorig, false, show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
"Index Cond", "Index Cond",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan,
...@@ -722,7 +711,7 @@ explain_outNode(StringInfo str, ...@@ -722,7 +711,7 @@ explain_outNode(StringInfo str,
break; break;
case T_BitmapHeapScan: case T_BitmapHeapScan:
/* XXX do we want to show this in production? */ /* XXX do we want to show this in production? */
show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, false, show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
"Recheck Cond", "Recheck Cond",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan,
...@@ -732,7 +721,7 @@ explain_outNode(StringInfo str, ...@@ -732,7 +721,7 @@ explain_outNode(StringInfo str,
case T_TidScan: case T_TidScan:
case T_SubqueryScan: case T_SubqueryScan:
case T_FunctionScan: case T_FunctionScan:
show_scan_qual(plan->qual, false, show_scan_qual(plan->qual,
"Filter", "Filter",
((Scan *) plan)->scanrelid, ((Scan *) plan)->scanrelid,
outer_plan, outer_plan,
...@@ -997,7 +986,7 @@ explain_outNode(StringInfo str, ...@@ -997,7 +986,7 @@ explain_outNode(StringInfo str,
* Show a qualifier expression for a scan plan node * Show a qualifier expression for a scan plan node
*/ */
static void static void
show_scan_qual(List *qual, bool is_or_qual, const char *qlabel, show_scan_qual(List *qual, const char *qlabel,
int scanrelid, Plan *outer_plan, int scanrelid, Plan *outer_plan,
StringInfo str, int indent, ExplainState *es) StringInfo str, int indent, ExplainState *es)
{ {
...@@ -1012,14 +1001,9 @@ show_scan_qual(List *qual, bool is_or_qual, const char *qlabel, ...@@ -1012,14 +1001,9 @@ show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
/* No work if empty qual */ /* No work if empty qual */
if (qual == NIL) if (qual == NIL)
return; return;
if (is_or_qual && list_length(qual) == 1 && linitial(qual) == NIL)
return;
/* Fix qual --- indexqual requires different processing */ /* Convert AND list to explicit AND */
if (is_or_qual) node = (Node *) make_ands_explicit(qual);
node = make_ors_ands_explicit(qual);
else
node = (Node *) make_ands_explicit(qual);
/* Generate deparse context */ /* Generate deparse context */
Assert(scanrelid > 0 && scanrelid <= list_length(es->rtable)); Assert(scanrelid > 0 && scanrelid <= list_length(es->rtable));
...@@ -1177,26 +1161,3 @@ show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols, ...@@ -1177,26 +1161,3 @@ show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
appendStringInfo(str, "\n"); appendStringInfo(str, "\n");
} }
/*
* Indexscan qual lists have an implicit OR-of-ANDs structure. Make it
* explicit so deparsing works properly.
*/
static Node *
make_ors_ands_explicit(List *orclauses)
{
if (orclauses == NIL)
return NULL; /* probably can't happen */
else if (list_length(orclauses) == 1)
return (Node *) make_ands_explicit(linitial(orclauses));
else
{
List *args = NIL;
ListCell *orptr;
foreach(orptr, orclauses)
args = lappend(args, make_ands_explicit(lfirst(orptr)));
return (Node *) make_orclause(args);
}
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.6 2005/04/24 18:16:38 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.7 2005/04/25 01:30:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,14 +22,11 @@ ...@@ -22,14 +22,11 @@
#include "postgres.h" #include "postgres.h"
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h"
#include "executor/execdebug.h" #include "executor/execdebug.h"
#include "executor/instrument.h" #include "executor/instrument.h"
#include "executor/nodeBitmapIndexscan.h" #include "executor/nodeBitmapIndexscan.h"
#include "executor/nodeIndexscan.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "parser/parsetree.h"
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -41,7 +38,7 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node) ...@@ -41,7 +38,7 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
{ {
#define MAX_TIDS 1024 #define MAX_TIDS 1024
TIDBitmap *tbm; TIDBitmap *tbm;
Oid indxid; Oid indexid;
Relation indexRelation; Relation indexRelation;
IndexScanDesc scandesc; IndexScanDesc scandesc;
ItemPointerData tids[MAX_TIDS]; ItemPointerData tids[MAX_TIDS];
...@@ -70,8 +67,8 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node) ...@@ -70,8 +67,8 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
* descriptors. Note we acquire no locks here; the index machinery * descriptors. Note we acquire no locks here; the index machinery
* does its own locks and unlocks. * does its own locks and unlocks.
*/ */
indxid = ((BitmapIndexScan *) node->ss.ps.plan)->indxid; indexid = ((BitmapIndexScan *) node->ss.ps.plan)->indexid;
indexRelation = index_open(indxid); indexRelation = index_open(indexid);
scandesc = index_beginscan_multi(indexRelation, scandesc = index_beginscan_multi(indexRelation,
node->ss.ps.state->es_snapshot, node->ss.ps.state->es_snapshot,
node->biss_NumScanKeys, node->biss_NumScanKeys,
...@@ -166,47 +163,10 @@ ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt) ...@@ -166,47 +163,10 @@ ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
*/ */
if (runtimeKeyInfo) if (runtimeKeyInfo)
{ {
int n_keys; ExecIndexEvalRuntimeKeys(econtext,
ScanKey scan_keys; runtimeKeyInfo,
ExprState **run_keys; node->biss_ScanKeys,
int j; node->biss_NumScanKeys);
n_keys = node->biss_NumScanKeys;
scan_keys = node->biss_ScanKeys;
run_keys = runtimeKeyInfo;
for (j = 0; j < n_keys; j++)
{
/*
* If we have a run-time key, then extract the run-time
* expression and evaluate it with respect to the current
* outer tuple. We then stick the result into the scan
* key.
*
* Note: the result of the eval could be a pass-by-ref value
* that's stored in the outer scan's tuple, not in
* econtext->ecxt_per_tuple_memory. We assume that the
* outer tuple will stay put throughout our scan. If this
* is wrong, we could copy the result into our context
* explicitly, but I think that's not necessary...
*/
if (run_keys[j] != NULL)
{
Datum scanvalue;
bool isNull;
scanvalue = ExecEvalExprSwitchContext(run_keys[j],
econtext,
&isNull,
NULL);
scan_keys[j].sk_argument = scanvalue;
if (isNull)
scan_keys[j].sk_flags |= SK_ISNULL;
else
scan_keys[j].sk_flags &= ~SK_ISNULL;
}
}
node->biss_RuntimeKeysReady = true; node->biss_RuntimeKeysReady = true;
} }
} }
...@@ -237,6 +197,8 @@ BitmapIndexScanState * ...@@ -237,6 +197,8 @@ BitmapIndexScanState *
ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate) ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
{ {
BitmapIndexScanState *indexstate; BitmapIndexScanState *indexstate;
ScanKey scanKeys;
int numScanKeys;
ExprState **runtimeKeyInfo; ExprState **runtimeKeyInfo;
bool have_runtime_keys; bool have_runtime_keys;
...@@ -262,7 +224,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate) ...@@ -262,7 +224,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
* *
* We don't need to initialize targetlist or qual since neither are used. * We don't need to initialize targetlist or qual since neither are used.
* *
* Note: we don't initialize all of the indxqual expression, only the * Note: we don't initialize all of the indexqual expression, only the
* sub-parts corresponding to runtime keys (see below). * sub-parts corresponding to runtime keys (see below).
*/ */
...@@ -271,169 +233,28 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate) ...@@ -271,169 +233,28 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
/* /*
* Initialize index-specific scan state * Initialize index-specific scan state
*/ */
indexstate->biss_ScanKeys = NULL;
indexstate->biss_NumScanKeys = 0;
indexstate->biss_RuntimeKeyInfo = NULL;
indexstate->biss_RuntimeContext = NULL;
indexstate->biss_RuntimeKeysReady = false; indexstate->biss_RuntimeKeysReady = false;
CXT1_printf("ExecInitBitmapIndexScan: context is %d\n", CurrentMemoryContext); CXT1_printf("ExecInitBitmapIndexScan: context is %d\n", CurrentMemoryContext);
/*
* initialize space for runtime key info (may not be needed)
*/
have_runtime_keys = false;
/* /*
* build the index scan keys from the index qualification * build the index scan keys from the index qualification
*/ */
{ have_runtime_keys =
List *quals; ExecIndexBuildScanKeys((PlanState *) indexstate,
List *strategies; node->indexqual,
List *subtypes; node->indexstrategy,
ListCell *qual_cell; node->indexsubtype,
ListCell *strategy_cell; &runtimeKeyInfo,
ListCell *subtype_cell; &scanKeys,
int n_keys; &numScanKeys);
ScanKey scan_keys;
ExprState **run_keys; indexstate->biss_RuntimeKeyInfo = runtimeKeyInfo;
int j; indexstate->biss_ScanKeys = scanKeys;
indexstate->biss_NumScanKeys = numScanKeys;
quals = node->indxqual;
strategies = node->indxstrategy;
subtypes = node->indxsubtype;
n_keys = list_length(quals);
scan_keys = (n_keys <= 0) ? NULL :
(ScanKey) palloc(n_keys * sizeof(ScanKeyData));
run_keys = (n_keys <= 0) ? NULL :
(ExprState **) palloc(n_keys * sizeof(ExprState *));
/*
* for each opclause in the given qual, convert each qual's
* opclause into a single scan key
*/
qual_cell = list_head(quals);
strategy_cell = list_head(strategies);
subtype_cell = list_head(subtypes);
for (j = 0; j < n_keys; j++)
{
OpExpr *clause; /* one clause of index qual */
Expr *leftop; /* expr on lhs of operator */
Expr *rightop; /* expr on rhs ... */
int flags = 0;
AttrNumber varattno; /* att number used in scan */
StrategyNumber strategy; /* op's strategy number */
Oid subtype; /* op's strategy subtype */
RegProcedure opfuncid; /* operator proc id used in scan */
Datum scanvalue; /* value used in scan (if const) */
/*
* extract clause information from the qualification
*/
clause = (OpExpr *) lfirst(qual_cell);
qual_cell = lnext(qual_cell);
strategy = lfirst_int(strategy_cell);
strategy_cell = lnext(strategy_cell);
subtype = lfirst_oid(subtype_cell);
subtype_cell = lnext(subtype_cell);
if (!IsA(clause, OpExpr))
elog(ERROR, "indxqual is not an OpExpr");
opfuncid = clause->opfuncid;
/*
* Here we figure out the contents of the index qual. The
* usual case is (var op const) which means we form a scan key
* for the attribute listed in the var node and use the value
* of the const as comparison data.
*
* If we don't have a const node, it means our scan key is a
* function of information obtained during the execution of
* the plan, in which case we need to recalculate the index
* scan key at run time. Hence, we set have_runtime_keys to
* true and place the appropriate subexpression in run_keys.
* The corresponding scan key values are recomputed at run
* time.
*/
run_keys[j] = NULL;
/*
* determine information in leftop
*/
leftop = (Expr *) get_leftop((Expr *) clause);
if (leftop && IsA(leftop, RelabelType))
leftop = ((RelabelType *) leftop)->arg;
Assert(leftop != NULL);
if (!(IsA(leftop, Var) &&
var_is_rel((Var *) leftop)))
elog(ERROR, "indxqual doesn't have key on left side");
varattno = ((Var *) leftop)->varattno;
/*
* now determine information in rightop
*/
rightop = (Expr *) get_rightop((Expr *) clause);
if (rightop && IsA(rightop, RelabelType))
rightop = ((RelabelType *) rightop)->arg;
Assert(rightop != NULL);
if (IsA(rightop, Const))
{
/*
* if the rightop is a const node then it means it
* identifies the value to place in our scan key.
*/
scanvalue = ((Const *) rightop)->constvalue;
if (((Const *) rightop)->constisnull)
flags |= SK_ISNULL;
}
else
{
/*
* otherwise, the rightop contains an expression evaluable
* at runtime to figure out the value to place in our scan
* key.
*/
have_runtime_keys = true;
run_keys[j] = ExecInitExpr(rightop, (PlanState *) indexstate);
scanvalue = (Datum) 0;
}
/*
* initialize the scan key's fields appropriately
*/
ScanKeyEntryInitialize(&scan_keys[j],
flags,
varattno, /* attribute number to
* scan */
strategy, /* op's strategy */
subtype, /* strategy subtype */
opfuncid, /* reg proc to use */
scanvalue); /* constant */
}
/*
* store the key information into the node.
*/
indexstate->biss_NumScanKeys = n_keys;
indexstate->biss_ScanKeys = scan_keys;
runtimeKeyInfo = run_keys;
}
/* /*
* If all of our keys have the form (var op const), then we have no * If we have runtime keys, we need an ExprContext to evaluate them.
* runtime keys so we store NULL in the runtime key info. Otherwise
* runtime key info contains an array of pointers to runtime key
* expressions.
*
* If we do have runtime keys, we need an ExprContext to evaluate them.
* We could just create a "standard" plan node exprcontext, but to * We could just create a "standard" plan node exprcontext, but to
* keep the code looking similar to nodeIndexscan.c, it seems better * keep the code looking similar to nodeIndexscan.c, it seems better
* to stick with the approach of using a separate ExprContext. * to stick with the approach of using a separate ExprContext.
...@@ -443,17 +264,12 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate) ...@@ -443,17 +264,12 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate)
ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext; ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
ExecAssignExprContext(estate, &indexstate->ss.ps); ExecAssignExprContext(estate, &indexstate->ss.ps);
indexstate->biss_RuntimeKeyInfo = runtimeKeyInfo;
indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext; indexstate->biss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
indexstate->ss.ps.ps_ExprContext = stdecontext; indexstate->ss.ps.ps_ExprContext = stdecontext;
} }
else else
{ {
indexstate->biss_RuntimeKeyInfo = NULL;
indexstate->biss_RuntimeContext = NULL; indexstate->biss_RuntimeContext = NULL;
/* Get rid of the speculatively-allocated flag array, too */
if (runtimeKeyInfo)
pfree(runtimeKeyInfo);
} }
/* We don't keep the table or index open across calls */ /* We don't keep the table or index open across calls */
......
This diff is collapsed.
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.302 2005/04/19 22:35:13 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.303 2005/04/25 01:30:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -253,13 +253,12 @@ _copyIndexScan(IndexScan *from) ...@@ -253,13 +253,12 @@ _copyIndexScan(IndexScan *from)
/* /*
* copy remainder of node * copy remainder of node
*/ */
COPY_NODE_FIELD(indxid); COPY_SCALAR_FIELD(indexid);
COPY_NODE_FIELD(indxqual); COPY_NODE_FIELD(indexqual);
COPY_NODE_FIELD(indxqualorig); COPY_NODE_FIELD(indexqualorig);
COPY_NODE_FIELD(indxstrategy); COPY_NODE_FIELD(indexstrategy);
COPY_NODE_FIELD(indxsubtype); COPY_NODE_FIELD(indexsubtype);
COPY_NODE_FIELD(indxlossy); COPY_SCALAR_FIELD(indexorderdir);
COPY_SCALAR_FIELD(indxorderdir);
return newnode; return newnode;
} }
...@@ -280,11 +279,11 @@ _copyBitmapIndexScan(BitmapIndexScan *from) ...@@ -280,11 +279,11 @@ _copyBitmapIndexScan(BitmapIndexScan *from)
/* /*
* copy remainder of node * copy remainder of node
*/ */
COPY_SCALAR_FIELD(indxid); COPY_SCALAR_FIELD(indexid);
COPY_NODE_FIELD(indxqual); COPY_NODE_FIELD(indexqual);
COPY_NODE_FIELD(indxqualorig); COPY_NODE_FIELD(indexqualorig);
COPY_NODE_FIELD(indxstrategy); COPY_NODE_FIELD(indexstrategy);
COPY_NODE_FIELD(indxsubtype); COPY_NODE_FIELD(indexsubtype);
return newnode; return newnode;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.249 2005/04/21 19:18:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.250 2005/04/25 01:30:13 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -351,13 +351,12 @@ _outIndexScan(StringInfo str, IndexScan *node) ...@@ -351,13 +351,12 @@ _outIndexScan(StringInfo str, IndexScan *node)
_outScanInfo(str, (Scan *) node); _outScanInfo(str, (Scan *) node);
WRITE_NODE_FIELD(indxid); WRITE_OID_FIELD(indexid);
WRITE_NODE_FIELD(indxqual); WRITE_NODE_FIELD(indexqual);
WRITE_NODE_FIELD(indxqualorig); WRITE_NODE_FIELD(indexqualorig);
WRITE_NODE_FIELD(indxstrategy); WRITE_NODE_FIELD(indexstrategy);
WRITE_NODE_FIELD(indxsubtype); WRITE_NODE_FIELD(indexsubtype);
WRITE_NODE_FIELD(indxlossy); WRITE_ENUM_FIELD(indexorderdir, ScanDirection);
WRITE_ENUM_FIELD(indxorderdir, ScanDirection);
} }
static void static void
...@@ -367,11 +366,11 @@ _outBitmapIndexScan(StringInfo str, BitmapIndexScan *node) ...@@ -367,11 +366,11 @@ _outBitmapIndexScan(StringInfo str, BitmapIndexScan *node)
_outScanInfo(str, (Scan *) node); _outScanInfo(str, (Scan *) node);
WRITE_OID_FIELD(indxid); WRITE_OID_FIELD(indexid);
WRITE_NODE_FIELD(indxqual); WRITE_NODE_FIELD(indexqual);
WRITE_NODE_FIELD(indxqualorig); WRITE_NODE_FIELD(indexqualorig);
WRITE_NODE_FIELD(indxstrategy); WRITE_NODE_FIELD(indexstrategy);
WRITE_NODE_FIELD(indxsubtype); WRITE_NODE_FIELD(indexsubtype);
} }
static void static void
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.127 2005/04/21 19:18:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.128 2005/04/25 01:30:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -174,13 +174,12 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte) ...@@ -174,13 +174,12 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Consider sequential scan */ /* Consider sequential scan */
add_path(rel, create_seqscan_path(root, rel)); add_path(rel, create_seqscan_path(root, rel));
/* Consider index scans */
create_index_paths(root, rel);
/* Consider TID scans */ /* Consider TID scans */
create_tidscan_paths(root, rel); create_tidscan_paths(root, rel);
/* Consider index paths for both simple and OR index clauses */
create_index_paths(root, rel);
create_or_index_paths(root, rel);
/* Now find the cheapest of the paths for this rel */ /* Now find the cheapest of the paths for this rel */
set_cheapest(rel); set_cheapest(rel);
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.177 2005/04/23 01:57:34 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.178 2005/04/25 01:30:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -58,10 +58,6 @@ static List *find_usable_indexes(Query *root, RelOptInfo *rel, ...@@ -58,10 +58,6 @@ static List *find_usable_indexes(Query *root, RelOptInfo *rel,
List *clauses, List *outer_clauses, List *clauses, List *outer_clauses,
bool istoplevel, bool isjoininner, bool istoplevel, bool isjoininner,
Relids outer_relids); Relids outer_relids);
static List *generate_bitmap_or_paths(Query *root, RelOptInfo *rel,
List *clauses, List *outer_clauses,
bool isjoininner,
Relids outer_relids);
static Path *choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths); static Path *choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths);
static int bitmap_path_comparator(const void *a, const void *b); static int bitmap_path_comparator(const void *a, const void *b);
static Cost bitmap_and_cost_est(Query *root, RelOptInfo *rel, List *paths); static Cost bitmap_and_cost_est(Query *root, RelOptInfo *rel, List *paths);
...@@ -365,7 +361,7 @@ find_usable_indexes(Query *root, RelOptInfo *rel, ...@@ -365,7 +361,7 @@ find_usable_indexes(Query *root, RelOptInfo *rel,
* for the purpose of generating indexquals, but are not to be searched for * for the purpose of generating indexquals, but are not to be searched for
* ORs. (See find_usable_indexes() for motivation.) * ORs. (See find_usable_indexes() for motivation.)
*/ */
static List * List *
generate_bitmap_or_paths(Query *root, RelOptInfo *rel, generate_bitmap_or_paths(Query *root, RelOptInfo *rel,
List *clauses, List *outer_clauses, List *clauses, List *outer_clauses,
bool isjoininner, bool isjoininner,
...@@ -520,11 +516,7 @@ choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths) ...@@ -520,11 +516,7 @@ choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths)
paths = list_make1(patharray[0]); paths = list_make1(patharray[0]);
costsofar = bitmap_and_cost_est(root, rel, paths); costsofar = bitmap_and_cost_est(root, rel, paths);
if (IsA(patharray[0], IndexPath)) if (IsA(patharray[0], IndexPath))
{ qualsofar = list_copy(((IndexPath *) patharray[0])->indexclauses);
Assert(list_length(((IndexPath *) patharray[0])->indexclauses) == 1);
qualsofar = (List *) linitial(((IndexPath *) patharray[0])->indexclauses);
qualsofar = list_copy(qualsofar);
}
else else
qualsofar = NIL; qualsofar = NIL;
lastcell = list_head(paths); /* for quick deletions */ lastcell = list_head(paths); /* for quick deletions */
...@@ -537,8 +529,7 @@ choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths) ...@@ -537,8 +529,7 @@ choose_bitmap_and(Query *root, RelOptInfo *rel, List *paths)
if (IsA(newpath, IndexPath)) if (IsA(newpath, IndexPath))
{ {
Assert(list_length(((IndexPath *) newpath)->indexclauses) == 1); newqual = ((IndexPath *) newpath)->indexclauses;
newqual = (List *) linitial(((IndexPath *) newpath)->indexclauses);
if (list_difference(newqual, qualsofar) == NIL) if (list_difference(newqual, qualsofar) == NIL)
continue; /* redundant */ continue; /* redundant */
} }
...@@ -714,108 +705,6 @@ group_clauses_by_indexkey(IndexOptInfo *index, ...@@ -714,108 +705,6 @@ group_clauses_by_indexkey(IndexOptInfo *index,
} }
/*
* group_clauses_by_indexkey_for_or
* Generate a list of sublists of clauses that can be used with an index
* to find rows matching an OR subclause.
*
* This is essentially just like group_clauses_by_indexkey() except that
* we can use the given clause (or any AND subclauses of it) as well as
* top-level restriction clauses of the relation. Furthermore, we demand
* that at least one such use be made, otherwise we fail and return NIL.
* (Any path we made without such a use would be redundant with non-OR
* indexscans.)
*
* XXX When we generate an indexqual list that uses both the OR subclause
* and top-level restriction clauses, we end up with a slightly inefficient
* plan because create_indexscan_plan is not very bright about figuring out
* which restriction clauses are implied by the generated indexqual condition.
* Currently we'll end up rechecking both the OR clause and the top-level
* restriction clause as qpquals. FIXME someday.
*/
List *
group_clauses_by_indexkey_for_or(IndexOptInfo *index, Expr *orsubclause)
{
List *clausegroup_list = NIL;
bool matched = false;
int indexcol = 0;
Oid *classes = index->classlist;
do
{
Oid curClass = classes[0];
List *clausegroup = NIL;
ListCell *item;
/* Try to match the OR subclause to the index key */
if (IsA(orsubclause, RestrictInfo))
{
if (match_clause_to_indexcol(index, indexcol, curClass,
(RestrictInfo *) orsubclause,
NULL))
{
clausegroup = lappend(clausegroup, orsubclause);
matched = true;
}
}
else if (and_clause((Node *) orsubclause))
{
foreach(item, ((BoolExpr *) orsubclause)->args)
{
RestrictInfo *subsubclause = (RestrictInfo *) lfirst(item);
if (IsA(subsubclause, RestrictInfo) &&
match_clause_to_indexcol(index, indexcol, curClass,
subsubclause,
NULL))
{
clausegroup = lappend(clausegroup, subsubclause);
matched = true;
}
}
}
/*
* If we found no clauses for this indexkey in the OR subclause
* itself, try looking in the rel's top-level restriction list.
*
* XXX should we always search the top-level list? Slower but could
* sometimes yield a better plan.
*/
if (clausegroup == NIL)
{
foreach(item, index->rel->baserestrictinfo)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
if (match_clause_to_indexcol(index, indexcol, curClass,
rinfo,
NULL))
clausegroup = lappend(clausegroup, rinfo);
}
}
/*
* If still no clauses match this key, we're done; we don't want
* to look at keys to its right.
*/
if (clausegroup == NIL)
break;
clausegroup_list = lappend(clausegroup_list, clausegroup);
indexcol++;
classes++;
} while (!DoneMatchingIndexKeys(classes));
/* if OR clause was not used then forget it, per comments above */
if (!matched)
return NIL;
return clausegroup_list;
}
/* /*
* match_clause_to_indexcol() * match_clause_to_indexcol()
* Determines whether a restriction clause matches a column of an index. * Determines whether a restriction clause matches a column of an index.
...@@ -2017,7 +1906,7 @@ find_clauses_for_join(Query *root, RelOptInfo *rel, ...@@ -2017,7 +1906,7 @@ find_clauses_for_join(Query *root, RelOptInfo *rel,
* of RestrictInfos. * of RestrictInfos.
* *
* This is used to flatten out the result of group_clauses_by_indexkey() * This is used to flatten out the result of group_clauses_by_indexkey()
* or one of its sibling routines, to produce an indexclauses list. * to produce an indexclauses list.
*/ */
List * List *
flatten_clausegroups_list(List *clausegroups) flatten_clausegroups_list(List *clausegroups)
...@@ -2030,39 +1919,6 @@ flatten_clausegroups_list(List *clausegroups) ...@@ -2030,39 +1919,6 @@ flatten_clausegroups_list(List *clausegroups)
return allclauses; return allclauses;
} }
/*
* make_expr_from_indexclauses()
* Given an indexclauses structure, produce an ordinary boolean expression.
*
* This consists of stripping out the RestrictInfo nodes and inserting
* explicit AND and OR nodes as needed. There's not much to it, but
* the functionality is needed in a few places, so centralize the logic.
*/
Expr *
make_expr_from_indexclauses(List *indexclauses)
{
List *orclauses = NIL;
ListCell *orlist;
/* There's no such thing as an indexpath with zero scans */
Assert(indexclauses != NIL);
foreach(orlist, indexclauses)
{
List *andlist = (List *) lfirst(orlist);
/* Strip RestrictInfos */
andlist = get_actual_clauses(andlist);
/* Insert AND node if needed, and add to orclauses list */
orclauses = lappend(orclauses, make_ands_explicit(andlist));
}
if (list_length(orclauses) > 1)
return make_orclause(orclauses);
else
return (Expr *) linitial(orclauses);
}
/**************************************************************************** /****************************************************************************
* ---- ROUTINES TO CHECK OPERANDS ---- * ---- ROUTINES TO CHECK OPERANDS ----
...@@ -2403,7 +2259,7 @@ match_special_index_operator(Expr *clause, Oid opclass, ...@@ -2403,7 +2259,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
* *
* The input list is ordered by index key, and so the output list is too. * The input list is ordered by index key, and so the output list is too.
* (The latter is not depended on by any part of the planner, so far as I can * (The latter is not depended on by any part of the planner, so far as I can
* tell; but some parts of the executor do assume that the indxqual list * tell; but some parts of the executor do assume that the indexqual list
* ultimately delivered to the executor is so ordered. One such place is * ultimately delivered to the executor is so ordered. One such place is
* _bt_preprocess_keys() in the btree support. Perhaps that ought to be fixed * _bt_preprocess_keys() in the btree support. Perhaps that ought to be fixed
* someday --- tgl 7/00) * someday --- tgl 7/00)
......
This diff is collapsed.
This diff is collapsed.
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.108 2005/04/22 21:58:31 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.109 2005/04/25 01:30:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -107,18 +107,18 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -107,18 +107,18 @@ set_plan_references(Plan *plan, List *rtable)
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((IndexScan *) plan)->indxqual); (Node *) ((IndexScan *) plan)->indexqual);
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((IndexScan *) plan)->indxqualorig); (Node *) ((IndexScan *) plan)->indexqualorig);
break; break;
case T_BitmapIndexScan: case T_BitmapIndexScan:
/* no need to fix targetlist and qual */ /* no need to fix targetlist and qual */
Assert(plan->targetlist == NIL); Assert(plan->targetlist == NIL);
Assert(plan->qual == NIL); Assert(plan->qual == NIL);
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((BitmapIndexScan *) plan)->indxqual); (Node *) ((BitmapIndexScan *) plan)->indexqual);
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((BitmapIndexScan *) plan)->indxqualorig); (Node *) ((BitmapIndexScan *) plan)->indexqualorig);
break; break;
case T_BitmapHeapScan: case T_BitmapHeapScan:
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
...@@ -422,31 +422,31 @@ set_inner_join_references(Plan *inner_plan, ...@@ -422,31 +422,31 @@ set_inner_join_references(Plan *inner_plan,
* var nodes to refer to the outer side of the join. * var nodes to refer to the outer side of the join.
*/ */
IndexScan *innerscan = (IndexScan *) inner_plan; IndexScan *innerscan = (IndexScan *) inner_plan;
List *indxqualorig = innerscan->indxqualorig; List *indexqualorig = innerscan->indexqualorig;
/* No work needed if indxqual refers only to its own rel... */ /* No work needed if indexqual refers only to its own rel... */
if (NumRelids((Node *) indxqualorig) > 1) if (NumRelids((Node *) indexqualorig) > 1)
{ {
Index innerrel = innerscan->scan.scanrelid; Index innerrel = innerscan->scan.scanrelid;
/* only refs to outer vars get changed in the inner qual */ /* only refs to outer vars get changed in the inner qual */
innerscan->indxqualorig = join_references(indxqualorig, innerscan->indexqualorig = join_references(indexqualorig,
rtable, rtable,
outer_tlist, outer_tlist,
NIL, NIL,
innerrel, innerrel,
tlists_have_non_vars); tlists_have_non_vars);
innerscan->indxqual = join_references(innerscan->indxqual, innerscan->indexqual = join_references(innerscan->indexqual,
rtable, rtable,
outer_tlist, outer_tlist,
NIL, NIL,
innerrel, innerrel,
tlists_have_non_vars); tlists_have_non_vars);
/* /*
* We must fix the inner qpqual too, if it has join * We must fix the inner qpqual too, if it has join
* clauses (this could happen if special operators are * clauses (this could happen if special operators are
* involved: some indxquals may get rechecked as qpquals). * involved: some indexquals may get rechecked as qpquals).
*/ */
if (NumRelids((Node *) inner_plan->qual) > 1) if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual, inner_plan->qual = join_references(inner_plan->qual,
...@@ -463,26 +463,26 @@ set_inner_join_references(Plan *inner_plan, ...@@ -463,26 +463,26 @@ set_inner_join_references(Plan *inner_plan,
* Same, but index is being used within a bitmap plan. * Same, but index is being used within a bitmap plan.
*/ */
BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan; BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan;
List *indxqualorig = innerscan->indxqualorig; List *indexqualorig = innerscan->indexqualorig;
/* No work needed if indxqual refers only to its own rel... */ /* No work needed if indexqual refers only to its own rel... */
if (NumRelids((Node *) indxqualorig) > 1) if (NumRelids((Node *) indexqualorig) > 1)
{ {
Index innerrel = innerscan->scan.scanrelid; Index innerrel = innerscan->scan.scanrelid;
/* only refs to outer vars get changed in the inner qual */ /* only refs to outer vars get changed in the inner qual */
innerscan->indxqualorig = join_references(indxqualorig, innerscan->indexqualorig = join_references(indexqualorig,
rtable, rtable,
outer_tlist, outer_tlist,
NIL, NIL,
innerrel, innerrel,
tlists_have_non_vars); tlists_have_non_vars);
innerscan->indxqual = join_references(innerscan->indxqual, innerscan->indexqual = join_references(innerscan->indexqual,
rtable, rtable,
outer_tlist, outer_tlist,
NIL, NIL,
innerrel, innerrel,
tlists_have_non_vars); tlists_have_non_vars);
/* no need to fix inner qpqual */ /* no need to fix inner qpqual */
Assert(inner_plan->qual == NIL); Assert(inner_plan->qual == NIL);
} }
...@@ -512,7 +512,7 @@ set_inner_join_references(Plan *inner_plan, ...@@ -512,7 +512,7 @@ set_inner_join_references(Plan *inner_plan,
/* /*
* We must fix the inner qpqual too, if it has join * We must fix the inner qpqual too, if it has join
* clauses (this could happen if special operators are * clauses (this could happen if special operators are
* involved: some indxquals may get rechecked as qpquals). * involved: some indexquals may get rechecked as qpquals).
*/ */
if (NumRelids((Node *) inner_plan->qual) > 1) if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual, inner_plan->qual = join_references(inner_plan->qual,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.97 2005/04/19 22:35:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.98 2005/04/25 01:30:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1028,21 +1028,21 @@ finalize_plan(Plan *plan, List *rtable, ...@@ -1028,21 +1028,21 @@ finalize_plan(Plan *plan, List *rtable,
break; break;
case T_IndexScan: case T_IndexScan:
finalize_primnode((Node *) ((IndexScan *) plan)->indxqual, finalize_primnode((Node *) ((IndexScan *) plan)->indexqual,
&context); &context);
/* /*
* we need not look at indxqualorig, since it will have the * we need not look at indexqualorig, since it will have the
* same param references as indxqual. * same param references as indexqual.
*/ */
break; break;
case T_BitmapIndexScan: case T_BitmapIndexScan:
finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indxqual, finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indexqual,
&context); &context);
/* /*
* we need not look at indxqualorig, since it will have the * we need not look at indexqualorig, since it will have the
* same param references as indxqual. * same param references as indexqual.
*/ */
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.119 2005/04/22 21:58:31 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.120 2005/04/25 01:30:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -475,13 +475,10 @@ create_index_path(Query *root, ...@@ -475,13 +475,10 @@ create_index_path(Query *root,
/* Flatten the clause-groups list to produce indexclauses list */ /* Flatten the clause-groups list to produce indexclauses list */
allclauses = flatten_clausegroups_list(clause_groups); allclauses = flatten_clausegroups_list(clause_groups);
/* /* Fill in the pathnode */
* We are making a pathnode for a single-scan indexscan; therefore, pathnode->indexinfo = index;
* indexinfo etc should be single-element lists. pathnode->indexclauses = allclauses;
*/ pathnode->indexquals = indexquals;
pathnode->indexinfo = list_make1(index);
pathnode->indexclauses = list_make1(allclauses);
pathnode->indexquals = list_make1(indexquals);
pathnode->isjoininner = isjoininner; pathnode->isjoininner = isjoininner;
pathnode->indexscandir = indexscandir; pathnode->indexscandir = indexscandir;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.33 2005/04/22 21:58:31 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.34 2005/04/25 01:30:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -65,55 +65,10 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere) ...@@ -65,55 +65,10 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere)
is_pushed_down, valid_everywhere); is_pushed_down, valid_everywhere);
} }
/*
* make_restrictinfo_from_indexclauses
*
* Given an indexclauses structure, convert to ordinary expression format
* and build RestrictInfo node(s).
*
* The result is a List since we might need to return multiple RestrictInfos.
*
* This could be done as make_restrictinfo(make_expr_from_indexclauses()),
* but if we did it that way then we would strip the original RestrictInfo
* nodes from the index clauses and be forced to build new ones. It's better
* to have a specialized routine that allows sharing of RestrictInfos.
*/
List *
make_restrictinfo_from_indexclauses(List *indexclauses,
bool is_pushed_down,
bool valid_everywhere)
{
List *withris = NIL;
List *withoutris = NIL;
ListCell *orlist;
/* Empty list probably can't happen, but here's what to do */
if (indexclauses == NIL)
return NIL;
/* If single indexscan, just return the ANDed clauses */
if (list_length(indexclauses) == 1)
return (List *) linitial(indexclauses);
/* Else we need an OR RestrictInfo structure */
foreach(orlist, indexclauses)
{
List *andlist = (List *) lfirst(orlist);
/* Create AND subclause with RestrictInfos */
withris = lappend(withris, make_ands_explicit(andlist));
/* And one without */
andlist = get_actual_clauses(andlist);
withoutris = lappend(withoutris, make_ands_explicit(andlist));
}
return list_make1(make_restrictinfo_internal(make_orclause(withoutris),
make_orclause(withris),
is_pushed_down,
valid_everywhere));
}
/* /*
* make_restrictinfo_internal * make_restrictinfo_internal
* *
* Common code for the above two entry points. * Common code for the main entry point and the recursive cases.
*/ */
static RestrictInfo * static RestrictInfo *
make_restrictinfo_internal(Expr *clause, Expr *orclause, make_restrictinfo_internal(Expr *clause, Expr *orclause,
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.177 2005/04/14 20:03:26 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.178 2005/04/25 01:30:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3682,7 +3682,7 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype, ...@@ -3682,7 +3682,7 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
* Estimate the selectivity of a fixed prefix for a pattern match. * Estimate the selectivity of a fixed prefix for a pattern match.
* *
* A fixed prefix "foo" is estimated as the selectivity of the expression * A fixed prefix "foo" is estimated as the selectivity of the expression
* "variable >= 'foo' AND variable < 'fop'" (see also indxqual.c). * "variable >= 'foo' AND variable < 'fop'" (see also indxpath.c).
* *
* We use the >= and < operators from the specified btree opclass to do the * We use the >= and < operators from the specified btree opclass to do the
* estimation. The given variable and Const must be of the associated * estimation. The given variable and Const must be of the associated
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.22 2005/04/19 22:35:17 tgl Exp $ * $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.23 2005/04/25 01:30:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,4 +24,14 @@ extern void ExecIndexMarkPos(IndexScanState *node); ...@@ -24,4 +24,14 @@ extern void ExecIndexMarkPos(IndexScanState *node);
extern void ExecIndexRestrPos(IndexScanState *node); extern void ExecIndexRestrPos(IndexScanState *node);
extern void ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt); extern void ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt);
/* routines exported to share code with nodeBitmapIndexscan.c */
extern bool ExecIndexBuildScanKeys(PlanState *planstate, List *quals,
List *strategies, List *subtypes,
ExprState ***runtimeKeyInfo,
ScanKey *scanKeys, int *numScanKeys);
extern void ExecIndexEvalRuntimeKeys(ExprContext *econtext,
ExprState **run_keys,
ScanKey scan_keys,
int n_keys);
#endif /* NODEINDEXSCAN_H */ #endif /* NODEINDEXSCAN_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.128 2005/04/24 18:16:38 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.129 2005/04/25 01:30:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -862,40 +862,28 @@ typedef ScanState SeqScanState; ...@@ -862,40 +862,28 @@ typedef ScanState SeqScanState;
/* ---------------- /* ----------------
* IndexScanState information * IndexScanState information
* *
* indxqualorig execution state for indxqualorig expressions * indexqualorig execution state for indexqualorig expressions
* NumIndices number of indices in this scan * ScanKeys Skey structures to scan index rel
* IndexPtr current index in use * NumScanKeys number of Skey structs
* MarkIndexPtr IndexPtr for marked scan point * RuntimeKeyInfo array of exprstates for Skeys
* ScanKeys Skey structures to scan index rels
* NumScanKeys array of no of keys in each Skey struct
* RuntimeKeyInfo array of array of exprstates for Skeys
* that will be evaluated at runtime * that will be evaluated at runtime
* RuntimeContext expr context for evaling runtime Skeys * RuntimeContext expr context for evaling runtime Skeys
* RuntimeKeysReady true if runtime Skeys have been computed * RuntimeKeysReady true if runtime Skeys have been computed
* RelationDescs ptr to array of relation descriptors * RelationDesc index relation descriptor
* ScanDescs ptr to array of scan descriptors * ScanDesc index scan descriptor
* LossyQuals ptr to array of qual lists for lossy operators
* DupHash hashtable for recognizing dups in multiple scan
* MaxHash max # entries we will allow in hashtable
* ---------------- * ----------------
*/ */
typedef struct IndexScanState typedef struct IndexScanState
{ {
ScanState ss; /* its first field is NodeTag */ ScanState ss; /* its first field is NodeTag */
List *indxqualorig; List *indexqualorig;
int iss_NumIndices; ScanKey iss_ScanKeys;
int iss_IndexPtr; int iss_NumScanKeys;
int iss_MarkIndexPtr; ExprState **iss_RuntimeKeyInfo;
ScanKey *iss_ScanKeys;
int *iss_NumScanKeys;
ExprState ***iss_RuntimeKeyInfo;
ExprContext *iss_RuntimeContext; ExprContext *iss_RuntimeContext;
bool iss_RuntimeKeysReady; bool iss_RuntimeKeysReady;
RelationPtr iss_RelationDescs; Relation iss_RelationDesc;
IndexScanDescPtr iss_ScanDescs; IndexScanDesc iss_ScanDesc;
List **iss_LossyQuals;
HTAB *iss_DupHash;
long iss_MaxHash;
} IndexScanState; } IndexScanState;
/* ---------------- /* ----------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.78 2005/04/19 22:35:17 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.79 2005/04/25 01:30:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -182,22 +182,35 @@ typedef Scan SeqScan; ...@@ -182,22 +182,35 @@ typedef Scan SeqScan;
/* ---------------- /* ----------------
* index scan node * index scan node
* *
* Note: this can actually represent N indexscans, all on the same table * indexqualorig is an implicitly-ANDed list of index qual expressions, each
* but potentially using different indexes, put together with OR semantics. * in the same form it appeared in the query WHERE condition. Each should
* (XXX that extension should probably go away, because bitmapindexscan will * be of the form (indexkey OP comparisonval) or (comparisonval OP indexkey).
* largely eliminate the need for it.) * The indexkey is a Var or expression referencing column(s) of the index's
* base table. The comparisonval might be any expression, but it won't use
* any columns of the base table.
*
* indexqual has the same form, but the expressions have been commuted if
* necessary to put the indexkeys on the left, and the indexkeys are replaced
* by Var nodes identifying the index columns (varattno is the index column
* position, not the base table's column, even though varno is for the base
* table). This is a bit hokey ... would be cleaner to use a special-purpose
* node type that could not be mistaken for a regular Var. But it will do
* for now.
*
* indexstrategy and indexsubtype are lists corresponding one-to-one with
* indexqual; they give information about the indexable operators that appear
* at the top of each indexqual.
* ---------------- * ----------------
*/ */
typedef struct IndexScan typedef struct IndexScan
{ {
Scan scan; Scan scan;
List *indxid; /* list of index OIDs (1 per scan) */ Oid indexid; /* OID of index to scan */
List *indxqual; /* list of sublists of index quals */ List *indexqual; /* list of index quals (OpExprs) */
List *indxqualorig; /* the same in original form */ List *indexqualorig; /* the same in original form */
List *indxstrategy; /* list of sublists of strategy numbers */ List *indexstrategy; /* integer list of strategy numbers */
List *indxsubtype; /* list of sublists of strategy subtypes */ List *indexsubtype; /* OID list of strategy subtypes */
List *indxlossy; /* list of sublists of lossy flags (ints) */ ScanDirection indexorderdir; /* forward or backward or don't care */
ScanDirection indxorderdir; /* forward or backward or don't care */
} IndexScan; } IndexScan;
/* ---------------- /* ----------------
...@@ -209,19 +222,22 @@ typedef struct IndexScan ...@@ -209,19 +222,22 @@ typedef struct IndexScan
* intermediate BitmapAnd and/or BitmapOr nodes to combine it with * intermediate BitmapAnd and/or BitmapOr nodes to combine it with
* the results of other BitmapIndexScans. * the results of other BitmapIndexScans.
* *
* The fields have the same meanings as for IndexScan, except we don't
* store a direction flag because direction is uninteresting.
*
* In a BitmapIndexScan plan node, the targetlist and qual fields are * In a BitmapIndexScan plan node, the targetlist and qual fields are
* not used and are always NIL. The indxqualorig field is useless at * not used and are always NIL. The indexqualorig field is unused at
* run time too, but is saved for the benefit of EXPLAIN. * run time too, but is saved for the benefit of EXPLAIN.
* ---------------- * ----------------
*/ */
typedef struct BitmapIndexScan typedef struct BitmapIndexScan
{ {
Scan scan; Scan scan;
Oid indxid; /* OID of index to scan */ Oid indexid; /* OID of index to scan */
List *indxqual; /* list of index quals */ List *indexqual; /* list of index quals (OpExprs) */
List *indxqualorig; /* list of original forms of index quals */ List *indexqualorig; /* the same in original form */
List *indxstrategy; /* list of strategy numbers */ List *indexstrategy; /* integer list of strategy numbers */
List *indxsubtype; /* list of strategy subtypes */ List *indexsubtype; /* OID list of strategy subtypes */
} BitmapIndexScan; } BitmapIndexScan;
/* ---------------- /* ----------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.108 2005/04/22 21:58:32 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.109 2005/04/25 01:30:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -332,33 +332,20 @@ typedef struct Path ...@@ -332,33 +332,20 @@ typedef struct Path
} Path; } Path;
/*---------- /*----------
* IndexPath represents an index scan. Although an indexscan can only read * IndexPath represents an index scan over a single index.
* a single relation, it can scan it more than once, potentially using a
* different index during each scan. The result is the union (OR) of all the
* tuples matched during any scan. (The executor is smart enough not to return
* the same tuple more than once, even if it is matched in multiple scans.)
* *
* XXX bitmap index scans will probably obviate the need for plain OR * 'indexinfo' is the index to be scanned.
* indexscans, allowing a lot of this to be simplified.
* *
* 'indexinfo' is a list of IndexOptInfo nodes, one per scan to be performed. * 'indexclauses' is a list of index qualification clauses, with implicit
* * AND semantics across the list. Each clause is a RestrictInfo node from
* 'indexclauses' is a list of index qualifications, also one per scan. * the query's WHERE or JOIN conditions.
* Each entry in 'indexclauses' is a sublist of qualification clauses to be
* used for that scan, with implicit AND semantics across the sublist items.
* NOTE that the semantics of the top-level list in 'indexclauses' is OR
* combination, while the sublists are implicitly AND combinations!
* *
* 'indexquals' has the same structure as 'indexclauses', but it contains * 'indexquals' has the same structure as 'indexclauses', but it contains
* the actual indexqual conditions that can be used with the index(es). * the actual indexqual conditions that can be used with the index.
* In simple cases this is identical to 'indexclauses', but when special * In simple cases this is identical to 'indexclauses', but when special
* indexable operators appear in 'indexclauses', they are replaced by the * indexable operators appear in 'indexclauses', they are replaced by the
* derived indexscannable conditions in 'indexquals'. * derived indexscannable conditions in 'indexquals'.
* *
* Both 'indexclauses' and 'indexquals' are lists of sublists of RestrictInfo
* nodes. (Before 8.0, we kept bare operator expressions in these lists, but
* storing RestrictInfos is more efficient since selectivities can be cached.)
*
* 'isjoininner' is TRUE if the path is a nestloop inner scan (that is, * 'isjoininner' is TRUE if the path is a nestloop inner scan (that is,
* some of the index conditions are join rather than restriction clauses). * some of the index conditions are join rather than restriction clauses).
* *
...@@ -372,7 +359,8 @@ typedef struct Path ...@@ -372,7 +359,8 @@ typedef struct Path
* *
* 'indextotalcost' and 'indexselectivity' are saved in the IndexPath so that * 'indextotalcost' and 'indexselectivity' are saved in the IndexPath so that
* we need not recompute them when considering using the same index in a * we need not recompute them when considering using the same index in a
* bitmap index/heap scan (see BitmapHeapPath). * bitmap index/heap scan (see BitmapHeapPath). The costs of the IndexPath
* itself represent the costs of an IndexScan plan type.
* *
* 'rows' is the estimated result tuple count for the indexscan. This * 'rows' is the estimated result tuple count for the indexscan. This
* is the same as path.parent->rows for a simple indexscan, but it is * is the same as path.parent->rows for a simple indexscan, but it is
...@@ -384,7 +372,7 @@ typedef struct Path ...@@ -384,7 +372,7 @@ typedef struct Path
typedef struct IndexPath typedef struct IndexPath
{ {
Path path; Path path;
List *indexinfo; IndexOptInfo *indexinfo;
List *indexclauses; List *indexclauses;
List *indexquals; List *indexquals;
bool isjoininner; bool isjoininner;
...@@ -402,13 +390,13 @@ typedef struct IndexPath ...@@ -402,13 +390,13 @@ typedef struct IndexPath
* out in physical heap order no matter what the underlying indexes did. * out in physical heap order no matter what the underlying indexes did.
* *
* The individual indexscans are represented by IndexPath nodes, and any * The individual indexscans are represented by IndexPath nodes, and any
* logic on top of them is represented by BitmapAndPath and BitmapOrPath. * logic on top of them is represented by a tree of BitmapAndPath and
* Notice that we can use the same IndexPath node both to represent a regular * BitmapOrPath nodes. Notice that we can use the same IndexPath node both
* IndexScan plan, and as the child of a BitmapHeapPath that represents * to represent a regular IndexScan plan, and as the child of a BitmapHeapPath
* scanning the same index using a BitmapIndexScan. The startup_cost and * that represents scanning the same index using a BitmapIndexScan. The
* total_cost figures of an IndexPath always represent the costs to use it * startup_cost and total_cost figures of an IndexPath always represent the
* as a regular IndexScan. The costs of a BitmapIndexScan can be computed * costs to use it as a regular IndexScan. The costs of a BitmapIndexScan
* using the IndexPath's indextotalcost and indexselectivity. * can be computed using the IndexPath's indextotalcost and indexselectivity.
* *
* BitmapHeapPaths can be nestloop inner indexscans. The isjoininner and * BitmapHeapPaths can be nestloop inner indexscans. The isjoininner and
* rows fields serve the same purpose as for plain IndexPaths. * rows fields serve the same purpose as for plain IndexPaths.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.82 2005/04/22 21:58:32 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/paths.h,v 1.83 2005/04/25 01:30:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -36,13 +36,15 @@ extern void debug_print_rel(Query *root, RelOptInfo *rel); ...@@ -36,13 +36,15 @@ extern void debug_print_rel(Query *root, RelOptInfo *rel);
* routines to generate index paths * routines to generate index paths
*/ */
extern void create_index_paths(Query *root, RelOptInfo *rel); extern void create_index_paths(Query *root, RelOptInfo *rel);
extern List *generate_bitmap_or_paths(Query *root, RelOptInfo *rel,
List *clauses, List *outer_clauses,
bool isjoininner,
Relids outer_relids);
extern Path *best_inner_indexscan(Query *root, RelOptInfo *rel, extern Path *best_inner_indexscan(Query *root, RelOptInfo *rel,
Relids outer_relids, JoinType jointype); Relids outer_relids, JoinType jointype);
extern List *group_clauses_by_indexkey(IndexOptInfo *index, extern List *group_clauses_by_indexkey(IndexOptInfo *index,
List *clauses, List *outer_clauses, List *clauses, List *outer_clauses,
Relids outer_relids); Relids outer_relids);
extern List *group_clauses_by_indexkey_for_or(IndexOptInfo *index,
Expr *orsubclause);
extern bool match_index_to_operand(Node *operand, int indexcol, extern bool match_index_to_operand(Node *operand, int indexcol,
IndexOptInfo *index); IndexOptInfo *index);
extern List *expand_indexqual_conditions(IndexOptInfo *index, extern List *expand_indexqual_conditions(IndexOptInfo *index,
...@@ -50,14 +52,12 @@ extern List *expand_indexqual_conditions(IndexOptInfo *index, ...@@ -50,14 +52,12 @@ extern List *expand_indexqual_conditions(IndexOptInfo *index,
extern void check_partial_indexes(Query *root, RelOptInfo *rel); extern void check_partial_indexes(Query *root, RelOptInfo *rel);
extern bool pred_test(List *predicate_list, List *restrictinfo_list); extern bool pred_test(List *predicate_list, List *restrictinfo_list);
extern List *flatten_clausegroups_list(List *clausegroups); extern List *flatten_clausegroups_list(List *clausegroups);
extern Expr *make_expr_from_indexclauses(List *indexclauses);
/* /*
* orindxpath.c * orindxpath.c
* additional routines for indexable OR clauses * additional routines for indexable OR clauses
*/ */
extern bool create_or_index_quals(Query *root, RelOptInfo *rel); extern bool create_or_index_quals(Query *root, RelOptInfo *rel);
extern void create_or_index_paths(Query *root, RelOptInfo *rel);
/* /*
* tidpath.h * tidpath.h
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.82 2005/04/12 05:11:28 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.83 2005/04/25 01:30:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -33,6 +33,7 @@ extern Plan *optimize_minmax_aggregates(Query *root, List *tlist, ...@@ -33,6 +33,7 @@ extern Plan *optimize_minmax_aggregates(Query *root, List *tlist,
* prototypes for plan/createplan.c * prototypes for plan/createplan.c
*/ */
extern Plan *create_plan(Query *root, Path *best_path); extern Plan *create_plan(Query *root, Path *best_path);
extern List *create_bitmap_restriction(Path *bitmapqual);
extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual, extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
Index scanrelid, Plan *subplan); Index scanrelid, Plan *subplan);
extern Append *make_append(List *appendplans, bool isTarget, List *tlist); extern Append *make_append(List *appendplans, bool isTarget, List *tlist);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.27 2005/04/22 21:58:32 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.28 2005/04/25 01:30:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,9 +18,6 @@ ...@@ -18,9 +18,6 @@
extern RestrictInfo *make_restrictinfo(Expr *clause, bool is_pushed_down, extern RestrictInfo *make_restrictinfo(Expr *clause, bool is_pushed_down,
bool valid_everywhere); bool valid_everywhere);
extern List *make_restrictinfo_from_indexclauses(List *indexclauses,
bool is_pushed_down,
bool valid_everywhere);
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo); extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
extern List *get_actual_clauses(List *restrictinfo_list); extern List *get_actual_clauses(List *restrictinfo_list);
extern void get_actual_join_clauses(List *restrictinfo_list, extern void get_actual_join_clauses(List *restrictinfo_list,
......
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