aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/gist/gist.c97
-rw-r--r--src/backend/access/index/istrat.c198
-rw-r--r--src/backend/bootstrap/bootparse.y6
-rw-r--r--src/backend/catalog/index.c14
-rw-r--r--src/backend/catalog/indexing.c8
-rw-r--r--src/backend/commands/cluster.c3
-rw-r--r--src/backend/commands/command.c8
-rw-r--r--src/backend/commands/indexcmds.c190
-rw-r--r--src/backend/nodes/copyfuncs.c4
-rw-r--r--src/backend/nodes/equalfuncs.c4
-rw-r--r--src/backend/nodes/outfuncs.c8
-rw-r--r--src/backend/optimizer/path/costsize.c16
-rw-r--r--src/backend/optimizer/path/indxpath.c168
-rw-r--r--src/backend/optimizer/plan/createplan.c148
-rw-r--r--src/backend/optimizer/util/plancat.c24
-rw-r--r--src/backend/parser/analyze.c3
-rw-r--r--src/backend/parser/gram.y8
-rw-r--r--src/backend/tcop/utility.c3
-rw-r--r--src/backend/utils/adt/regproc.c221
-rw-r--r--src/backend/utils/cache/catcache.c17
-rw-r--r--src/backend/utils/cache/lsyscache.c72
-rw-r--r--src/backend/utils/cache/syscache.c39
-rw-r--r--src/backend/utils/sort/tuplesort.c58
23 files changed, 600 insertions, 717 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 4d0cbb6d9c5..779a0aa8757 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.81 2001/08/10 14:34:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.82 2001/08/21 16:35:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,8 +20,10 @@
#include "access/heapam.h"
#include "catalog/index.h"
#include "catalog/pg_index.h"
+#include "catalog/pg_opclass.h"
#include "executor/executor.h"
#include "miscadmin.h"
+#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "access/xlogutils.h"
@@ -1377,10 +1379,9 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
{
+ IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
sum_grow=0;
for (j=0; j<r->rd_att->natts; j++) {
- IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
-
datum = index_getattr(itup, j+1, r->rd_att, &IsNull);
gistdentryinit(giststate, j, &entry, datum, r, p, i, ATTSIZE( datum, r, j+1, IsNull ), FALSE, IsNull);
gistpenalty( giststate, j, &entry, IsNull, &identry[j], isnull[j], &usize);
@@ -1548,20 +1549,32 @@ initGISTstate(GISTSTATE *giststate, Relation index)
RegProcedure consistent_proc,
union_proc,
compress_proc,
- decompress_proc;
- RegProcedure penalty_proc,
+ decompress_proc,
+ penalty_proc,
picksplit_proc,
equal_proc;
- HeapTuple htup;
+ HeapTuple itup;
+ HeapTuple ctup;
Form_pg_index itupform;
- Oid indexrelid;
+ Form_pg_opclass opclassform;
+ Oid inputtype;
+ Oid keytype;
int i;
- if (index->rd_att->natts >= INDEX_MAX_KEYS)
- elog(ERROR, "initGISTstate: numberOfAttributes %d > %d",
- index->rd_att->natts, INDEX_MAX_KEYS);
+ if (index->rd_att->natts > INDEX_MAX_KEYS)
+ elog(ERROR, "initGISTstate: numberOfAttributes %d > %d",
+ index->rd_att->natts, INDEX_MAX_KEYS);
+
+ itup = SearchSysCache(INDEXRELID,
+ ObjectIdGetDatum(RelationGetRelid(index)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(itup))
+ elog(ERROR, "initGISTstate: index %u not found",
+ RelationGetRelid(index));
+ itupform = (Form_pg_index) GETSTRUCT(itup);
- for(i=0; i<index->rd_att->natts; i++) {
+ for (i = 0; i < index->rd_att->natts; i++)
+ {
consistent_proc = index_getprocid(index, i+1, GIST_CONSISTENT_PROC );
union_proc = index_getprocid(index, i+1, GIST_UNION_PROC );
compress_proc = index_getprocid(index, i+1, GIST_COMPRESS_PROC );
@@ -1577,37 +1590,35 @@ initGISTstate(GISTSTATE *giststate, Relation index)
fmgr_info(picksplit_proc, &((giststate->picksplitFn)[i]) );
fmgr_info(equal_proc, &((giststate->equalFn)[i]) );
- giststate->attbyval[i] =
- index->rd_att->attrs[i]->attbyval;
+ /* Check opclass entry to see if there is a keytype */
+ ctup = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(itupform->indclass[i]),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(ctup))
+ elog(ERROR, "cache lookup failed for opclass %u",
+ itupform->indclass[i]);
+ opclassform = (Form_pg_opclass) GETSTRUCT(ctup);
+ inputtype = opclassform->opcintype;
+ keytype = opclassform->opckeytype;
+ ReleaseSysCache(ctup);
+
+ if (OidIsValid(keytype))
+ {
+ /* index column type is (possibly) different from input data */
+ giststate->haskeytype[i] = true;
+ giststate->attbyval[i] = get_typbyval(inputtype);
+ giststate->keytypbyval[i] = index->rd_att->attrs[i]->attbyval;
+ }
+ else
+ {
+ /* Normal case where index column type is same as input data */
+ giststate->haskeytype[i] = false;
+ giststate->attbyval[i] = index->rd_att->attrs[i]->attbyval;
+ giststate->keytypbyval[i] = false; /* not actually used */
+ }
}
- /* see if key type is different from type of attribute being indexed */
- htup = SearchSysCache(INDEXRELID,
- ObjectIdGetDatum(RelationGetRelid(index)),
- 0, 0, 0);
- if (!HeapTupleIsValid(htup))
- elog(ERROR, "initGISTstate: index %u not found",
- RelationGetRelid(index));
- itupform = (Form_pg_index) GETSTRUCT(htup);
- giststate->haskeytype = itupform->indhaskeytype;
- indexrelid = itupform->indexrelid;
- ReleaseSysCache(htup);
-
- if (giststate->haskeytype)
- {
- /* key type is different -- is it byval? */
- htup = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(indexrelid),
- UInt16GetDatum(FirstOffsetNumber),
- 0, 0);
- if (!HeapTupleIsValid(htup))
- elog(ERROR, "initGISTstate: no attribute tuple %u %d",
- indexrelid, FirstOffsetNumber);
- giststate->keytypbyval = (((Form_pg_attribute) htup)->attbyval);
- ReleaseSysCache(htup);
- }
- else
- giststate->keytypbyval = FALSE;
+ ReleaseSysCache(itup);
}
#ifdef GIST_PAGEADDITEM
@@ -1670,7 +1681,7 @@ gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
GISTENTRY *dep;
gistentryinit(*e, k, r, pg, o, b, l);
- if (giststate->haskeytype)
+ if (giststate->haskeytype[nkey])
{
if ( b && ! isNull ) {
dep = (GISTENTRY *)
@@ -1698,7 +1709,7 @@ gistcentryinit(GISTSTATE *giststate, int nkey,
GISTENTRY *cep;
gistentryinit(*e, k, r, pg, o, b, l);
- if (giststate->haskeytype)
+ if (giststate->haskeytype[nkey])
{
if ( ! isNull ) {
cep = (GISTENTRY *)
@@ -1792,7 +1803,7 @@ gistpenalty( GISTSTATE *giststate, int attno,
FunctionCall3(&giststate->penaltyFn[attno],
PointerGetDatum(key1),
PointerGetDatum(key2),
- PointerGetDatum(&penalty));
+ PointerGetDatum(penalty));
}
#ifdef GISTDEBUG
diff --git a/src/backend/access/index/istrat.c b/src/backend/access/index/istrat.c
index 188f69b5719..35df06aeace 100644
--- a/src/backend/access/index/istrat.c
+++ b/src/backend/access/index/istrat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.51 2001/06/01 02:41:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.52 2001/08/21 16:36:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -457,61 +457,32 @@ RelationInvokeStrategy(Relation relation,
#endif
/* ----------------
- * OperatorRelationFillScanKeyEntry
+ * FillScanKeyEntry
*
- * Initialize a ScanKey entry given already-opened pg_operator relation.
+ * Initialize a ScanKey entry for the given operator OID.
* ----------------
*/
static void
-OperatorRelationFillScanKeyEntry(Relation operatorRelation,
- Oid operatorObjectId,
- ScanKey entry)
+FillScanKeyEntry(Oid operatorObjectId, ScanKey entry)
{
HeapTuple tuple;
- HeapScanDesc scan = NULL;
- bool cachesearch = (!IsBootstrapProcessingMode()) && IsCacheInitialized();
- if (cachesearch)
- {
- tuple = SearchSysCache(OPEROID,
- ObjectIdGetDatum(operatorObjectId),
- 0, 0, 0);
- }
- else
- {
- ScanKeyData scanKeyData;
-
- ScanKeyEntryInitialize(&scanKeyData, 0,
- ObjectIdAttributeNumber,
- F_OIDEQ,
- ObjectIdGetDatum(operatorObjectId));
-
- scan = heap_beginscan(operatorRelation, false, SnapshotNow,
- 1, &scanKeyData);
-
- tuple = heap_getnext(scan, 0);
- }
+ tuple = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(operatorObjectId),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
- {
- if (!cachesearch)
- heap_endscan(scan);
- elog(ERROR, "OperatorRelationFillScanKeyEntry: unknown operator %u",
+ elog(ERROR, "FillScanKeyEntry: unknown operator %u",
operatorObjectId);
- }
MemSet(entry, 0, sizeof(*entry));
entry->sk_flags = 0;
entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
- if (cachesearch)
- ReleaseSysCache(tuple);
- else
- heap_endscan(scan);
+ ReleaseSysCache(tuple);
if (!RegProcedureIsValid(entry->sk_procedure))
- elog(ERROR,
- "OperatorRelationFillScanKeyEntry: no procedure for operator %u",
+ elog(ERROR, "FillScanKeyEntry: no procedure for operator %u",
operatorObjectId);
/*
@@ -548,160 +519,99 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber)
{
- Relation relation = NULL;
- HeapScanDesc scan = NULL;
- ScanKeyData entry[2];
- Relation operatorRelation;
HeapTuple tuple;
Form_pg_index iform;
- StrategyMap map;
- AttrNumber attNumber;
int attIndex;
Oid operatorClassObjectId[INDEX_MAX_KEYS];
- bool cachesearch = (!IsBootstrapProcessingMode()) && IsCacheInitialized();
-
- if (cachesearch)
- {
- tuple = SearchSysCache(INDEXRELID,
- ObjectIdGetDatum(indexObjectId),
- 0, 0, 0);
- }
- else
- {
- ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid,
- F_OIDEQ,
- ObjectIdGetDatum(indexObjectId));
- relation = heap_openr(IndexRelationName, AccessShareLock);
- scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
- tuple = heap_getnext(scan, 0);
- }
+ maxStrategyNumber = AMStrategies(maxStrategyNumber);
+ tuple = SearchSysCache(INDEXRELID,
+ ObjectIdGetDatum(indexObjectId),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "IndexSupportInitialize: no pg_index entry for index %u",
indexObjectId);
-
iform = (Form_pg_index) GETSTRUCT(tuple);
*isUnique = iform->indisunique;
- maxStrategyNumber = AMStrategies(maxStrategyNumber);
-
/*
* XXX note that the following assumes the INDEX tuple is well formed
* and that the *key and *class are 0 terminated.
*/
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
{
- if (!OidIsValid(iform->indkey[attIndex]))
- {
- if (attIndex == InvalidAttrNumber)
- elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
- break;
- }
-
+ if (iform->indkey[attIndex] == InvalidAttrNumber ||
+ !OidIsValid(iform->indclass[attIndex]))
+ elog(ERROR, "IndexSupportInitialize: bogus pg_index tuple");
operatorClassObjectId[attIndex] = iform->indclass[attIndex];
}
- if (cachesearch)
- ReleaseSysCache(tuple);
- else
- {
- heap_endscan(scan);
- heap_close(relation, AccessShareLock);
- }
+ ReleaseSysCache(tuple);
/* if support routines exist for this access method, load them */
if (maxSupportNumber > 0)
{
- ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_amproc_amid,
- F_OIDEQ,
- ObjectIdGetDatum(accessMethodObjectId));
-
- ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
- F_OIDEQ,
- InvalidOid); /* will set below */
-
- relation = heap_openr(AccessMethodProcedureRelationName,
- AccessShareLock);
-
- for (attNumber = 1; attNumber <= maxAttributeNumber; attNumber++)
+ for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
{
+ Oid opclass = operatorClassObjectId[attIndex];
RegProcedure *loc;
StrategyNumber support;
- loc = &indexSupport[((attNumber - 1) * maxSupportNumber)];
+ loc = &indexSupport[attIndex * maxSupportNumber];
for (support = 0; support < maxSupportNumber; ++support)
- loc[support] = InvalidOid;
-
- entry[1].sk_argument =
- ObjectIdGetDatum(operatorClassObjectId[attNumber - 1]);
-
- scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
-
- while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
{
- Form_pg_amproc aform;
-
- aform = (Form_pg_amproc) GETSTRUCT(tuple);
- support = aform->amprocnum;
- Assert(support > 0 && support <= maxSupportNumber);
- loc[support - 1] = aform->amproc;
+ tuple = SearchSysCache(AMPROCNUM,
+ ObjectIdGetDatum(opclass),
+ Int16GetDatum(support+1),
+ 0, 0);
+ if (HeapTupleIsValid(tuple))
+ {
+ Form_pg_amproc amprocform;
+
+ amprocform = (Form_pg_amproc) GETSTRUCT(tuple);
+ loc[support] = amprocform->amproc;
+ ReleaseSysCache(tuple);
+ }
+ else
+ loc[support] = InvalidOid;
}
-
- heap_endscan(scan);
}
- heap_close(relation, AccessShareLock);
}
/* Now load the strategy information for the index operators */
- ScanKeyEntryInitialize(&entry[0], 0,
- Anum_pg_amop_amopid,
- F_OIDEQ,
- ObjectIdGetDatum(accessMethodObjectId));
-
- ScanKeyEntryInitialize(&entry[1], 0,
- Anum_pg_amop_amopclaid,
- F_OIDEQ,
- 0); /* will fill below */
-
- relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
- operatorRelation = heap_openr(OperatorRelationName, AccessShareLock);
-
- for (attNumber = maxAttributeNumber; attNumber > 0; attNumber--)
+ for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
{
+ Oid opclass = operatorClassObjectId[attIndex];
+ StrategyMap map;
StrategyNumber strategy;
- entry[1].sk_argument =
- ObjectIdGetDatum(operatorClassObjectId[attNumber - 1]);
-
map = IndexStrategyGetStrategyMap(indexStrategy,
maxStrategyNumber,
- attNumber);
+ attIndex + 1);
for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
- ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy));
+ {
+ ScanKey mapentry = StrategyMapGetScanKeyEntry(map, strategy);
- scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
+ tuple = SearchSysCache(AMOPSTRATEGY,
+ ObjectIdGetDatum(opclass),
+ Int16GetDatum(strategy),
+ 0, 0);
+ if (HeapTupleIsValid(tuple))
+ {
+ Form_pg_amop amopform;
- while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
- {
- Form_pg_amop aform;
-
- aform = (Form_pg_amop) GETSTRUCT(tuple);
- strategy = aform->amopstrategy;
- Assert(strategy > 0 && strategy <= maxStrategyNumber);
- OperatorRelationFillScanKeyEntry(operatorRelation,
- aform->amopopr,
- StrategyMapGetScanKeyEntry(map, strategy));
+ amopform = (Form_pg_amop) GETSTRUCT(tuple);
+ FillScanKeyEntry(amopform->amopopr, mapentry);
+ ReleaseSysCache(tuple);
+ }
+ else
+ ScanKeyEntrySetIllegal(mapentry);
}
-
- heap_endscan(scan);
}
-
- heap_close(operatorRelation, AccessShareLock);
- heap_close(relation, AccessShareLock);
}
/* ----------------
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 28da7541d51..0265561856b 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.37 2001/08/10 18:57:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.38 2001/08/21 16:36:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -246,7 +246,7 @@ Boot_DeclareIndexStmt:
DefineIndex(LexIDStr($5),
LexIDStr($3),
LexIDStr($7),
- $9, NIL, 0, 0, 0, NIL);
+ $9, false, false, NULL, NIL);
do_end();
}
;
@@ -259,7 +259,7 @@ Boot_DeclareUniqueIndexStmt:
DefineIndex(LexIDStr($6),
LexIDStr($4),
LexIDStr($8),
- $10, NIL, 1, 0, 0, NIL);
+ $10, true, false, NULL, NIL);
do_end();
}
;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 4dbc1648c19..9ea03697b47 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.160 2001/08/17 23:50:00 inoue Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.161 2001/08/21 16:36:00 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -71,9 +71,9 @@ static void InitializeAttributeOids(Relation indexRelation,
int numatts, Oid indexoid);
static void AppendAttributeTuples(Relation indexRelation, int numatts);
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
- IndexInfo *indexInfo,
- Oid *classOids,
- bool islossy, bool primary);
+ IndexInfo *indexInfo,
+ Oid *classOids,
+ bool primary);
static Oid IndexGetRelation(Oid indexId);
static bool activate_index(Oid indexId, bool activate, bool inplace);
@@ -495,7 +495,6 @@ UpdateIndexRelation(Oid indexoid,
Oid heapoid,
IndexInfo *indexInfo,
Oid *classOids,
- bool islossy,
bool primary)
{
Form_pg_index indexForm;
@@ -535,8 +534,6 @@ UpdateIndexRelation(Oid indexoid,
indexForm->indrelid = heapoid;
indexForm->indproc = indexInfo->ii_FuncOid;
indexForm->indisclustered = false; /* not used */
- indexForm->indislossy = islossy;
- indexForm->indhaskeytype = true; /* used by GIST */
indexForm->indisunique = indexInfo->ii_Unique;
indexForm->indisprimary = primary;
memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
@@ -671,7 +668,6 @@ index_create(char *heapRelationName,
IndexInfo *indexInfo,
Oid accessMethodObjectId,
Oid *classObjectId,
- bool islossy,
bool primary,
bool allow_system_table_mods)
{
@@ -779,7 +775,7 @@ index_create(char *heapRelationName,
* ----------------
*/
UpdateIndexRelation(indexoid, heapoid, indexInfo,
- classObjectId, islossy, primary);
+ classObjectId, primary);
/*
* initialize the index strategy
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 361295fe8bc..28b85169473 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.81 2001/08/10 18:57:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.82 2001/08/21 16:36:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -36,9 +36,9 @@ char *Name_pg_aggregate_indices[Num_pg_aggregate_indices] =
char *Name_pg_am_indices[Num_pg_am_indices] =
{AmNameIndex, AmOidIndex};
char *Name_pg_amop_indices[Num_pg_amop_indices] =
-{AccessMethodOpidIndex, AccessMethodStrategyIndex};
+{AccessMethodOperatorIndex, AccessMethodStrategyIndex};
char *Name_pg_amproc_indices[Num_pg_amproc_indices] =
-{AccessProcedureIndex};
+{AccessMethodProcedureIndex};
char *Name_pg_attr_indices[Num_pg_attr_indices] =
{AttributeRelidNameIndex, AttributeRelidNumIndex};
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices] =
@@ -58,7 +58,7 @@ char *Name_pg_language_indices[Num_pg_language_indices] =
char *Name_pg_largeobject_indices[Num_pg_largeobject_indices] =
{LargeObjectLOidPNIndex};
char *Name_pg_opclass_indices[Num_pg_opclass_indices] =
-{OpclassDeftypeIndex, OpclassNameIndex, OpclassOidIndex};
+{OpclassAmNameIndex, OpclassOidIndex};
char *Name_pg_operator_indices[Num_pg_operator_indices] =
{OperatorOidIndex, OperatorNameIndex};
char *Name_pg_proc_indices[Num_pg_proc_indices] =
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 0d76c6e8d37..7d5d3e6cbdb 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.68 2001/08/10 18:57:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.69 2001/08/21 16:36:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -225,7 +225,6 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
indexInfo,
Old_pg_index_relation_Form->relam,
Old_pg_index_Form->indclass,
- Old_pg_index_Form->indislossy,
Old_pg_index_Form->indisprimary,
allowSystemTableMods);
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 1e8b7c56992..81ce6e11856 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.140 2001/08/10 18:57:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.141 2001/08/21 16:36:01 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
@@ -1902,12 +1902,12 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = true;
- classObjectId[0] = OID_OPS_OID;
- classObjectId[1] = INT4_OPS_OID;
+ classObjectId[0] = OID_BTREE_OPS_OID;
+ classObjectId[1] = INT4_BTREE_OPS_OID;
toast_idxid = index_create(toast_relname, toast_idxname, indexInfo,
BTREE_AM_OID, classObjectId,
- false, true, true);
+ true, true);
/*
* Update toast rel's pg_class entry to show that it has an index.
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 3b556da3ed5..2304dd0b0cd 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,26 +8,19 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.56 2001/08/10 18:57:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.57 2001/08/21 16:36:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/heap.h"
#include "catalog/index.h"
-#include "catalog/pg_am.h"
-#include "catalog/pg_amop.h"
-#include "catalog/pg_database.h"
-#include "catalog/pg_index.h"
#include "catalog/pg_opclass.h"
-#include "catalog/pg_operator.h"
-#include "catalog/pg_proc.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
@@ -36,7 +29,6 @@
#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
-#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
@@ -57,7 +49,7 @@ static void NormIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
char *accessMethodName, Oid accessMethodId);
static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
char *accessMethodName, Oid accessMethodId);
-static char *GetDefaultOpClass(Oid atttypid);
+static Oid GetDefaultOpClass(Oid attrType, Oid accessMethodId);
/*
* DefineIndex
@@ -65,16 +57,14 @@ static char *GetDefaultOpClass(Oid atttypid);
*
* 'attributeList' is a list of IndexElem specifying either a functional
* index or a list of attributes to index on.
- * 'parameterList' is a list of DefElem specified in the with clause.
* 'predicate' is the qual specified in the where clause.
- * 'rangetable' is needed to interpret the predicate
+ * 'rangetable' is needed to interpret the predicate.
*/
void
DefineIndex(char *heapRelationName,
char *indexRelationName,
char *accessMethodName,
List *attributeList,
- List *parameterList,
bool unique,
bool primary,
Expr *predicate,
@@ -88,8 +78,6 @@ DefineIndex(char *heapRelationName,
IndexInfo *indexInfo;
int numberOfAttributes;
List *cnfPred = NIL;
- bool lossy = false;
- List *pl;
/*
* count attributes in index
@@ -130,20 +118,6 @@ DefineIndex(char *heapRelationName,
ReleaseSysCache(tuple);
/*
- * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
- */
- foreach(pl, parameterList)
- {
- DefElem *param = (DefElem *) lfirst(pl);
-
- if (!strcasecmp(param->defname, "islossy"))
- lossy = true;
- else
- elog(NOTICE, "Unrecognized index attribute \"%s\" ignored",
- param->defname);
- }
-
- /*
* Convert the partial-index predicate from parsetree form to
* an implicit-AND qual expression, for easier evaluation at runtime.
* While we are at it, we reduce it to a canonical (CNF or DNF) form
@@ -203,7 +177,7 @@ DefineIndex(char *heapRelationName,
index_create(heapRelationName, indexRelationName,
indexInfo, accessMethodId, classObjectId,
- lossy, primary, allowSystemTableMods);
+ primary, allowSystemTableMods);
/*
* We update the relation's pg_class tuple even if it already has
@@ -390,111 +364,109 @@ static Oid
GetAttrOpClass(IndexElem *attribute, Oid attrType,
char *accessMethodName, Oid accessMethodId)
{
- Relation relation;
- HeapScanDesc scan;
- ScanKeyData entry[2];
HeapTuple tuple;
Oid opClassId,
- oprId;
- bool doTypeCheck = true;
+ opInputType;
if (attribute->class == NULL)
{
/* no operator class specified, so find the default */
- attribute->class = GetDefaultOpClass(attrType);
- if (attribute->class == NULL)
- elog(ERROR, "data type %s has no default operator class"
+ opClassId = GetDefaultOpClass(attrType, accessMethodId);
+ if (!OidIsValid(opClassId))
+ elog(ERROR, "data type %s has no default operator class for access method \"%s\""
"\n\tYou must specify an operator class for the index or define a"
"\n\tdefault operator class for the data type",
- format_type_be(attrType));
- /* assume we need not check type compatibility */
- doTypeCheck = false;
+ format_type_be(attrType), accessMethodName);
+ return opClassId;
}
- opClassId = GetSysCacheOid(CLANAME,
- PointerGetDatum(attribute->class),
- 0, 0, 0);
- if (!OidIsValid(opClassId))
- elog(ERROR, "DefineIndex: opclass \"%s\" not found",
- attribute->class);
-
/*
- * Assume the opclass is supported by this index access method if we
- * can find at least one relevant entry in pg_amop.
+ * Find the index operator class and verify that it accepts this
+ * datatype. Note we will accept binary compatibility.
*/
- ScanKeyEntryInitialize(&entry[0], 0,
- Anum_pg_amop_amopid,
- F_OIDEQ,
- ObjectIdGetDatum(accessMethodId));
- ScanKeyEntryInitialize(&entry[1], 0,
- Anum_pg_amop_amopclaid,
- F_OIDEQ,
- ObjectIdGetDatum(opClassId));
-
- relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
- scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
-
- if (!HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
- elog(ERROR, "DefineIndex: opclass \"%s\" not supported by access method \"%s\"",
+ tuple = SearchSysCache(CLAAMNAME,
+ ObjectIdGetDatum(accessMethodId),
+ PointerGetDatum(attribute->class),
+ 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "DefineIndex: operator class \"%s\" not supported by access method \"%s\"",
attribute->class, accessMethodName);
+ opClassId = tuple->t_data->t_oid;
+ opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
+ ReleaseSysCache(tuple);
- oprId = ((Form_pg_amop) GETSTRUCT(tuple))->amopopr;
+ if (attrType != opInputType &&
+ !IS_BINARY_COMPATIBLE(attrType, opInputType))
+ elog(ERROR, "operator class \"%s\" does not accept data type %s",
+ attribute->class, format_type_be(attrType));
- heap_endscan(scan);
- heap_close(relation, AccessShareLock);
+ return opClassId;
+}
+
+static Oid
+GetDefaultOpClass(Oid attrType, Oid accessMethodId)
+{
+ Relation relation;
+ ScanKeyData entry[1];
+ HeapScanDesc scan;
+ HeapTuple tuple;
+ int nexact = 0;
+ int ncompatible = 0;
+ Oid exactOid = InvalidOid;
+ Oid compatibleOid = InvalidOid;
/*
- * Make sure the operators associated with this opclass actually
- * accept the column data type. This prevents possible coredumps
- * caused by user errors like applying text_ops to an int4 column. We
- * will accept an opclass as OK if the operator's input datatype is
- * binary-compatible with the actual column datatype. Note we assume
- * that all the operators associated with an opclass accept the same
- * datatypes, so checking the first one we happened to find in the
- * table is sufficient.
+ * We scan through all the opclasses available for the access method,
+ * looking for one that is marked default and matches the target type
+ * (either exactly or binary-compatibly, but prefer an exact match).
+ *
+ * We could find more than one binary-compatible match, in which case we
+ * require the user to specify which one he wants. If we find more than
+ * one exact match, then someone put bogus entries in pg_opclass.
*
- * If the opclass was the default for the datatype, assume we can skip
- * this check --- that saves a few cycles in the most common case. If
- * pg_opclass is wrong then we're probably screwed anyway...
+ * We could use an indexscan here, but since pg_opclass is small
+ * and a scan on opcamid won't be very selective, the indexscan would
+ * probably actually be slower than heapscan.
*/
- if (doTypeCheck)
+ ScanKeyEntryInitialize(&entry[0], 0x0,
+ Anum_pg_opclass_opcamid,
+ F_OIDEQ,
+ ObjectIdGetDatum(accessMethodId));
+
+ relation = heap_openr(OperatorClassRelationName, AccessShareLock);
+ scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
+
+ while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
{
- tuple = SearchSysCache(OPEROID,
- ObjectIdGetDatum(oprId),
- 0, 0, 0);
- if (HeapTupleIsValid(tuple))
+ Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tuple);
+
+ if (opclass->opcdefault)
{
- Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tuple);
- Oid opInputType = (optup->oprkind == 'l') ?
- optup->oprright : optup->oprleft;
-
- if (attrType != opInputType &&
- !IS_BINARY_COMPATIBLE(attrType, opInputType))
- elog(ERROR, "operator class \"%s\" does not accept data type %s",
- attribute->class, format_type_be(attrType));
- ReleaseSysCache(tuple);
+ if (opclass->opcintype == attrType)
+ {
+ nexact++;
+ exactOid = tuple->t_data->t_oid;
+ }
+ else if (IS_BINARY_COMPATIBLE(opclass->opcintype, attrType))
+ {
+ ncompatible++;
+ compatibleOid = tuple->t_data->t_oid;
+ }
}
}
- return opClassId;
-}
-
-static char *
-GetDefaultOpClass(Oid atttypid)
-{
- HeapTuple tuple;
- char *result;
-
- tuple = SearchSysCache(CLADEFTYPE,
- ObjectIdGetDatum(atttypid),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- return NULL;
+ heap_endscan(scan);
+ heap_close(relation, AccessShareLock);
- result = pstrdup(NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname));
+ if (nexact == 1)
+ return exactOid;
+ if (nexact != 0)
+ elog(ERROR, "pg_opclass contains multiple default opclasses for data tyype %s",
+ format_type_be(attrType));
+ if (ncompatible == 1)
+ return compatibleOid;
- ReleaseSysCache(tuple);
- return result;
+ return InvalidOid;
}
/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 68ad14119f1..26da8d47937 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.153 2001/08/16 20:38:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.154 2001/08/21 16:36:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1166,7 +1166,6 @@ _copyIndexOptInfo(IndexOptInfo *from)
newnode->indproc = from->indproc;
Node_Copy(from, newnode, indpred);
newnode->unique = from->unique;
- newnode->lossy = from->lossy;
return newnode;
}
@@ -2059,7 +2058,6 @@ _copyIndexStmt(IndexStmt *from)
newnode->relname = pstrdup(from->relname);
newnode->accessMethod = pstrdup(from->accessMethod);
Node_Copy(from, newnode, indexParams);
- Node_Copy(from, newnode, withClause);
Node_Copy(from, newnode, whereClause);
Node_Copy(from, newnode, rangetable);
newnode->unique = from->unique;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 80ffc01dc1e..c2cd2109fe9 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.101 2001/08/16 20:38:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.102 2001/08/21 16:36:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -926,8 +926,6 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
return false;
if (!equal(a->indexParams, b->indexParams))
return false;
- if (!equal(a->withClause, b->withClause))
- return false;
if (!equal(a->whereClause, b->whereClause))
return false;
if (!equal(a->rangetable, b->rangetable))
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 335a1eb606a..5b30fd2a21d 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.144 2001/08/16 20:38:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.145 2001/08/21 16:36:02 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
@@ -133,16 +133,10 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
_outToken(str, node->accessMethod);
appendStringInfo(str, " :indexParams ");
_outNode(str, node->indexParams);
-
- appendStringInfo(str, " :withClause ");
- _outNode(str, node->withClause);
-
appendStringInfo(str, " :whereClause ");
_outNode(str, node->whereClause);
-
appendStringInfo(str, " :rangetable ");
_outNode(str, node->rangetable);
-
appendStringInfo(str, " :unique %s :primary %s ",
booltostr(node->unique),
booltostr(node->primary));
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 2099adc664c..73d72a03cb3 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -42,7 +42,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.77 2001/06/11 00:17:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.78 2001/08/21 16:36:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -339,16 +339,16 @@ cost_index(Path *path, Query *root,
*
* Normally the indexquals will be removed from the list of
* restriction clauses that we have to evaluate as qpquals, so we
- * should subtract their costs from baserestrictcost. For a lossy
- * index, however, we will have to recheck all the quals and so
- * mustn't subtract anything. Also, if we are doing a join then some
- * of the indexquals are join clauses and shouldn't be subtracted.
- * Rather than work out exactly how much to subtract, we don't
- * subtract anything in that case either.
+ * should subtract their costs from baserestrictcost. XXX For a lossy
+ * index, not all the quals will be removed and so we really shouldn't
+ * subtract their costs; but detecting that seems more expensive than
+ * it's worth. Also, if we are doing a join then some of the indexquals
+ * are join clauses and shouldn't be subtracted. Rather than work out
+ * exactly how much to subtract, we don't subtract anything.
*/
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost;
- if (!index->lossy && !is_injoin)
+ if (!is_injoin)
cpu_per_tuple -= cost_qual_eval(indexQuals);
run_cost += cpu_per_tuple * tuples_fetched;
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 8c0b8948348..f30097ec282 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.110 2001/08/06 18:09:45 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.111 2001/08/21 16:36:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,16 +46,16 @@
*
* Determine whether we should continue matching index keys in a clause.
* Depends on if there are more to match or if this is a functional index.
- * In the latter case we stop after the first match since the there can
- * be only key (i.e. the function's return value) and the attributes in
+ * In the latter case we stop after the first match since there can
+ * be only 1 key (i.e. the function's return value) and the attributes in
* keys list represent the arguments to the function. -mer 3 Oct. 1991
*/
#define DoneMatchingIndexKeys(indexkeys, index) \
(indexkeys[0] == 0 || \
(index->indproc != InvalidOid))
-#define is_indexable_operator(clause,opclass,relam,indexkey_on_left) \
- (indexable_operator(clause,opclass,relam,indexkey_on_left) != InvalidOid)
+#define is_indexable_operator(clause,opclass,indexkey_on_left) \
+ (indexable_operator(clause,opclass,indexkey_on_left) != InvalidOid)
static void match_index_orclauses(RelOptInfo *rel, IndexOptInfo *index,
@@ -92,7 +92,7 @@ static bool match_index_to_operand(int indexkey, Var *operand,
RelOptInfo *rel, IndexOptInfo *index);
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
IndexOptInfo *index);
-static bool match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
+static bool match_special_index_operator(Expr *clause, Oid opclass,
bool indexkey_on_left);
static List *prefix_quals(Var *leftop, Oid expr_op,
char *prefix, Pattern_Prefix_Status pstatus);
@@ -754,30 +754,28 @@ match_clause_to_indexkey(RelOptInfo *rel,
if (match_index_to_operand(indexkey, leftop, rel, index) &&
is_pseudo_constant_clause((Node *) rightop))
{
- if (is_indexable_operator(clause, opclass, index->relam, true))
+ if (is_indexable_operator(clause, opclass, true))
return true;
/*
* If we didn't find a member of the index's opclass, see
* whether it is a "special" indexable operator.
*/
- if (match_special_index_operator(clause, opclass, index->relam,
- true))
+ if (match_special_index_operator(clause, opclass, true))
return true;
return false;
}
if (match_index_to_operand(indexkey, rightop, rel, index) &&
is_pseudo_constant_clause((Node *) leftop))
{
- if (is_indexable_operator(clause, opclass, index->relam, false))
+ if (is_indexable_operator(clause, opclass, false))
return true;
/*
* If we didn't find a member of the index's opclass, see
* whether it is a "special" indexable operator.
*/
- if (match_special_index_operator(clause, opclass, index->relam,
- false))
+ if (match_special_index_operator(clause, opclass, false))
return true;
return false;
}
@@ -799,7 +797,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
isIndexable =
!intMember(lfirsti(rel->relids), othervarnos) &&
!contain_noncachable_functions((Node *) rightop) &&
- is_indexable_operator(clause, opclass, index->relam, true);
+ is_indexable_operator(clause, opclass, true);
freeList(othervarnos);
return isIndexable;
}
@@ -811,7 +809,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
isIndexable =
!intMember(lfirsti(rel->relids), othervarnos) &&
!contain_noncachable_functions((Node *) leftop) &&
- is_indexable_operator(clause, opclass, index->relam, false);
+ is_indexable_operator(clause, opclass, false);
freeList(othervarnos);
return isIndexable;
}
@@ -822,12 +820,11 @@ match_clause_to_indexkey(RelOptInfo *rel,
/*
* indexable_operator
- * Does a binary opclause contain an operator matching the index's
- * access method?
+ * Does a binary opclause contain an operator matching the index opclass?
*
* If the indexkey is on the right, what we actually want to know
* is whether the operator has a commutator operator that matches
- * the index's access method.
+ * the index's opclass.
*
* We try both the straightforward match and matches that rely on
* recognizing binary-compatible datatypes. For example, if we have
@@ -844,8 +841,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
* OID is *not* commuted; it can be plugged directly into the given clause.
*/
Oid
-indexable_operator(Expr *clause, Oid opclass, Oid relam,
- bool indexkey_on_left)
+indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
{
Oid expr_op = ((Oper *) clause->oper)->opno;
Oid commuted_op,
@@ -865,8 +861,8 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
if (commuted_op == InvalidOid)
return InvalidOid;
- /* Done if the (commuted) operator is a member of the index's AM */
- if (op_class(commuted_op, opclass, relam))
+ /* Done if the (commuted) operator is a member of the index's opclass */
+ if (op_in_opclass(commuted_op, opclass))
return expr_op;
/*
@@ -937,7 +933,7 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
if (commuted_op == InvalidOid)
return InvalidOid;
- if (op_class(commuted_op, opclass, relam))
+ if (op_in_opclass(commuted_op, opclass))
return new_op;
}
}
@@ -1171,8 +1167,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
Oid pred_op,
clause_op,
test_op;
- Oid opclass_id;
- StrategyNumber pred_strategy,
+ Oid opclass_id = InvalidOid;
+ StrategyNumber pred_strategy = 0,
clause_strategy,
test_strategy;
Oper *test_oper;
@@ -1182,7 +1178,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
Relation relation;
HeapScanDesc scan;
HeapTuple tuple;
- ScanKeyData entry[3];
+ ScanKeyData entry[1];
Form_pg_amop aform;
ExprContext *econtext;
@@ -1227,23 +1223,6 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
/*
* 1. Find a "btree" strategy number for the pred_op
*
- * XXX consider using syscache lookups for these searches. Right
- * now we don't have caches that match all of the search conditions,
- * but reconsider it after upcoming restructuring of pg_opclass.
- */
- relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
-
- ScanKeyEntryInitialize(&entry[0], 0,
- Anum_pg_amop_amopid,
- F_OIDEQ,
- ObjectIdGetDatum(BTREE_AM_OID));
-
- ScanKeyEntryInitialize(&entry[1], 0,
- Anum_pg_amop_amopopr,
- F_OIDEQ,
- ObjectIdGetDatum(pred_op));
-
- /*
* The following assumes that any given operator will only be in a
* single btree operator class. This is true at least for all the
* pre-defined operator classes. If it isn't true, then whichever
@@ -1251,46 +1230,47 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
* will be used to find the associated strategy numbers for the test.
* --Nels, Jan '93
*/
- scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
- tuple = heap_getnext(scan, 0);
- if (!HeapTupleIsValid(tuple))
+ ScanKeyEntryInitialize(&entry[0], 0x0,
+ Anum_pg_amop_amopopr,
+ F_OIDEQ,
+ ObjectIdGetDatum(pred_op));
+
+ relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
+ scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
+
+ while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
{
- /* predicate operator isn't btree-indexable */
- heap_endscan(scan);
- heap_close(relation, AccessShareLock);
- return false;
+ aform = (Form_pg_amop) GETSTRUCT(tuple);
+ if (opclass_is_btree(aform->amopclaid))
+ {
+ /* Get the predicate operator's btree strategy number (1 to 5) */
+ pred_strategy = (StrategyNumber) aform->amopstrategy;
+ Assert(pred_strategy >= 1 && pred_strategy <= 5);
+ /* Remember which operator class this strategy number came from */
+ opclass_id = aform->amopclaid;
+ break;
+ }
}
- aform = (Form_pg_amop) GETSTRUCT(tuple);
-
- /* Get the predicate operator's btree strategy number (1 to 5) */
- pred_strategy = (StrategyNumber) aform->amopstrategy;
- Assert(pred_strategy >= 1 && pred_strategy <= 5);
-
- /* Remember which operator class this strategy number came from */
- opclass_id = aform->amopclaid;
heap_endscan(scan);
+ heap_close(relation, AccessShareLock);
+
+ if (!OidIsValid(opclass_id))
+ {
+ /* predicate operator isn't btree-indexable */
+ return false;
+ }
/*
* 2. From the same opclass, find a strategy num for the clause_op
*/
- ScanKeyEntryInitialize(&entry[1], 0,
- Anum_pg_amop_amopclaid,
- F_OIDEQ,
- ObjectIdGetDatum(opclass_id));
-
- ScanKeyEntryInitialize(&entry[2], 0,
- Anum_pg_amop_amopopr,
- F_OIDEQ,
- ObjectIdGetDatum(clause_op));
-
- scan = heap_beginscan(relation, false, SnapshotNow, 3, entry);
- tuple = heap_getnext(scan, 0);
+ tuple = SearchSysCache(AMOPOPID,
+ ObjectIdGetDatum(opclass_id),
+ ObjectIdGetDatum(clause_op),
+ 0, 0);
if (!HeapTupleIsValid(tuple))
{
/* clause operator isn't btree-indexable, or isn't in this opclass */
- heap_endscan(scan);
- heap_close(relation, AccessShareLock);
return false;
}
aform = (Form_pg_amop) GETSTRUCT(tuple);
@@ -1299,7 +1279,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
clause_strategy = (StrategyNumber) aform->amopstrategy;
Assert(clause_strategy >= 1 && clause_strategy <= 5);
- heap_endscan(scan);
+ ReleaseSysCache(tuple);
/*
* 3. Look up the "test" strategy number in the implication table
@@ -1307,26 +1287,20 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
if (test_strategy == 0)
{
- heap_close(relation, AccessShareLock);
return false; /* the implication cannot be determined */
}
/*
* 4. From the same opclass, find the operator for the test strategy
*/
- ScanKeyEntryInitialize(&entry[2], 0,
- Anum_pg_amop_amopstrategy,
- F_INT2EQ,
- Int16GetDatum(test_strategy));
-
- scan = heap_beginscan(relation, false, SnapshotNow, 3, entry);
- tuple = heap_getnext(scan, 0);
+ tuple = SearchSysCache(AMOPSTRATEGY,
+ ObjectIdGetDatum(opclass_id),
+ Int16GetDatum(test_strategy),
+ 0, 0);
if (!HeapTupleIsValid(tuple))
{
/* this probably shouldn't fail? */
elog(DEBUG, "pred_test_simple_clause: unknown test_op");
- heap_endscan(scan);
- heap_close(relation, AccessShareLock);
return false;
}
aform = (Form_pg_amop) GETSTRUCT(tuple);
@@ -1334,9 +1308,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
/* Get the test operator */
test_op = aform->amopopr;
- heap_endscan(scan);
-
- heap_close(relation, AccessShareLock);
+ ReleaseSysCache(tuple);
/*
* 5. Evaluate the test
@@ -1681,7 +1653,7 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
* Return 'true' if we can do something with it anyway.
*/
static bool
-match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
+match_special_index_operator(Expr *clause, Oid opclass,
bool indexkey_on_left)
{
bool isIndexable = false;
@@ -1806,8 +1778,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_TEXT_ICLIKE_OP:
case OID_TEXT_REGEXEQ_OP:
case OID_TEXT_ICREGEXEQ_OP:
- if (!op_class(find_operator(">=", TEXTOID), opclass, relam) ||
- !op_class(find_operator("<", TEXTOID), opclass, relam))
+ if (!op_in_opclass(find_operator(">=", TEXTOID), opclass) ||
+ !op_in_opclass(find_operator("<", TEXTOID), opclass))
isIndexable = false;
break;
@@ -1815,8 +1787,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_BPCHAR_ICLIKE_OP:
case OID_BPCHAR_REGEXEQ_OP:
case OID_BPCHAR_ICREGEXEQ_OP:
- if (!op_class(find_operator(">=", BPCHAROID), opclass, relam) ||
- !op_class(find_operator("<", BPCHAROID), opclass, relam))
+ if (!op_in_opclass(find_operator(">=", BPCHAROID), opclass) ||
+ !op_in_opclass(find_operator("<", BPCHAROID), opclass))
isIndexable = false;
break;
@@ -1824,8 +1796,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_VARCHAR_ICLIKE_OP:
case OID_VARCHAR_REGEXEQ_OP:
case OID_VARCHAR_ICREGEXEQ_OP:
- if (!op_class(find_operator(">=", VARCHAROID), opclass, relam) ||
- !op_class(find_operator("<", VARCHAROID), opclass, relam))
+ if (!op_in_opclass(find_operator(">=", VARCHAROID), opclass) ||
+ !op_in_opclass(find_operator("<", VARCHAROID), opclass))
isIndexable = false;
break;
@@ -1833,24 +1805,24 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_NAME_ICLIKE_OP:
case OID_NAME_REGEXEQ_OP:
case OID_NAME_ICREGEXEQ_OP:
- if (!op_class(find_operator(">=", NAMEOID), opclass, relam) ||
- !op_class(find_operator("<", NAMEOID), opclass, relam))
+ if (!op_in_opclass(find_operator(">=", NAMEOID), opclass) ||
+ !op_in_opclass(find_operator("<", NAMEOID), opclass))
isIndexable = false;
break;
case OID_INET_SUB_OP:
case OID_INET_SUBEQ_OP:
/* for SUB we actually need ">" not ">=", but this should do */
- if (!op_class(find_operator(">=", INETOID), opclass, relam) ||
- !op_class(find_operator("<=", INETOID), opclass, relam))
+ if (!op_in_opclass(find_operator(">=", INETOID), opclass) ||
+ !op_in_opclass(find_operator("<=", INETOID), opclass))
isIndexable = false;
break;
case OID_CIDR_SUB_OP:
case OID_CIDR_SUBEQ_OP:
/* for SUB we actually need ">" not ">=", but this should do */
- if (!op_class(find_operator(">=", CIDROID), opclass, relam) ||
- !op_class(find_operator("<=", CIDROID), opclass, relam))
+ if (!op_in_opclass(find_operator(">=", CIDROID), opclass) ||
+ !op_in_opclass(find_operator("<=", CIDROID), opclass))
isIndexable = false;
break;
}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 78e22c7b9e3..9a32ae7a1b9 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.107 2001/06/05 05:26:04 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.108 2001/08/21 16:36:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -56,9 +56,12 @@ static HashJoin *create_hashjoin_plan(HashPath *best_path, List *tlist,
List *joinclauses, List *otherclauses,
Plan *outer_plan, List *outer_tlist,
Plan *inner_plan, List *inner_tlist);
-static List *fix_indxqual_references(List *indexquals, IndexPath *index_path);
-static List *fix_indxqual_sublist(List *indexqual, int baserelid,
- IndexOptInfo *index);
+static void fix_indxqual_references(List *indexquals, IndexPath *index_path,
+ List **fixed_indexquals,
+ List **recheck_indexquals);
+static void fix_indxqual_sublist(List *indexqual, int baserelid,
+ IndexOptInfo *index,
+ List **fixed_quals, List **recheck_quals);
static Node *fix_indxqual_operand(Node *node, int baserelid,
IndexOptInfo *index,
Oid *opclass);
@@ -381,11 +384,12 @@ create_indexscan_plan(Query *root,
List *indxqual = best_path->indexqual;
Index baserelid;
List *qpqual;
+ Expr *indxqual_or_expr = NULL;
List *fixed_indxqual;
+ List *recheck_indxqual;
List *indexids;
List *ixinfo;
IndexScan *scan_plan;
- bool lossy;
/* there should be exactly one base rel involved... */
Assert(length(best_path->path.parent->relids) == 1);
@@ -394,25 +398,23 @@ create_indexscan_plan(Query *root,
baserelid = lfirsti(best_path->path.parent->relids);
/*
- * Build list of index OIDs, and check to see if any of the indices
- * are lossy.
+ * Build list of index OIDs.
*/
indexids = NIL;
- lossy = false;
foreach(ixinfo, best_path->indexinfo)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
indexids = lappendi(indexids, index->indexoid);
- lossy |= index->lossy;
}
/*
* The qpqual list must contain all restrictions not automatically
- * handled by the index. Note that for non-lossy indices, the
- * predicates in the indxqual are checked fully by the index, while
- * for lossy indices the indxqual predicates need to be double-checked
- * after the index fetches the best-guess tuples.
+ * handled by the index. Normally the predicates in the indxqual
+ * are checked fully by the index, but if the index is "lossy" for
+ * a particular operator (as signaled by the amopreqcheck flag in
+ * pg_amop), then we need to double-check that predicate in qpqual,
+ * because the index may return more tuples than match the predicate.
*
* Since the indexquals were generated from the restriction clauses given
* by scan_clauses, there will normally be some duplications between
@@ -420,7 +422,6 @@ create_indexscan_plan(Query *root,
*/
if (length(indxqual) > 1)
{
-
/*
* Build an expression representation of the indexqual, expanding
* the implicit OR and AND semantics of the first- and
@@ -428,32 +429,24 @@ create_indexscan_plan(Query *root,
*/
List *orclauses = NIL;
List *orclause;
- Expr *indxqual_expr;
foreach(orclause, indxqual)
+ {
orclauses = lappend(orclauses,
make_ands_explicit(lfirst(orclause)));
- indxqual_expr = make_orclause(orclauses);
-
- qpqual = set_difference(scan_clauses, makeList1(indxqual_expr));
+ }
+ indxqual_or_expr = make_orclause(orclauses);
- if (lossy)
- qpqual = lappend(qpqual, copyObject(indxqual_expr));
+ qpqual = set_difference(scan_clauses, makeList1(indxqual_or_expr));
}
else if (indxqual != NIL)
{
-
/*
* Here, we can simply treat the first sublist as an independent
* set of qual expressions, since there is no top-level OR
* behavior.
*/
- List *indxqual_list = lfirst(indxqual);
-
- qpqual = set_difference(scan_clauses, indxqual_list);
-
- if (lossy)
- qpqual = nconc(qpqual, (List *) copyObject(indxqual_list));
+ qpqual = set_difference(scan_clauses, lfirst(indxqual));
}
else
qpqual = scan_clauses;
@@ -461,9 +454,35 @@ create_indexscan_plan(Query *root,
/*
* The executor needs a copy with the indexkey on the left of each
* clause and with index attr numbers substituted for table ones.
+ * This pass also looks for "lossy" operators.
*/
- fixed_indxqual = fix_indxqual_references(indxqual, best_path);
+ fix_indxqual_references(indxqual, best_path,
+ &fixed_indxqual, &recheck_indxqual);
+ /*
+ * If there were any "lossy" operators, need to add back the appropriate
+ * qual clauses to the qpqual. When there is just one indexscan being
+ * performed (ie, we have simple AND semantics), we can just add the
+ * lossy clauses themselves to qpqual. If we have OR-of-ANDs, we'd
+ * better add the entire original indexqual to make sure that the
+ * semantics are correct.
+ */
+ if (recheck_indxqual != NIL)
+ {
+ if (indxqual_or_expr)
+ {
+ /* Better do a deep copy of the original scanclauses */
+ qpqual = lappend(qpqual, copyObject(indxqual_or_expr));
+ }
+ else
+ {
+ /* Subroutine already copied quals, so just append to list */
+ Assert(length(recheck_indxqual) == 1);
+ qpqual = nconc(qpqual, (List *) lfirst(recheck_indxqual));
+ }
+ }
+
+ /* Finally ready to build the plan node */
scan_plan = make_indexscan(tlist,
qpqual,
baserelid,
@@ -868,9 +887,9 @@ create_hashjoin_plan(HashPath *best_path,
/*
* fix_indxqual_references
* Adjust indexqual clauses to the form the executor's indexqual
- * machinery needs.
+ * machinery needs, and check for recheckable (lossy) index conditions.
*
- * We have three tasks here:
+ * We have four tasks here:
* * Index keys must be represented by Var nodes with varattno set to the
* index's attribute number, not the attribute number in the original rel.
* * indxpath.c may have selected an index that is binary-compatible with
@@ -879,20 +898,34 @@ create_hashjoin_plan(HashPath *best_path,
* equivalent operator that the index will recognize.
* * If the index key is on the right, commute the clause to put it on the
* left. (Someday the executor might not need this, but for now it does.)
+ * * If the indexable operator is marked 'amopreqcheck' in pg_amop, then
+ * the index is "lossy" for this operator: it may return more tuples than
+ * actually satisfy the operator condition. For each such operator, we
+ * must add (the original form of) the indexqual clause to the "qpquals"
+ * of the indexscan node, where the operator will be re-evaluated to
+ * ensure it passes.
*
* This code used to be entirely bogus for multi-index scans. Now it keeps
* track of which index applies to each subgroup of index qual clauses...
*
- * Returns a modified copy of the indexqual list --- the original is not
- * changed. Note also that the copy shares no substructure with the
- * original; this is needed in case there is a subplan in it (we need
+ * Both the input list and the output lists have the form of lists of sublists
+ * of qual clauses --- the top-level list has one entry for each indexscan
+ * to be performed. The semantics are OR-of-ANDs.
+ *
+ * fixed_indexquals receives a modified copy of the indexqual list --- the
+ * original is not changed. Note also that the copy shares no substructure
+ * with the original; this is needed in case there is a subplan in it (we need
* two separate copies of the subplan tree, or things will go awry).
+ *
+ * recheck_indexquals similarly receives a full copy of whichever clauses
+ * need rechecking.
*/
-
-static List *
-fix_indxqual_references(List *indexquals, IndexPath *index_path)
+static void
+fix_indxqual_references(List *indexquals, IndexPath *index_path,
+ List **fixed_indexquals, List **recheck_indexquals)
{
List *fixed_quals = NIL;
+ List *recheck_quals = NIL;
int baserelid = lfirsti(index_path->path.parent->relids);
List *ixinfo = index_path->indexinfo;
List *i;
@@ -901,14 +934,20 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
{
List *indexqual = lfirst(i);
IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
+ List *fixed_qual;
+ List *recheck_qual;
+
+ fix_indxqual_sublist(indexqual, baserelid, index,
+ &fixed_qual, &recheck_qual);
+ fixed_quals = lappend(fixed_quals, fixed_qual);
+ if (recheck_qual != NIL)
+ recheck_quals = lappend(recheck_quals, recheck_qual);
- fixed_quals = lappend(fixed_quals,
- fix_indxqual_sublist(indexqual,
- baserelid,
- index));
ixinfo = lnext(ixinfo);
}
- return fixed_quals;
+
+ *fixed_indexquals = fixed_quals;
+ *recheck_indexquals = recheck_quals;
}
/*
@@ -916,12 +955,19 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
*
* For each qual clause, commute if needed to put the indexkey operand on the
* left, and then fix its varattno. (We do not need to change the other side
- * of the clause.) Also change the operator if necessary.
+ * of the clause.) Also change the operator if necessary, and check for
+ * lossy index behavior.
+ *
+ * Returns two lists: the list of fixed indexquals, and the list (usually
+ * empty) of original clauses that must be rechecked as qpquals because
+ * the index is lossy for this operator type.
*/
-static List *
-fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index)
+static void
+fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
+ List **fixed_quals, List **recheck_quals)
{
List *fixed_qual = NIL;
+ List *recheck_qual = NIL;
List *i;
foreach(i, indexqual)
@@ -968,14 +1014,24 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index)
* is merely binary-compatible with the index. This shouldn't
* fail, since indxpath.c found it before...
*/
- newopno = indexable_operator(newclause, opclass, index->relam, true);
+ newopno = indexable_operator(newclause, opclass, true);
if (newopno == InvalidOid)
elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
((Oper *) newclause->oper)->opno = newopno;
fixed_qual = lappend(fixed_qual, newclause);
+
+ /*
+ * Finally, check to see if index is lossy for this operator.
+ * If so, add (a copy of) original form of clause to recheck list.
+ */
+ if (op_requires_recheck(newopno, opclass))
+ recheck_qual = lappend(recheck_qual,
+ copyObject((Node *) clause));
}
- return fixed_qual;
+
+ *fixed_quals = fixed_qual;
+ *recheck_quals = recheck_qual;
}
static Node *
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 3f537fb0d9b..6d609853aa4 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.67 2001/07/15 22:48:18 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.68 2001/08/21 16:36:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -103,8 +103,7 @@ find_secondary_indexes(Oid relationObjectId)
IndexOptInfo *info;
int i;
Relation indexRelation;
- Oid relam;
- uint16 amorderstrategy;
+ int16 amorderstrategy;
indexTuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexoid),
@@ -138,7 +137,6 @@ find_secondary_indexes(Oid relationObjectId)
else
info->indpred = NIL;
info->unique = index->indisunique;
- info->lossy = index->indislossy;
for (i = 0; i < INDEX_MAX_KEYS; i++)
{
@@ -160,8 +158,7 @@ find_secondary_indexes(Oid relationObjectId)
/* Extract info from the relation descriptor for the index */
indexRelation = index_open(index->indexrelid);
- relam = indexRelation->rd_rel->relam;
- info->relam = relam;
+ info->relam = indexRelation->rd_rel->relam;
info->pages = indexRelation->rd_rel->relpages;
info->tuples = indexRelation->rd_rel->reltuples;
info->amcostestimate = index_cost_estimator(indexRelation);
@@ -181,14 +178,12 @@ find_secondary_indexes(Oid relationObjectId)
amopTuple =
SearchSysCache(AMOPSTRATEGY,
- ObjectIdGetDatum(relam),
ObjectIdGetDatum(index->indclass[i]),
- UInt16GetDatum(amorderstrategy),
- 0);
+ Int16GetDatum(amorderstrategy),
+ 0, 0);
if (!HeapTupleIsValid(amopTuple))
- elog(ERROR, "find_secondary_indexes: no amop %u %u %d",
- relam, index->indclass[i],
- (int) amorderstrategy);
+ elog(ERROR, "find_secondary_indexes: no amop %u %d",
+ index->indclass[i], (int) amorderstrategy);
amop = (Form_pg_amop) GETSTRUCT(amopTuple);
info->ordering[i] = amop->amopopr;
ReleaseSysCache(amopTuple);
@@ -370,7 +365,7 @@ has_unique_index(RelOptInfo *rel, AttrNumber attno)
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
/*
- * Note: ignore functional, partial, or lossy indexes, since they
+ * Note: ignore functional and partial indexes, since they
* don't allow us to conclude that all attr values are distinct.
* Also, a multicolumn unique index doesn't allow us to conclude
* that just the specified attr is unique.
@@ -379,8 +374,7 @@ has_unique_index(RelOptInfo *rel, AttrNumber attno)
index->nkeys == 1 &&
index->indexkeys[0] == attno &&
index->indproc == InvalidOid &&
- index->indpred == NIL &&
- !index->lossy)
+ index->indpred == NIL)
return true;
}
return false;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 7604d42a039..6c5e5f7e0de 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.195 2001/08/16 20:38:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.196 2001/08/21 16:36:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -995,7 +995,6 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
index->relname = stmt->relname;
index->accessMethod = "btree";
index->indexParams = NIL;
- index->withClause = NIL;
index->whereClause = NULL;
foreach(keys, constraint->keys)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6cd7f064803..ada73b1e7ca 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.246 2001/08/16 20:38:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.247 2001/08/21 16:36:03 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -2399,13 +2399,12 @@ RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list
* QUERY:
* create index <indexname> on <relname>
* [ using <access> ] "(" (<col> with <op>)+ ")"
- * [ with <parameters> ]
* [ where <predicate> ]
*
*****************************************************************************/
IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
- access_method_clause '(' index_params ')' opt_with where_clause
+ access_method_clause '(' index_params ')' where_clause
{
IndexStmt *n = makeNode(IndexStmt);
n->unique = $2;
@@ -2413,8 +2412,7 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
n->relname = $6;
n->accessMethod = $7;
n->indexParams = $9;
- n->withClause = $11;
- n->whereClause = $12;
+ n->whereClause = $11;
$$ = (Node *)n;
}
;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index a791a67715e..c05546fb8ec 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.115 2001/07/16 05:06:58 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.116 2001/08/21 16:36:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -538,7 +538,6 @@ ProcessUtility(Node *parsetree,
stmt->idxname, /* index name */
stmt->accessMethod, /* am name */
stmt->indexParams, /* parameters */
- stmt->withClause,
stmt->unique,
stmt->primary,
(Expr *) stmt->whereClause,
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index eb6ab3f4646..3ae65c6c8e5 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.62 2001/06/22 19:16:23 wieck Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.63 2001/08/21 16:36:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,12 +19,12 @@
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_proc.h"
-#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
+
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
@@ -32,126 +32,103 @@
/*
* regprocin - converts "proname" or "proid" to proid
*
+ * We need to accept an OID for cases where the name is ambiguous.
+ *
* proid of '-' signifies unknown, for consistency with regprocout
*/
Datum
regprocin(PG_FUNCTION_ARGS)
{
char *pro_name_or_oid = PG_GETARG_CSTRING(0);
- HeapTuple proctup;
- HeapTupleData tuple;
RegProcedure result = InvalidOid;
+ int matches = 0;
+ ScanKeyData skey[1];
if (pro_name_or_oid[0] == '-' && pro_name_or_oid[1] == '\0')
PG_RETURN_OID(InvalidOid);
- if (!IsIgnoringSystemIndexes())
+ if (pro_name_or_oid[0] >= '0' &&
+ pro_name_or_oid[0] <= '9')
{
+ Oid searchOid;
+
+ searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(pro_name_or_oid)));
+ result = (RegProcedure) GetSysCacheOid(PROCOID,
+ ObjectIdGetDatum(searchOid),
+ 0, 0, 0);
+ if (!RegProcedureIsValid(result))
+ elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
+ matches = 1;
+ }
+ else if (!IsIgnoringSystemIndexes())
+ {
+ Relation hdesc;
+ Relation idesc;
+ IndexScanDesc sd;
+ RetrieveIndexResult indexRes;
+ HeapTupleData tuple;
+ Buffer buffer;
+
+ ScanKeyEntryInitialize(&skey[0], 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) F_NAMEEQ,
+ CStringGetDatum(pro_name_or_oid));
- /*
- * we need to use the oid because there can be multiple entries
- * with the same name. We accept int4eq_1323 and 1323.
- */
- if (pro_name_or_oid[0] >= '0' &&
- pro_name_or_oid[0] <= '9')
- {
- result = (RegProcedure)
- GetSysCacheOid(PROCOID,
- DirectFunctionCall1(oidin,
- CStringGetDatum(pro_name_or_oid)),
- 0, 0, 0);
- if (!RegProcedureIsValid(result))
- elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
- }
- else
- {
- Relation hdesc;
- Relation idesc;
- IndexScanDesc sd;
- ScanKeyData skey[1];
- RetrieveIndexResult indexRes;
- Buffer buffer;
- int matches = 0;
-
- ScanKeyEntryInitialize(&skey[0],
- (bits16) 0x0,
- (AttrNumber) 1,
- (RegProcedure) F_NAMEEQ,
- CStringGetDatum(pro_name_or_oid));
-
- hdesc = heap_openr(ProcedureRelationName, AccessShareLock);
- idesc = index_openr(ProcedureNameIndex);
+ hdesc = heap_openr(ProcedureRelationName, AccessShareLock);
+ idesc = index_openr(ProcedureNameIndex);
+ sd = index_beginscan(idesc, false, 1, skey);
- sd = index_beginscan(idesc, false, 1, skey);
- while ((indexRes = index_getnext(sd, ForwardScanDirection)))
+ while ((indexRes = index_getnext(sd, ForwardScanDirection)))
+ {
+ tuple.t_datamcxt = NULL;
+ tuple.t_data = NULL;
+ tuple.t_self = indexRes->heap_iptr;
+ heap_fetch(hdesc, SnapshotNow, &tuple, &buffer, sd);
+ pfree(indexRes);
+ if (tuple.t_data != NULL)
{
- tuple.t_datamcxt = NULL;
- tuple.t_data = NULL;
- tuple.t_self = indexRes->heap_iptr;
- heap_fetch(hdesc, SnapshotNow,
- &tuple,
- &buffer,
- sd);
- pfree(indexRes);
- if (tuple.t_data != NULL)
- {
- result = (RegProcedure) tuple.t_data->t_oid;
- ReleaseBuffer(buffer);
-
- if (++matches > 1)
- break;
- }
+ result = (RegProcedure) tuple.t_data->t_oid;
+ ReleaseBuffer(buffer);
+ if (++matches > 1)
+ break;
}
-
- index_endscan(sd);
- index_close(idesc);
- heap_close(hdesc, AccessShareLock);
-
- if (matches > 1)
- elog(ERROR, "There is more than one procedure named %s.\n\tSupply the pg_proc oid inside single quotes.", pro_name_or_oid);
- else if (matches == 0)
- elog(ERROR, "No procedure with name %s", pro_name_or_oid);
}
+
+ index_endscan(sd);
+ index_close(idesc);
+ heap_close(hdesc, AccessShareLock);
}
else
{
Relation proc;
HeapScanDesc procscan;
- ScanKeyData key;
- bool isnull;
+ HeapTuple proctup;
- proc = heap_openr(ProcedureRelationName, AccessShareLock);
- ScanKeyEntryInitialize(&key,
- (bits16) 0,
- (AttrNumber) 1,
+ ScanKeyEntryInitialize(&skey[0], 0x0,
+ (AttrNumber) Anum_pg_proc_proname,
(RegProcedure) F_NAMEEQ,
CStringGetDatum(pro_name_or_oid));
- procscan = heap_beginscan(proc, 0, SnapshotNow, 1, &key);
- if (!HeapScanIsValid(procscan))
- {
- heap_close(proc, AccessShareLock);
- elog(ERROR, "regprocin: could not begin scan of %s",
- ProcedureRelationName);
- PG_RETURN_OID(InvalidOid);
- }
- proctup = heap_getnext(procscan, 0);
- if (HeapTupleIsValid(proctup))
+ proc = heap_openr(ProcedureRelationName, AccessShareLock);
+ procscan = heap_beginscan(proc, 0, SnapshotNow, 1, skey);
+
+ while (HeapTupleIsValid(proctup = heap_getnext(procscan, 0)))
{
- result = (RegProcedure) heap_getattr(proctup,
- ObjectIdAttributeNumber,
- RelationGetDescr(proc),
- &isnull);
- if (isnull)
- elog(ERROR, "regprocin: null procedure %s", pro_name_or_oid);
+ result = proctup->t_data->t_oid;
+ if (++matches > 1)
+ break;
}
- else
- elog(ERROR, "No procedure with name %s", pro_name_or_oid);
heap_endscan(procscan);
heap_close(proc, AccessShareLock);
}
+ if (matches > 1)
+ elog(ERROR, "There is more than one procedure named %s.\n\tSupply the pg_proc oid inside single quotes.", pro_name_or_oid);
+ else if (matches == 0)
+ elog(ERROR, "No procedure with name %s", pro_name_or_oid);
+
PG_RETURN_OID(result);
}
@@ -174,66 +151,22 @@ regprocout(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(result);
}
- if (!IsBootstrapProcessingMode())
- {
- proctup = SearchSysCache(PROCOID,
- ObjectIdGetDatum(proid),
- 0, 0, 0);
+ proctup = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(proid),
+ 0, 0, 0);
- if (HeapTupleIsValid(proctup))
- {
- char *s;
+ if (HeapTupleIsValid(proctup))
+ {
+ char *s;
- s = NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname);
- StrNCpy(result, s, NAMEDATALEN);
- ReleaseSysCache(proctup);
- }
- else
- {
- result[0] = '-';
- result[1] = '\0';
- }
+ s = NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname);
+ StrNCpy(result, s, NAMEDATALEN);
+ ReleaseSysCache(proctup);
}
else
{
- Relation proc;
- HeapScanDesc procscan;
- ScanKeyData key;
-
- proc = heap_openr(ProcedureRelationName, AccessShareLock);
- ScanKeyEntryInitialize(&key,
- (bits16) 0,
- (AttrNumber) ObjectIdAttributeNumber,
- (RegProcedure) F_INT4EQ,
- ObjectIdGetDatum(proid));
-
- procscan = heap_beginscan(proc, 0, SnapshotNow, 1, &key);
- if (!HeapScanIsValid(procscan))
- {
- heap_close(proc, AccessShareLock);
- elog(ERROR, "regprocout: could not begin scan of %s",
- ProcedureRelationName);
- }
- proctup = heap_getnext(procscan, 0);
- if (HeapTupleIsValid(proctup))
- {
- char *s;
- bool isnull;
-
- s = (char *) heap_getattr(proctup, 1,
- RelationGetDescr(proc), &isnull);
- if (!isnull)
- StrNCpy(result, s, NAMEDATALEN);
- else
- elog(ERROR, "regprocout: null procedure %u", proid);
- }
- else
- {
- result[0] = '-';
- result[1] = '\0';
- }
- heap_endscan(procscan);
- heap_close(proc, AccessShareLock);
+ result[0] = '-';
+ result[1] = '\0';
}
PG_RETURN_CSTRING(result);
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index f5f16e77188..ce4363706b3 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.81 2001/06/22 19:16:23 wieck Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.82 2001/08/21 16:36:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,6 +18,7 @@
#include "access/hash.h"
#include "access/heapam.h"
#include "access/valid.h"
+#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "catalog/catname.h"
@@ -812,7 +813,7 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
sd = heap_beginscan(rel, false, SnapshotNow, 1, &key);
ntp = heap_getnext(sd, 0);
if (!HeapTupleIsValid(ntp))
- elog(ERROR, "SearchSelfReferences: %s not found in %s",
+ elog(ERROR, "IndexScanOK: %s not found in %s",
IndexRelidIndex, RelationRelationName);
indexSelfOid = ntp->t_data->t_oid;
heap_endscan(sd);
@@ -823,6 +824,16 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
if (DatumGetObjectId(cur_skey[0].sk_argument) == indexSelfOid)
return false;
}
+ else if (cache->id == AMOPSTRATEGY ||
+ cache->id == AMPROCNUM)
+ {
+ /* Looking for an OID or INT2 btree operator or function? */
+ Oid lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
+
+ if (lookup_oid == OID_BTREE_OPS_OID ||
+ lookup_oid == INT2_BTREE_OPS_OID)
+ return false;
+ }
else if (cache->id == OPEROID)
{
/* Looking for an OID comparison function? */
@@ -858,7 +869,7 @@ SearchCatCache(CatCache *cache,
MemoryContext oldcxt;
/*
- * one-time startup overhead
+ * one-time startup overhead for each cache
*/
if (cache->cc_tupdesc == NULL)
CatalogCacheInitializeCache(cache);
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 587213d48f8..1637abe999a 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.56 2001/06/14 01:09:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.57 2001/08/21 16:36:05 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -16,6 +16,8 @@
#include "postgres.h"
#include "access/tupmacs.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
@@ -30,19 +32,48 @@
/* ---------- AMOP CACHES ---------- */
/*
- * op_class
+ * op_in_opclass
*
- * Return t iff operator 'opno' is in operator class 'opclass' for
- * access method 'amopid'.
+ * Return t iff operator 'opno' is in operator class 'opclass'.
*/
bool
-op_class(Oid opno, Oid opclass, Oid amopid)
+op_in_opclass(Oid opno, Oid opclass)
{
return SearchSysCacheExists(AMOPOPID,
ObjectIdGetDatum(opclass),
ObjectIdGetDatum(opno),
- ObjectIdGetDatum(amopid),
- 0);
+ 0, 0);
+}
+
+/*
+ * op_requires_recheck
+ *
+ * Return t if operator 'opno' requires a recheck when used as a
+ * member of opclass 'opclass' (ie, this opclass is lossy for this
+ * operator).
+ *
+ * Caller should already have verified that opno is a member of opclass,
+ * therefore we raise an error if the tuple is not found.
+ */
+bool
+op_requires_recheck(Oid opno, Oid opclass)
+{
+ HeapTuple tp;
+ Form_pg_amop amop_tup;
+ bool result;
+
+ tp = SearchSysCache(AMOPOPID,
+ ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(opno),
+ 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "op_requires_recheck: op %u is not a member of opclass %u",
+ opno, opclass);
+ amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+
+ result = amop_tup->amopreqcheck;
+ ReleaseSysCache(tp);
+ return result;
}
/* ---------- ATTRIBUTE CACHES ---------- */
@@ -222,6 +253,33 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
/* watch this space...
*/
+/* ---------- OPCLASS CACHE ---------- */
+
+/*
+ * opclass_is_btree
+ *
+ * Returns TRUE iff the specified opclass is associated with the
+ * btree index access method.
+ */
+bool
+opclass_is_btree(Oid opclass)
+{
+ HeapTuple tp;
+ Form_pg_opclass cla_tup;
+ bool result;
+
+ tp = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(opclass),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for opclass %u", opclass);
+ cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
+
+ result = (cla_tup->opcamid == BTREE_AM_OID);
+ ReleaseSysCache(tp);
+ return result;
+}
+
/* ---------- OPERATOR CACHE ---------- */
/*
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index a407d39f5d0..6020597f2a3 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.64 2001/08/10 18:57:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.65 2001/08/21 16:36:05 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@@ -27,6 +27,7 @@
#include "catalog/indexing.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
#include "catalog/pg_group.h"
#include "catalog/pg_index.h"
#include "catalog/pg_inherits.h"
@@ -113,23 +114,33 @@ static struct cachedesc cacheinfo[] = {
0
}},
{AccessMethodOperatorRelationName, /* AMOPOPID */
- AccessMethodOpidIndex,
+ AccessMethodOperatorIndex,
0,
- 3,
+ 2,
{
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopopr,
- Anum_pg_amop_amopid,
+ 0,
0
}},
{AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
AccessMethodStrategyIndex,
0,
- 3,
+ 2,
{
- Anum_pg_amop_amopid,
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopstrategy,
+ 0,
+ 0
+ }},
+ {AccessMethodProcedureRelationName, /* AMPROCNUM */
+ AccessMethodProcedureIndex,
+ 0,
+ 2,
+ {
+ Anum_pg_amproc_amopclaid,
+ Anum_pg_amproc_amprocnum,
+ 0,
0
}},
{AttributeRelationName, /* ATTNAME */
@@ -152,22 +163,22 @@ static struct cachedesc cacheinfo[] = {
0,
0
}},
- {OperatorClassRelationName, /* CLADEFTYPE */
- OpclassDeftypeIndex,
+ {OperatorClassRelationName, /* CLAAMNAME */
+ OpclassAmNameIndex,
0,
- 1,
+ 2,
{
- Anum_pg_opclass_opcdeftype,
- 0,
+ Anum_pg_opclass_opcamid,
+ Anum_pg_opclass_opcname,
0,
0
}},
- {OperatorClassRelationName, /* CLANAME */
- OpclassNameIndex,
+ {OperatorClassRelationName, /* CLAOID */
+ OpclassOidIndex,
0,
1,
{
- Anum_pg_opclass_opcname,
+ ObjectIdAttributeNumber,
0,
0,
0
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 1391ea88c2e..f4e2faaa2b3 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -78,7 +78,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.17 2001/06/02 19:01:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.18 2001/08/21 16:36:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2055,7 +2055,7 @@ SelectSortFunction(Oid sortOperator,
{
Relation relation;
HeapScanDesc scan;
- ScanKeyData skey[3];
+ ScanKeyData skey[1];
HeapTuple tuple;
Form_pg_operator optup;
Oid opclass = InvalidOid;
@@ -2068,25 +2068,20 @@ SelectSortFunction(Oid sortOperator,
* If the operator is registered the same way in multiple opclasses,
* assume we can use the associated comparator function from any one.
*/
- relation = heap_openr(AccessMethodOperatorRelationName,
- AccessShareLock);
-
- ScanKeyEntryInitialize(&skey[0], 0,
- Anum_pg_amop_amopid,
- F_OIDEQ,
- ObjectIdGetDatum(BTREE_AM_OID));
-
- ScanKeyEntryInitialize(&skey[1], 0,
+ ScanKeyEntryInitialize(&skey[0], 0x0,
Anum_pg_amop_amopopr,
F_OIDEQ,
ObjectIdGetDatum(sortOperator));
- scan = heap_beginscan(relation, false, SnapshotNow, 2, skey);
+ relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
+ scan = heap_beginscan(relation, false, SnapshotNow, 1, skey);
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
{
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
+ if (!opclass_is_btree(aform->amopclaid))
+ continue;
if (aform->amopstrategy == BTLessStrategyNumber)
{
opclass = aform->amopclaid;
@@ -2107,39 +2102,18 @@ SelectSortFunction(Oid sortOperator,
if (OidIsValid(opclass))
{
/* Found a suitable opclass, get its comparator support function */
- relation = heap_openr(AccessMethodProcedureRelationName,
- AccessShareLock);
-
- ScanKeyEntryInitialize(&skey[0], 0,
- Anum_pg_amproc_amid,
- F_OIDEQ,
- ObjectIdGetDatum(BTREE_AM_OID));
-
- ScanKeyEntryInitialize(&skey[1], 0,
- Anum_pg_amproc_amopclaid,
- F_OIDEQ,
- ObjectIdGetDatum(opclass));
-
- ScanKeyEntryInitialize(&skey[2], 0,
- Anum_pg_amproc_amprocnum,
- F_INT2EQ,
- Int16GetDatum(BTORDER_PROC));
-
- scan = heap_beginscan(relation, false, SnapshotNow, 3, skey);
-
- *sortFunction = InvalidOid;
-
- if (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+ tuple = SearchSysCache(AMPROCNUM,
+ ObjectIdGetDatum(opclass),
+ Int16GetDatum(BTORDER_PROC),
+ 0, 0);
+ if (HeapTupleIsValid(tuple))
{
Form_pg_amproc aform = (Form_pg_amproc) GETSTRUCT(tuple);
*sortFunction = aform->amproc;
- }
-
- heap_endscan(scan);
- heap_close(relation, AccessShareLock);
-
- if (RegProcedureIsValid(*sortFunction))
+ ReleaseSysCache(tuple);
+ Assert(RegProcedureIsValid(*sortFunction));
return;
+ }
}
/*
@@ -2158,7 +2132,7 @@ SelectSortFunction(Oid sortOperator,
*kind = SORTFUNC_REVLT;
else
*kind = SORTFUNC_LT;
- *sortFunction = optup->oprcode;
+ *sortFunction = optup->oprcode;
ReleaseSysCache(tuple);
Assert(RegProcedureIsValid(*sortFunction));