aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/index/indexam.c24
-rw-r--r--src/backend/access/nbtree/nbtsearch.c12
-rw-r--r--src/backend/access/nbtree/nbtutils.c17
-rw-r--r--src/backend/optimizer/path/indxpath.c53
-rw-r--r--src/backend/optimizer/util/plancat.c5
-rw-r--r--src/backend/utils/adt/selfuncs.c122
-rw-r--r--src/include/access/genam.h3
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_am.h42
-rw-r--r--src/include/nodes/relation.h3
10 files changed, 181 insertions, 104 deletions
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 81c2114976e..a445efc7154 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.82 2005/05/27 23:31:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.83 2005/06/13 23:14:48 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relation OID
@@ -25,7 +25,6 @@
* index_getmulti - get multiple tuples from a scan
* index_bulk_delete - bulk deletion of index tuples
* index_vacuum_cleanup - post-deletion cleanup of an index
- * index_cost_estimator - fetch amcostestimate procedure OID
* index_getprocid - get a support procedure OID
* index_getprocinfo - get a support procedure's lookup info
*
@@ -719,27 +718,6 @@ index_vacuum_cleanup(Relation indexRelation,
}
/* ----------------
- * index_cost_estimator
- *
- * Fetch the amcostestimate procedure OID for an index.
- *
- * We could combine fetching and calling the procedure,
- * as index_insert does for example; but that would require
- * importing a bunch of planner/optimizer stuff into this file.
- * ----------------
- */
-RegProcedure
-index_cost_estimator(Relation indexRelation)
-{
- FmgrInfo *procedure;
-
- RELATION_CHECKS;
- GET_REL_PROCEDURE(amcostestimate);
-
- return procedure->fn_oid;
-}
-
-/* ----------------
* index_getprocid
*
* Some indexed access methods may require support routines that are
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 17b3b0dcddf..824d5ea70e6 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.91 2005/03/29 00:16:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.92 2005/06/13 23:14:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -594,15 +594,17 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
}
/*
- * Done if that was the last attribute.
+ * Done if that was the last attribute, or if next key
+ * is not in sequence (implying no boundary key is available
+ * for the next attribute).
*/
- if (i >= so->numberOfKeys)
+ if (i >= so->numberOfKeys ||
+ cur->sk_attno != curattr + 1)
break;
/*
- * Reset for next attr, which should be in sequence.
+ * Reset for next attr.
*/
- Assert(cur->sk_attno == curattr + 1);
curattr = cur->sk_attno;
chosen = NULL;
}
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 96a3f05a5d6..9a5f8d7ac90 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.62 2004/12/31 21:59:22 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.63 2005/06/13 23:14:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -190,7 +190,9 @@ _bt_formitem(IndexTuple itup)
* matched to continue the scan. In general, numberOfRequiredKeys is equal
* to the number of keys for leading attributes with "=" keys, plus the
* key(s) for the first non "=" attribute, which can be seen to be correct
- * by considering the above example.
+ * by considering the above example. Note in particular that if there are no
+ * keys for a given attribute, the keys for subsequent attributes can never
+ * be required; for instance "WHERE y = 4" requires a full-index scan.
*
* If possible, redundant keys are eliminated: we keep only the tightest
* >/>= bound and the tightest </<= bound, and if there's an = key then
@@ -248,8 +250,8 @@ _bt_preprocess_keys(IndexScanDesc scan)
outkeys = so->keyData;
cur = &inkeys[0];
/* we check that input keys are correctly ordered */
- if (cur->sk_attno != 1)
- elog(ERROR, "key(s) for attribute 1 missed");
+ if (cur->sk_attno < 1)
+ elog(ERROR, "btree index keys must be ordered by attribute");
/* We can short-circuit most of the work if there's just one key */
if (numberOfKeys == 1)
@@ -270,7 +272,8 @@ _bt_preprocess_keys(IndexScanDesc scan)
}
memcpy(outkeys, inkeys, sizeof(ScanKeyData));
so->numberOfKeys = 1;
- so->numberOfRequiredKeys = 1;
+ if (cur->sk_attno == 1)
+ so->numberOfRequiredKeys = 1;
return;
}
@@ -324,8 +327,8 @@ _bt_preprocess_keys(IndexScanDesc scan)
int priorNumberOfEqualCols = numberOfEqualCols;
/* check input keys are correctly ordered */
- if (i < numberOfKeys && cur->sk_attno != attno + 1)
- elog(ERROR, "key(s) for attribute %d missed", attno + 1);
+ if (i < numberOfKeys && cur->sk_attno < attno)
+ elog(ERROR, "btree index keys must be ordered by attribute");
/*
* If = has been specified, no other key will be used. In case
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 9c1874d5907..525304f5cb3 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.183 2005/06/10 22:25:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.184 2005/06/13 23:14:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -87,7 +87,8 @@ static Const *string_to_const(const char *str, Oid datatype);
*
* To be considered for an index scan, an index must match one or more
* restriction clauses or join clauses from the query's qual condition,
- * or match the query's ORDER BY condition.
+ * or match the query's ORDER BY condition, or have a predicate that
+ * matches the query's qual condition.
*
* There are two basic kinds of index scans. A "plain" index scan uses
* only restriction clauses (possibly none at all) in its indexqual,
@@ -210,6 +211,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
* 'clauses' is the current list of clauses (RestrictInfo nodes)
* 'outer_clauses' is the list of additional upper-level clauses
* 'istoplevel' is true if clauses are the rel's top-level restriction list
+ * (outer_clauses must be NIL when this is true)
* 'isjoininner' is true if forming an inner indexscan (so some of the
* given clauses are join clauses)
* 'outer_relids' identifies the outer side of the join (pass NULL
@@ -295,13 +297,12 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
* selectivity of the predicate might alone make the index useful.
*
* Note: not all index AMs support scans with no restriction clauses.
- * We assume here that the AM does so if and only if it supports
- * ordered scans. (It would probably be better if there were a
- * specific flag for this in pg_am, but there's not.)
+ * We can't generate a scan over an index with amoptionalkey = false
+ * unless there's at least one restriction clause.
*/
if (restrictclauses != NIL ||
- useful_pathkeys != NIL ||
- (index->indpred != NIL && index_is_ordered))
+ (index->amoptionalkey &&
+ (useful_pathkeys != NIL || index->indpred != NIL)))
{
ipath = create_index_path(root, index,
restrictclauses,
@@ -608,6 +609,11 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
* group_clauses_by_indexkey
* Find restriction clauses that can be used with an index.
*
+ * Returns a list of sublists of RestrictInfo nodes for clauses that can be
+ * used with this index. Each sublist contains clauses that can be used
+ * with one index key (in no particular order); the top list is ordered by
+ * index key. (This is depended on by expand_indexqual_conditions().)
+ *
* As explained in the comments for find_usable_indexes(), we can use
* clauses from either of the given lists, but the result is required to
* use at least one clause from the "current clauses" list. We return
@@ -616,18 +622,14 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
* outer_relids determines what Vars will be allowed on the other side
* of a possible index qual; see match_clause_to_indexcol().
*
- * Returns a list of sublists of RestrictInfo nodes for clauses that can be
- * used with this index. Each sublist contains clauses that can be used
- * with one index key (in no particular order); the top list is ordered by
- * index key. (This is depended on by expand_indexqual_conditions().)
+ * If the index has amoptionalkey = false, we give up and return NIL when
+ * there are no restriction clauses matching the first index key. Otherwise,
+ * we return NIL if there are no restriction clauses matching any index key.
+ * A non-NIL result will have one (possibly empty) sublist for each index key.
*
- * Note that in a multi-key index, we stop if we find a key that cannot be
- * used with any clause. For example, given an index on (A,B,C), we might
- * return ((C1 C2) (C3 C4)) if we find that clauses C1 and C2 use column A,
- * clauses C3 and C4 use column B, and no clauses use column C. But if
- * no clauses match B we will return ((C1 C2)), whether or not there are
- * clauses matching column C, because the executor couldn't use them anyway.
- * Therefore, there are no empty sublists in the result.
+ * Example: given an index on (A,B,C), we would return ((C1 C2) () (C3 C4))
+ * if we find that clauses C1 and C2 use column A, clauses C3 and C4 use
+ * column C, and no clauses use column B.
*/
List *
group_clauses_by_indexkey(IndexOptInfo *index,
@@ -680,11 +682,10 @@ group_clauses_by_indexkey(IndexOptInfo *index,
}
/*
- * If no clauses match this key, we're done; we don't want to look
- * at keys to its right.
+ * If no clauses match this key, check for amoptionalkey restriction.
*/
- if (clausegroup == NIL)
- break;
+ if (clausegroup == NIL && !index->amoptionalkey && indexcol == 0)
+ return NIL;
clausegroup_list = lappend(clausegroup_list, clausegroup);
@@ -1581,11 +1582,9 @@ match_special_index_operator(Expr *clause, Oid opclass,
* will know what to do with.
*
* 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
- * 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
- * _bt_preprocess_keys() in the btree support. Perhaps that ought to be fixed
- * someday --- tgl 7/00)
+ * (The latter is not depended on by any part of the core planner, I believe,
+ * but parts of the executor require it, and so do the amcostestimate
+ * functions.)
*/
List *
expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index a8dcdae9a2f..067e9f701ca 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.111 2005/06/05 22:32:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.112 2005/06/13 23:14:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -161,7 +161,8 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
}
info->relam = indexRelation->rd_rel->relam;
- info->amcostestimate = index_cost_estimator(indexRelation);
+ info->amcostestimate = indexRelation->rd_am->amcostestimate;
+ info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
/*
* Fetch the ordering operators associated with the index, if
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 0b03f27c39c..204d37bf415 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.181 2005/06/10 22:25:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.182 2005/06/13 23:14:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -4195,18 +4195,23 @@ string_to_bytea_const(const char *str, size_t str_len)
* don't have any better idea about how to estimate. Index-type-specific
* knowledge can be incorporated in the type-specific routines.
*
+ * One bit of index-type-specific knowledge we can relatively easily use
+ * in genericcostestimate is the estimate of the number of index tuples
+ * visited. If numIndexTuples is not 0 then it is used as the estimate,
+ * otherwise we compute a generic estimate.
+ *
*-------------------------------------------------------------------------
*/
static void
genericcostestimate(PlannerInfo *root,
IndexOptInfo *index, List *indexQuals,
+ double numIndexTuples,
Cost *indexStartupCost,
Cost *indexTotalCost,
Selectivity *indexSelectivity,
double *indexCorrelation)
{
- double numIndexTuples;
double numIndexPages;
QualCost index_qual_cost;
double qual_op_cost;
@@ -4254,20 +4259,20 @@ genericcostestimate(PlannerInfo *root,
JOIN_INNER);
/*
- * Estimate the number of tuples that will be visited. We do it in
- * this rather peculiar-looking way in order to get the right answer
- * for partial indexes. We can bound the number of tuples by the
- * index size, in any case.
+ * If caller didn't give us an estimate, estimate the number of index
+ * tuples that will be visited. We do it in this rather peculiar-looking
+ * way in order to get the right answer for partial indexes.
*/
- numIndexTuples = *indexSelectivity * index->rel->tuples;
-
- if (numIndexTuples > index->tuples)
- numIndexTuples = index->tuples;
+ if (numIndexTuples <= 0.0)
+ numIndexTuples = *indexSelectivity * index->rel->tuples;
/*
- * Always estimate at least one tuple is touched, even when
+ * We can bound the number of tuples by the index size in any case.
+ * Also, always estimate at least one tuple is touched, even when
* indexSelectivity estimate is tiny.
*/
+ if (numIndexTuples > index->tuples)
+ numIndexTuples = index->tuples;
if (numIndexTuples < 1.0)
numIndexTuples = 1.0;
@@ -4337,8 +4342,95 @@ btcostestimate(PG_FUNCTION_ARGS)
Oid relid;
AttrNumber colnum;
HeapTuple tuple;
+ double numIndexTuples;
+ List *indexBoundQuals;
+ int indexcol;
+ bool eqQualHere;
+ ListCell *l;
+
+ /*
+ * For a btree scan, only leading '=' quals plus inequality quals
+ * for the immediately next attribute contribute to index selectivity
+ * (these are the "boundary quals" that determine the starting and
+ * stopping points of the index scan). Additional quals can suppress
+ * visits to the heap, so it's OK to count them in indexSelectivity,
+ * but they should not count for estimating numIndexTuples. So we must
+ * examine the given indexQuals to find out which ones count as boundary
+ * quals. We rely on the knowledge that they are given in index column
+ * order.
+ */
+ indexBoundQuals = NIL;
+ indexcol = 0;
+ eqQualHere = false;
+ foreach(l, indexQuals)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+ Expr *clause;
+ Oid clause_op;
+ int op_strategy;
+
+ Assert(IsA(rinfo, RestrictInfo));
+ clause = rinfo->clause;
+ Assert(IsA(clause, OpExpr));
+ clause_op = ((OpExpr *) clause)->opno;
+ if (match_index_to_operand(get_leftop(clause), indexcol, index))
+ {
+ /* clause_op is correct */
+ }
+ else if (match_index_to_operand(get_rightop(clause), indexcol, index))
+ {
+ /* Must flip operator to get the opclass member */
+ clause_op = get_commutator(clause_op);
+ }
+ else
+ {
+ /* Must be past the end of quals for indexcol, try next */
+ if (!eqQualHere)
+ break; /* done if no '=' qual for indexcol */
+ indexcol++;
+ eqQualHere = false;
+ if (match_index_to_operand(get_leftop(clause), indexcol, index))
+ {
+ /* clause_op is correct */
+ }
+ else if (match_index_to_operand(get_rightop(clause),
+ indexcol, index))
+ {
+ /* Must flip operator to get the opclass member */
+ clause_op = get_commutator(clause_op);
+ }
+ else
+ {
+ /* No quals for new indexcol, so we are done */
+ break;
+ }
+ }
+ op_strategy = get_op_opclass_strategy(clause_op,
+ index->classlist[indexcol]);
+ Assert(op_strategy != 0); /* not a member of opclass?? */
+ if (op_strategy == BTEqualStrategyNumber)
+ eqQualHere = true;
+ indexBoundQuals = lappend(indexBoundQuals, rinfo);
+ }
+
+ /*
+ * If index is unique and we found an '=' clause for each column,
+ * we can just assume numIndexTuples = 1 and skip the expensive
+ * clauselist_selectivity calculations.
+ */
+ if (index->unique && indexcol == index->ncolumns - 1 && eqQualHere)
+ numIndexTuples = 1.0;
+ else
+ {
+ Selectivity btreeSelectivity;
+
+ btreeSelectivity = clauselist_selectivity(root, indexBoundQuals,
+ index->rel->relid,
+ JOIN_INNER);
+ numIndexTuples = btreeSelectivity * index->rel->tuples;
+ }
- genericcostestimate(root, index, indexQuals,
+ genericcostestimate(root, index, indexQuals, numIndexTuples,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
@@ -4414,7 +4506,7 @@ rtcostestimate(PG_FUNCTION_ARGS)
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
- genericcostestimate(root, index, indexQuals,
+ genericcostestimate(root, index, indexQuals, 0.0,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
@@ -4432,7 +4524,7 @@ hashcostestimate(PG_FUNCTION_ARGS)
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
- genericcostestimate(root, index, indexQuals,
+ genericcostestimate(root, index, indexQuals, 0.0,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
@@ -4450,7 +4542,7 @@ gistcostestimate(PG_FUNCTION_ARGS)
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
- genericcostestimate(root, index, indexQuals,
+ genericcostestimate(root, index, indexQuals, 0.0,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 3ad0a3d4b2c..1ed42f8be60 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.51 2005/05/27 23:31:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.52 2005/06/13 23:14:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -101,7 +101,6 @@ extern IndexBulkDeleteResult *index_bulk_delete(Relation indexRelation,
extern IndexBulkDeleteResult *index_vacuum_cleanup(Relation indexRelation,
IndexVacuumCleanupInfo *info,
IndexBulkDeleteResult *stats);
-extern RegProcedure index_cost_estimator(Relation indexRelation);
extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
uint16 procnum);
extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index ee8b3aee0a2..969c0e83299 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.274 2005/06/13 02:26:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.275 2005/06/13 23:14:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200506121
+#define CATALOG_VERSION_NO 200506131
#endif
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index bddfda993bb..f473277b46b 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.33 2005/04/14 01:38:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.34 2005/06/13 23:14:49 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -48,6 +48,7 @@ CATALOG(pg_am,2601)
* Zero if AM is not ordered. */
bool amcanunique; /* does AM support UNIQUE indexes? */
bool amcanmulticol; /* does AM support multi-column indexes? */
+ bool amoptionalkey; /* can query omit key for the first column? */
bool amindexnulls; /* does AM support NULL index entries? */
bool amconcurrent; /* does AM support concurrent updates? */
regproc aminsert; /* "insert this tuple" function */
@@ -75,42 +76,43 @@ typedef FormData_pg_am *Form_pg_am;
* compiler constants for pg_am
* ----------------
*/
-#define Natts_pg_am 20
+#define Natts_pg_am 21
#define Anum_pg_am_amname 1
#define Anum_pg_am_amstrategies 2
#define Anum_pg_am_amsupport 3
#define Anum_pg_am_amorderstrategy 4
#define Anum_pg_am_amcanunique 5
#define Anum_pg_am_amcanmulticol 6
-#define Anum_pg_am_amindexnulls 7
-#define Anum_pg_am_amconcurrent 8
-#define Anum_pg_am_aminsert 9
-#define Anum_pg_am_ambeginscan 10
-#define Anum_pg_am_amgettuple 11
-#define Anum_pg_am_amgetmulti 12
-#define Anum_pg_am_amrescan 13
-#define Anum_pg_am_amendscan 14
-#define Anum_pg_am_ammarkpos 15
-#define Anum_pg_am_amrestrpos 16
-#define Anum_pg_am_ambuild 17
-#define Anum_pg_am_ambulkdelete 18
-#define Anum_pg_am_amvacuumcleanup 19
-#define Anum_pg_am_amcostestimate 20
+#define Anum_pg_am_amoptionalkey 7
+#define Anum_pg_am_amindexnulls 8
+#define Anum_pg_am_amconcurrent 9
+#define Anum_pg_am_aminsert 10
+#define Anum_pg_am_ambeginscan 11
+#define Anum_pg_am_amgettuple 12
+#define Anum_pg_am_amgetmulti 13
+#define Anum_pg_am_amrescan 14
+#define Anum_pg_am_amendscan 15
+#define Anum_pg_am_ammarkpos 16
+#define Anum_pg_am_amrestrpos 17
+#define Anum_pg_am_ambuild 18
+#define Anum_pg_am_ambulkdelete 19
+#define Anum_pg_am_amvacuumcleanup 20
+#define Anum_pg_am_amcostestimate 21
/* ----------------
* initial contents of pg_am
* ----------------
*/
-DATA(insert OID = 402 ( rtree 8 3 0 f f f f rtinsert rtbeginscan rtgettuple rtgetmulti rtrescan rtendscan rtmarkpos rtrestrpos rtbuild rtbulkdelete - rtcostestimate ));
+DATA(insert OID = 402 ( rtree 8 3 0 f f f f f rtinsert rtbeginscan rtgettuple rtgetmulti rtrescan rtendscan rtmarkpos rtrestrpos rtbuild rtbulkdelete - rtcostestimate ));
DESCR("r-tree index access method");
-DATA(insert OID = 403 ( btree 5 1 1 t t t t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate ));
+DATA(insert OID = 403 ( btree 5 1 1 t t t t t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
-DATA(insert OID = 405 ( hash 1 1 0 f f f t hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete - hashcostestimate ));
+DATA(insert OID = 405 ( hash 1 1 0 f f f f t hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete - hashcostestimate ));
DESCR("hash index access method");
#define HASH_AM_OID 405
-DATA(insert OID = 783 ( gist 100 7 0 f t f f gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete - gistcostestimate ));
+DATA(insert OID = 783 ( gist 100 7 0 f t f f f gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete - gistcostestimate ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 687ef367841..0a2ca0e5f33 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.114 2005/06/10 03:32:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.115 2005/06/13 23:14:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -328,6 +328,7 @@ typedef struct IndexOptInfo
bool predOK; /* true if predicate matches query */
bool unique; /* true if a unique index */
+ bool amoptionalkey; /* can query omit key for the first column? */
} IndexOptInfo;