Commit 472d3935 authored by Tom Lane's avatar Tom Lane

Rethink representation of index clauses' mapping to index columns.

In commit e2c2c2e8 I made use of nested
list structures to show which clauses went with which index columns, but
on reflection that's a data structure that only an old-line Lisp hacker
could love.  Worse, it adds unnecessary complication to the many places
that don't much care which clauses go with which index columns.  Revert
to the previous arrangement of flat lists of clauses, and instead add a
parallel integer list of column numbers.  The places that care about the
pairing can chase both lists with forboth(), while the places that don't
care just examine one list the same as before.

The only real downside to this is that there are now two more lists that
need to be passed to amcostestimate functions in case they care about
column matching (which btcostestimate does, so not passing the info is not
an option).  Rather than deal with 11-argument amcostestimate functions,
pass just the IndexPath and expect the functions to extract fields from it.
That gets us down to 7 arguments which is better than 11, and it seems
more future-proof against likely additions to the information we keep
about an index path.
parent e2c2c2e8
...@@ -288,9 +288,7 @@ amcanreturn (Relation indexRelation); ...@@ -288,9 +288,7 @@ amcanreturn (Relation indexRelation);
<programlisting> <programlisting>
void void
amcostestimate (PlannerInfo *root, amcostestimate (PlannerInfo *root,
IndexOptInfo *index, IndexPath *path,
List *indexQuals,
List *indexOrderBys,
RelOptInfo *outer_rel, RelOptInfo *outer_rel,
Cost *indexStartupCost, Cost *indexStartupCost,
Cost *indexTotalCost, Cost *indexTotalCost,
...@@ -929,9 +927,7 @@ amrestrpos (IndexScanDesc scan); ...@@ -929,9 +927,7 @@ amrestrpos (IndexScanDesc scan);
<programlisting> <programlisting>
void void
amcostestimate (PlannerInfo *root, amcostestimate (PlannerInfo *root,
IndexOptInfo *index, IndexPath *path,
List *indexQuals,
List *indexOrderBys,
RelOptInfo *outer_rel, RelOptInfo *outer_rel,
Cost *indexStartupCost, Cost *indexStartupCost,
Cost *indexTotalCost, Cost *indexTotalCost,
...@@ -939,7 +935,7 @@ amcostestimate (PlannerInfo *root, ...@@ -939,7 +935,7 @@ amcostestimate (PlannerInfo *root,
double *indexCorrelation); double *indexCorrelation);
</programlisting> </programlisting>
The first five parameters are inputs: The first three parameters are inputs:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
...@@ -952,32 +948,11 @@ amcostestimate (PlannerInfo *root, ...@@ -952,32 +948,11 @@ amcostestimate (PlannerInfo *root,
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><parameter>index</></term> <term><parameter>path</></term>
<listitem> <listitem>
<para> <para>
The index being considered. The index access path being considered. All fields except cost and
</para> selectivity values are valid.
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>indexQuals</></term>
<listitem>
<para>
List of index qual clauses (implicitly ANDed);
a <symbol>NIL</> list indicates no qualifiers are available.
Note that the list contains expression trees with RestrictInfo nodes
at the top, not ScanKeys.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>indexOrderBys</></term>
<listitem>
<para>
List of indexable ORDER BY operators, or <symbol>NIL</> if none.
Note that the list contains expression trees, not ScanKeys.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -988,7 +963,8 @@ amcostestimate (PlannerInfo *root, ...@@ -988,7 +963,8 @@ amcostestimate (PlannerInfo *root,
<para> <para>
If the index is being considered for use in a join inner indexscan, If the index is being considered for use in a join inner indexscan,
the planner's information about the outer side of the join. Otherwise the planner's information about the outer side of the join. Otherwise
<symbol>NULL</>. When non-<symbol>NULL</>, some of the qual clauses will be join clauses <symbol>NULL</>. When non-<symbol>NULL</>, some of the qual clauses
will be join clauses for joins
with this rel rather than being simple restriction clauses. Also, with this rel rather than being simple restriction clauses. Also,
the cost estimator should expect that the index scan will be repeated the cost estimator should expect that the index scan will be repeated
for each row of the outer rel. for each row of the outer rel.
...@@ -1055,7 +1031,7 @@ amcostestimate (PlannerInfo *root, ...@@ -1055,7 +1031,7 @@ amcostestimate (PlannerInfo *root,
row should usually be taken as <varname>cpu_index_tuple_cost</>. In row should usually be taken as <varname>cpu_index_tuple_cost</>. In
addition, an appropriate multiple of <varname>cpu_operator_cost</> should addition, an appropriate multiple of <varname>cpu_operator_cost</> should
be charged for any comparison operators invoked during index processing be charged for any comparison operators invoked during index processing
(especially evaluation of the <literal>indexQuals</> themselves). (especially evaluation of the indexquals themselves).
</para> </para>
<para> <para>
...@@ -1103,8 +1079,8 @@ amcostestimate (PlannerInfo *root, ...@@ -1103,8 +1079,8 @@ amcostestimate (PlannerInfo *root,
knowledge, use the standard optimizer function <function>clauselist_selectivity()</function>: knowledge, use the standard optimizer function <function>clauselist_selectivity()</function>:
<programlisting> <programlisting>
*indexSelectivity = clauselist_selectivity(root, indexQuals, *indexSelectivity = clauselist_selectivity(root, path-&gt;indexquals,
index-&gt;rel-&gt;relid, path-&gt;indexinfo-&gt;rel-&gt;relid,
JOIN_INNER, NULL); JOIN_INNER, NULL);
</programlisting> </programlisting>
</para> </para>
...@@ -1115,7 +1091,8 @@ amcostestimate (PlannerInfo *root, ...@@ -1115,7 +1091,8 @@ amcostestimate (PlannerInfo *root,
Estimate the number of index rows that will be visited during the Estimate the number of index rows that will be visited during the
scan. For many index types this is the same as <parameter>indexSelectivity</> times scan. For many index types this is the same as <parameter>indexSelectivity</> times
the number of rows in the index, but it might be more. (Note that the the number of rows in the index, but it might be more. (Note that the
index's size in pages and rows is available from the <structname>IndexOptInfo</> struct.) index's size in pages and rows is available from the
<literal>path-&gt;indexinfo</> struct.)
</para> </para>
</step> </step>
...@@ -1137,7 +1114,7 @@ amcostestimate (PlannerInfo *root, ...@@ -1137,7 +1114,7 @@ amcostestimate (PlannerInfo *root,
* Also, we charge for evaluation of the indexquals at each index row. * Also, we charge for evaluation of the indexquals at each index row.
* All the costs are assumed to be paid incrementally during the scan. * All the costs are assumed to be paid incrementally during the scan.
*/ */
cost_qual_eval(&amp;index_qual_cost, indexQuals, root); cost_qual_eval(&amp;index_qual_cost, path-&gt;indexquals, root);
*indexStartupCost = index_qual_cost.startup; *indexStartupCost = index_qual_cost.startup;
*indexTotalCost = seq_page_cost * numIndexPages + *indexTotalCost = seq_page_cost * numIndexPages +
(cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples; (cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
......
...@@ -616,7 +616,7 @@ _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir) ...@@ -616,7 +616,7 @@ _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir)
* *
* The output keys must be sorted by index attribute. Presently we expect * The output keys must be sorted by index attribute. Presently we expect
* (but verify) that the input keys are already so sorted --- this is done * (but verify) that the input keys are already so sorted --- this is done
* by group_clauses_by_indexkey() in indxpath.c. Some reordering of the keys * by match_clauses_to_index() in indxpath.c. Some reordering of the keys
* within each attribute may be done as a byproduct of the processing here, * within each attribute may be done as a byproduct of the processing here,
* but no other code depends on that. * but no other code depends on that.
* *
......
...@@ -1512,7 +1512,9 @@ _outIndexPath(StringInfo str, const IndexPath *node) ...@@ -1512,7 +1512,9 @@ _outIndexPath(StringInfo str, const IndexPath *node)
WRITE_NODE_FIELD(indexinfo); WRITE_NODE_FIELD(indexinfo);
WRITE_NODE_FIELD(indexclauses); WRITE_NODE_FIELD(indexclauses);
WRITE_NODE_FIELD(indexquals); WRITE_NODE_FIELD(indexquals);
WRITE_NODE_FIELD(indexqualcols);
WRITE_NODE_FIELD(indexorderbys); WRITE_NODE_FIELD(indexorderbys);
WRITE_NODE_FIELD(indexorderbycols);
WRITE_BOOL_FIELD(isjoininner); WRITE_BOOL_FIELD(isjoininner);
WRITE_ENUM_FIELD(indexscandir, ScanDirection); WRITE_ENUM_FIELD(indexscandir, ScanDirection);
WRITE_FLOAT_FIELD(indextotalcost, "%.2f"); WRITE_FLOAT_FIELD(indextotalcost, "%.2f");
......
...@@ -52,7 +52,9 @@ ...@@ -52,7 +52,9 @@
* results into. All the input data they need is passed as separate * results into. All the input data they need is passed as separate
* parameters, even though much of it could be extracted from the Path. * parameters, even though much of it could be extracted from the Path.
* An exception is made for the cost_XXXjoin() routines, which expect all * An exception is made for the cost_XXXjoin() routines, which expect all
* the non-cost fields of the passed XXXPath to be filled in. * the non-cost fields of the passed XXXPath to be filled in, and similarly
* cost_index() assumes the passed IndexPath is valid except for its output
* values.
* *
* *
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
...@@ -208,38 +210,28 @@ cost_seqscan(Path *path, PlannerInfo *root, ...@@ -208,38 +210,28 @@ cost_seqscan(Path *path, PlannerInfo *root,
* cost_index * cost_index
* Determines and returns the cost of scanning a relation using an index. * Determines and returns the cost of scanning a relation using an index.
* *
* 'index' is the index to be used * 'path' describes the indexscan under consideration, and is complete
* 'indexQuals' is a list of lists of applicable qual clauses (implicit AND * except for the fields to be set by this routine
* semantics, one sub-list per index column)
* 'indexOrderBys' is a list of lists of lists of ORDER BY expressions for
* amcanorderbyop indexes (lists per pathkey and index column)
* 'indexonly' is true if it's an index-only scan
* 'outer_rel' is the outer relation when we are considering using the index * 'outer_rel' is the outer relation when we are considering using the index
* scan as the inside of a nestloop join (hence, some of the indexQuals * scan as the inside of a nestloop join (hence, some of the indexquals
* are join clauses, and we should expect repeated scans of the index); * are join clauses, and we should expect repeated scans of the index);
* NULL for a plain index scan * NULL for a plain index scan
* *
* cost_index() takes an IndexPath not just a Path, because it sets a few * In addition to startup_cost and total_cost, cost_index() sets the path's
* additional fields of the IndexPath besides startup_cost and total_cost. * indextotalcost and indexselectivity fields. These values are needed if
* These fields are needed if the IndexPath is used in a BitmapIndexScan. * the IndexPath is used in a BitmapIndexScan.
* *
* indexQuals is a list of lists of RestrictInfo nodes, but indexOrderBys * NOTE: path->indexquals must contain only clauses usable as index
* is a list of lists of lists of bare expressions. * restrictions. Any additional quals evaluated as qpquals may reduce the
* * number of returned tuples, but they won't reduce the number of tuples
* NOTE: 'indexQuals' must contain only clauses usable as index restrictions. * we have to fetch from the table, so they don't reduce the scan cost.
* Any additional quals evaluated as qpquals may reduce the number of returned
* tuples, but they won't reduce the number of tuples we have to fetch from
* the table, so they don't reduce the scan cost.
*/ */
void void
cost_index(IndexPath *path, PlannerInfo *root, cost_index(IndexPath *path, PlannerInfo *root, RelOptInfo *outer_rel)
IndexOptInfo *index,
List *indexQuals,
List *indexOrderBys,
bool indexonly,
RelOptInfo *outer_rel)
{ {
IndexOptInfo *index = path->indexinfo;
RelOptInfo *baserel = index->rel; RelOptInfo *baserel = index->rel;
bool indexonly = (path->path.pathtype == T_IndexOnlyScan);
Cost startup_cost = 0; Cost startup_cost = 0;
Cost run_cost = 0; Cost run_cost = 0;
Cost indexStartupCost; Cost indexStartupCost;
...@@ -271,11 +263,9 @@ cost_index(IndexPath *path, PlannerInfo *root, ...@@ -271,11 +263,9 @@ cost_index(IndexPath *path, PlannerInfo *root,
* the fraction of main-table tuples we will have to retrieve) and its * the fraction of main-table tuples we will have to retrieve) and its
* correlation to the main-table tuple order. * correlation to the main-table tuple order.
*/ */
OidFunctionCall9(index->amcostestimate, OidFunctionCall7(index->amcostestimate,
PointerGetDatum(root), PointerGetDatum(root),
PointerGetDatum(index), PointerGetDatum(path),
PointerGetDatum(indexQuals),
PointerGetDatum(indexOrderBys),
PointerGetDatum(outer_rel), PointerGetDatum(outer_rel),
PointerGetDatum(&indexStartupCost), PointerGetDatum(&indexStartupCost),
PointerGetDatum(&indexTotalCost), PointerGetDatum(&indexTotalCost),
...@@ -431,7 +421,7 @@ cost_index(IndexPath *path, PlannerInfo *root, ...@@ -431,7 +421,7 @@ cost_index(IndexPath *path, PlannerInfo *root,
{ {
QualCost index_qual_cost; QualCost index_qual_cost;
cost_qual_eval(&index_qual_cost, indexQuals, root); cost_qual_eval(&index_qual_cost, path->indexquals, root);
/* any startup cost still has to be paid ... */ /* any startup cost still has to be paid ... */
cpu_per_tuple -= index_qual_cost.per_tuple; cpu_per_tuple -= index_qual_cost.per_tuple;
} }
...@@ -589,7 +579,7 @@ get_indexpath_pages(Path *bitmapqual) ...@@ -589,7 +579,7 @@ get_indexpath_pages(Path *bitmapqual)
* 'baserel' is the relation to be scanned * 'baserel' is the relation to be scanned
* 'bitmapqual' is a tree of IndexPaths, BitmapAndPaths, and BitmapOrPaths * 'bitmapqual' is a tree of IndexPaths, BitmapAndPaths, and BitmapOrPaths
* 'outer_rel' is the outer relation when we are considering using the bitmap * 'outer_rel' is the outer relation when we are considering using the bitmap
* scan as the inside of a nestloop join (hence, some of the indexQuals * scan as the inside of a nestloop join (hence, some of the indexquals
* are join clauses, and we should expect repeated scans of the table); * are join clauses, and we should expect repeated scans of the table);
* NULL for a plain bitmap scan * NULL for a plain bitmap scan
* *
......
This diff is collapsed.
This diff is collapsed.
...@@ -3296,7 +3296,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) ...@@ -3296,7 +3296,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
/* Estimate the cost of index scan */ /* Estimate the cost of index scan */
indexScanPath = create_index_path(root, indexInfo, indexScanPath = create_index_path(root, indexInfo,
NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
ForwardScanDirection, false, NULL); ForwardScanDirection, false, NULL);
return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost); return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
......
...@@ -410,10 +410,14 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel) ...@@ -410,10 +410,14 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel)
* Creates a path node for an index scan. * Creates a path node for an index scan.
* *
* 'index' is a usable index. * 'index' is a usable index.
* 'clause_groups' is a list of lists of RestrictInfo nodes * 'indexclauses' is a list of RestrictInfo nodes representing clauses
* to be used as index qual conditions in the scan. * to be used as index qual conditions in the scan.
* 'indexorderbys' is a list of lists of lists of bare expressions (not * 'indexclausecols' is an integer list of index column numbers (zero based)
* RestrictInfos) to be used as index ordering operators. * the indexclauses can be used with.
* 'indexorderbys' is a list of bare expressions (no RestrictInfos)
* to be used as index ordering operators in the scan.
* 'indexorderbycols' is an integer list of index column numbers (zero based)
* the ordering operators can be used with.
* 'pathkeys' describes the ordering of the path. * 'pathkeys' describes the ordering of the path.
* 'indexscandir' is ForwardScanDirection or BackwardScanDirection * 'indexscandir' is ForwardScanDirection or BackwardScanDirection
* for an ordered index, or NoMovementScanDirection for * for an ordered index, or NoMovementScanDirection for
...@@ -427,8 +431,10 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel) ...@@ -427,8 +431,10 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel)
IndexPath * IndexPath *
create_index_path(PlannerInfo *root, create_index_path(PlannerInfo *root,
IndexOptInfo *index, IndexOptInfo *index,
List *clause_groups, List *indexclauses,
List *indexclausecols,
List *indexorderbys, List *indexorderbys,
List *indexorderbycols,
List *pathkeys, List *pathkeys,
ScanDirection indexscandir, ScanDirection indexscandir,
bool indexonly, bool indexonly,
...@@ -437,7 +443,7 @@ create_index_path(PlannerInfo *root, ...@@ -437,7 +443,7 @@ create_index_path(PlannerInfo *root,
IndexPath *pathnode = makeNode(IndexPath); IndexPath *pathnode = makeNode(IndexPath);
RelOptInfo *rel = index->rel; RelOptInfo *rel = index->rel;
List *indexquals, List *indexquals,
*allclauses; *indexqualcols;
/* /*
* For a join inner scan, there's no point in marking the path with any * For a join inner scan, there's no point in marking the path with any
...@@ -457,16 +463,16 @@ create_index_path(PlannerInfo *root, ...@@ -457,16 +463,16 @@ create_index_path(PlannerInfo *root,
pathnode->path.pathkeys = pathkeys; pathnode->path.pathkeys = pathkeys;
/* Convert clauses to indexquals the executor can handle */ /* Convert clauses to indexquals the executor can handle */
indexquals = expand_indexqual_conditions(index, clause_groups); expand_indexqual_conditions(index, indexclauses, indexclausecols,
&indexquals, &indexqualcols);
/* Flatten the clause-groups list to produce indexclauses list */
allclauses = flatten_clausegroups_list(clause_groups);
/* Fill in the pathnode */ /* Fill in the pathnode */
pathnode->indexinfo = index; pathnode->indexinfo = index;
pathnode->indexclauses = allclauses; pathnode->indexclauses = indexclauses;
pathnode->indexquals = indexquals; pathnode->indexquals = indexquals;
pathnode->indexqualcols = indexqualcols;
pathnode->indexorderbys = indexorderbys; pathnode->indexorderbys = indexorderbys;
pathnode->indexorderbycols = indexorderbycols;
pathnode->isjoininner = (outer_rel != NULL); pathnode->isjoininner = (outer_rel != NULL);
pathnode->indexscandir = indexscandir; pathnode->indexscandir = indexscandir;
...@@ -476,7 +482,7 @@ create_index_path(PlannerInfo *root, ...@@ -476,7 +482,7 @@ create_index_path(PlannerInfo *root,
/* /*
* We must compute the estimated number of output rows for the * We must compute the estimated number of output rows for the
* indexscan. This is less than rel->rows because of the additional * indexscan. This is less than rel->rows because of the additional
* selectivity of the join clauses. Since clause_groups may contain * selectivity of the join clauses. Since indexclauses may contain
* both restriction and join clauses, we have to do a set union to get * both restriction and join clauses, we have to do a set union to get
* the full set of clauses that must be considered to compute the * the full set of clauses that must be considered to compute the
* correct selectivity. (Without the union operation, we might have * correct selectivity. (Without the union operation, we might have
...@@ -489,7 +495,9 @@ create_index_path(PlannerInfo *root, ...@@ -489,7 +495,9 @@ create_index_path(PlannerInfo *root,
* Note that we force the clauses to be treated as non-join clauses * Note that we force the clauses to be treated as non-join clauses
* during selectivity estimation. * during selectivity estimation.
*/ */
allclauses = list_union_ptr(rel->baserestrictinfo, allclauses); List *allclauses;
allclauses = list_union_ptr(rel->baserestrictinfo, indexclauses);
pathnode->rows = rel->tuples * pathnode->rows = rel->tuples *
clauselist_selectivity(root, clauselist_selectivity(root,
allclauses, allclauses,
...@@ -508,8 +516,7 @@ create_index_path(PlannerInfo *root, ...@@ -508,8 +516,7 @@ create_index_path(PlannerInfo *root,
pathnode->rows = rel->rows; pathnode->rows = rel->rows;
} }
cost_index(pathnode, root, index, indexquals, indexorderbys, cost_index(pathnode, root, outer_rel);
indexonly, outer_rel);
return pathnode; return pathnode;
} }
......
This diff is collapsed.
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201112231 #define CATALOG_VERSION_NO 201112241
#endif #endif
...@@ -548,7 +548,7 @@ DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 ...@@ -548,7 +548,7 @@ DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 16 "2281" _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ )); DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 16 "2281" _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ )); DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ )); DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
DESCR("btree(internal)"); DESCR("btree(internal)");
...@@ -662,7 +662,7 @@ DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4 ...@@ -662,7 +662,7 @@ DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ )); DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ )); DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ hashcostestimate _null_ _null_ _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ )); DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ hashoptions _null_ _null_ _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
...@@ -917,7 +917,7 @@ DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4 ...@@ -917,7 +917,7 @@ DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ )); DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ )); DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gistcostestimate _null_ _null_ _null_ ));
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ )); DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ gistoptions _null_ _null_ _null_ ));
DESCR("gist(internal)"); DESCR("gist(internal)");
...@@ -3870,7 +3870,7 @@ DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4 ...@@ -3870,7 +3870,7 @@ DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4
DESCR("gin(internal)"); DESCR("gin(internal)");
DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ )); DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ )); DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ gincostestimate _null_ _null_ _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ )); DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ ginoptions _null_ _null_ _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
...@@ -4530,7 +4530,7 @@ DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v ...@@ -4530,7 +4530,7 @@ DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v
DESCR("spgist(internal)"); DESCR("spgist(internal)");
DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 16 "2281" _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ )); DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 16 "2281" _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
DESCR("spgist(internal)"); DESCR("spgist(internal)");
DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ )); DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 7 0 2278 "2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
DESCR("spgist(internal)"); DESCR("spgist(internal)");
DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ )); DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));
DESCR("spgist(internal)"); DESCR("spgist(internal)");
......
...@@ -657,27 +657,33 @@ typedef struct Path ...@@ -657,27 +657,33 @@ typedef struct Path
* *
* 'indexclauses' is a list of index qualification clauses, with implicit * 'indexclauses' is a list of index qualification clauses, with implicit
* AND semantics across the list. Each clause is a RestrictInfo node from * AND semantics across the list. Each clause is a RestrictInfo node from
* the query's WHERE or JOIN conditions. * the query's WHERE or JOIN conditions. An empty list implies a full
* * index scan.
* 'indexquals' is a list of sub-lists of the actual index qual conditions *
* that can be used with the index. There is one possibly-empty sub-list * 'indexquals' has the same structure as 'indexclauses', but it contains
* for each index column (but empty sub-lists for trailing columns can be * the actual index qual conditions that can be used with the index.
* omitted). The qual conditions are RestrictInfos, and in simple cases * In simple cases this is identical to 'indexclauses', but when special
* are the same RestrictInfos that appear in the flat indexclauses list. * indexable operators appear in 'indexclauses', they are replaced by the
* But when special indexable operators appear in 'indexclauses', they are * derived indexscannable conditions in 'indexquals'.
* replaced by their derived indexscannable conditions in 'indexquals'. *
* Note that an entirely empty indexquals list denotes a full-index scan. * 'indexqualcols' is an integer list of index column numbers (zero-based)
* * of the same length as 'indexquals', showing which index column each qual
* 'indexorderbys', if not NIL, is a list of lists of lists of ORDER BY * is meant to be used with. 'indexquals' is required to be ordered by
* expressions that have been found to be usable as ordering operators for an * index column, so 'indexqualcols' must form a nondecreasing sequence.
* amcanorderbyop index. These are not RestrictInfos, just bare expressions, * (The order of multiple quals for the same index column is unspecified.)
*
* 'indexorderbys', if not NIL, is a list of ORDER BY expressions that have
* been found to be usable as ordering operators for an amcanorderbyop index.
* The list must match the path's pathkeys, ie, one expression per pathkey
* in the same order. These are not RestrictInfos, just bare expressions,
* since they generally won't yield booleans. Also, unlike the case for * since they generally won't yield booleans. Also, unlike the case for
* quals, it's guaranteed that each expression has the index key on the left * quals, it's guaranteed that each expression has the index key on the left
* side of the operator. The top list has one entry per pathkey in the * side of the operator.
* path's pathkeys, and the sub-lists have one sub-sublist per index column. *
* This representation is a bit of overkill, since there will be only one * 'indexorderbycols' is an integer list of index column numbers (zero-based)
* actual expression per pathkey, but it's convenient because each sub-list * of the same length as 'indexorderbys', showing which index column each
* has the same structure as the indexquals list. * ORDER BY expression is meant to be used with. (There is no restriction
* on which index column each ORDER BY can be used with.)
* *
* '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).
...@@ -711,7 +717,9 @@ typedef struct IndexPath ...@@ -711,7 +717,9 @@ typedef struct IndexPath
IndexOptInfo *indexinfo; IndexOptInfo *indexinfo;
List *indexclauses; List *indexclauses;
List *indexquals; List *indexquals;
List *indexqualcols;
List *indexorderbys; List *indexorderbys;
List *indexorderbycols;
bool isjoininner; bool isjoininner;
ScanDirection indexscandir; ScanDirection indexscandir;
Cost indextotalcost; Cost indextotalcost;
......
...@@ -67,9 +67,8 @@ extern double clamp_row_est(double nrows); ...@@ -67,9 +67,8 @@ extern double clamp_row_est(double nrows);
extern double index_pages_fetched(double tuples_fetched, BlockNumber pages, extern double index_pages_fetched(double tuples_fetched, BlockNumber pages,
double index_pages, PlannerInfo *root); double index_pages, PlannerInfo *root);
extern void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel); extern void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel);
extern void cost_index(IndexPath *path, PlannerInfo *root, IndexOptInfo *index, extern void cost_index(IndexPath *path, PlannerInfo *root,
List *indexQuals, List *indexOrderBys, RelOptInfo *outer_rel);
bool indexonly, RelOptInfo *outer_rel);
extern void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, extern void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
Path *bitmapqual, RelOptInfo *outer_rel); Path *bitmapqual, RelOptInfo *outer_rel);
extern void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root); extern void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root);
......
...@@ -30,8 +30,10 @@ extern void add_path(RelOptInfo *parent_rel, Path *new_path); ...@@ -30,8 +30,10 @@ extern void add_path(RelOptInfo *parent_rel, Path *new_path);
extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel); extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel);
extern IndexPath *create_index_path(PlannerInfo *root, extern IndexPath *create_index_path(PlannerInfo *root,
IndexOptInfo *index, IndexOptInfo *index,
List *clause_groups, List *indexclauses,
List *indexclausecols,
List *indexorderbys, List *indexorderbys,
List *indexorderbycols,
List *pathkeys, List *pathkeys,
ScanDirection indexscandir, ScanDirection indexscandir,
bool indexonly, bool indexonly,
......
...@@ -57,11 +57,10 @@ extern bool eclass_matches_any_index(EquivalenceClass *ec, ...@@ -57,11 +57,10 @@ extern bool eclass_matches_any_index(EquivalenceClass *ec,
RelOptInfo *rel); RelOptInfo *rel);
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 void expand_indexqual_conditions(IndexOptInfo *index,
List *clausegroups); List *indexclauses, List *indexclausecols,
List **indexquals_p, List **indexqualcols_p);
extern void check_partial_indexes(PlannerInfo *root, RelOptInfo *rel); extern void check_partial_indexes(PlannerInfo *root, RelOptInfo *rel);
extern List *flatten_clausegroups_list(List *clausegroups);
extern List *flatten_indexorderbys_list(List *indexorderbys);
extern Expr *adjust_rowcompare_for_index(RowCompareExpr *clause, extern Expr *adjust_rowcompare_for_index(RowCompareExpr *clause,
IndexOptInfo *index, IndexOptInfo *index,
int indexcol, int indexcol,
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
/* /*
* Maximum number of arguments to a function. * Maximum number of arguments to a function.
* *
* The minimum value is 9 (index cost estimation uses 9-argument functions). * The minimum value is 8 (GIN indexes use 8-argument support functions).
* The maximum possible value is around 600 (limited by index tuple size in * The maximum possible value is around 600 (limited by index tuple size in
* pg_proc's index; BLCKSZ larger than 8K would allow more). Values larger * pg_proc's index; BLCKSZ larger than 8K would allow more). Values larger
* than needed will waste memory and processing time, but do not directly * than needed will waste memory and processing time, but do not directly
......
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