Produce an appropriate error message when opclass is not supported by

specified index access method.  Clean up wording of some existing error
messages, too.
This commit is contained in:
Tom Lane 2000-04-23 01:44:55 +00:00
parent a77c4df2c1
commit 97f0521d8e

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.23 2000/04/12 17:14:58 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.24 2000/04/23 01:44:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -20,18 +20,20 @@
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/heap.h" #include "catalog/heap.h"
#include "catalog/index.h" #include "catalog/index.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_database.h"
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "catalog/pg_database.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "optimizer/prep.h" #include "optimizer/prep.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "miscadmin.h" /* ReindexDatabase() */ #include "miscadmin.h" /* ReindexDatabase() */
@ -45,12 +47,15 @@ static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid); static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid); static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
static void FuncIndexArgs(IndexElem *funcIndex, FuncIndexInfo *funcInfo, static void FuncIndexArgs(IndexElem *funcIndex, FuncIndexInfo *funcInfo,
AttrNumber *attNumP, Oid *opOidP, Oid relId); AttrNumber *attNumP, Oid *opOidP, Oid relId,
char *accessMethodName, Oid accessMethodId);
static void NormIndexAttrs(List *attList, AttrNumber *attNumP, static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
Oid *opOidP, Oid relId); Oid *opOidP, Oid relId,
char *accessMethodName, Oid accessMethodId);
static void ProcessAttrTypename(IndexElem *attribute, static void ProcessAttrTypename(IndexElem *attribute,
Oid defType, int32 defTypmod); Oid defType, int32 defTypmod);
static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType); static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
char *accessMethodName, Oid accessMethodId);
static char *GetDefaultOpClass(Oid atttypid); static char *GetDefaultOpClass(Oid atttypid);
/* /*
@ -91,7 +96,7 @@ DefineIndex(char *heapRelationName,
List *pl; List *pl;
/* /*
* Handle attributes * count attributes
*/ */
numberOfAttributes = length(attributeList); numberOfAttributes = length(attributeList);
if (numberOfAttributes <= 0) if (numberOfAttributes <= 0)
@ -105,10 +110,15 @@ DefineIndex(char *heapRelationName,
*/ */
if ((relationId = RelnameFindRelid(heapRelationName)) == InvalidOid) if ((relationId = RelnameFindRelid(heapRelationName)) == InvalidOid)
{ {
elog(ERROR, "DefineIndex: %s relation not found", elog(ERROR, "DefineIndex: relation \"%s\" not found",
heapRelationName); heapRelationName);
} }
/*
* XXX Hardwired hacks to check for limitations on supported index types.
* We really ought to be learning this info from entries in the pg_am
* table, instead of having it wired in here!
*/
if (unique && strcmp(accessMethodName, "btree") != 0) if (unique && strcmp(accessMethodName, "btree") != 0)
elog(ERROR, "DefineIndex: unique indices are only available with the btree access method"); elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
@ -123,7 +133,7 @@ DefineIndex(char *heapRelationName,
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
elog(ERROR, "DefineIndex: %s access method not found", elog(ERROR, "DefineIndex: access method \"%s\" not found",
accessMethodName); accessMethodName);
} }
accessMethodId = tuple->t_data->t_oid; accessMethodId = tuple->t_data->t_oid;
@ -138,7 +148,7 @@ DefineIndex(char *heapRelationName,
if (!strcasecmp(param->defname, "islossy")) if (!strcasecmp(param->defname, "islossy"))
lossy = TRUE; lossy = TRUE;
else else
elog(NOTICE, "Unrecognized index attribute '%s' ignored", elog(NOTICE, "Unrecognized index attribute \"%s\" ignored",
param->defname); param->defname);
} }
@ -158,7 +168,8 @@ DefineIndex(char *heapRelationName,
} }
if (!IsBootstrapProcessingMode() && !IndexesAreActive(relationId, false)) if (!IsBootstrapProcessingMode() && !IndexesAreActive(relationId, false))
elog(ERROR, "existent indexes are inactive. REINDEX first"); elog(ERROR, "Existing indexes are inactive. REINDEX first");
if (IsFuncIndex(attributeList)) if (IsFuncIndex(attributeList))
{ {
IndexElem *funcIndex = lfirst(attributeList); IndexElem *funcIndex = lfirst(attributeList);
@ -179,12 +190,12 @@ DefineIndex(char *heapRelationName,
classObjectId = (Oid *) palloc(sizeof(Oid)); classObjectId = (Oid *) palloc(sizeof(Oid));
FuncIndexArgs(funcIndex, &fInfo, attributeNumberA, FuncIndexArgs(funcIndex, &fInfo, attributeNumberA,
classObjectId, relationId); classObjectId, relationId,
accessMethodName, accessMethodId);
index_create(heapRelationName, index_create(heapRelationName, indexRelationName,
indexRelationName, &fInfo, NULL,
&fInfo, NULL, accessMethodId, accessMethodId, numberOfAttributes, attributeNumberA,
numberOfAttributes, attributeNumberA,
classObjectId, parameterCount, parameterA, classObjectId, parameterCount, parameterA,
(Node *) cnfPred, (Node *) cnfPred,
lossy, unique, primary); lossy, unique, primary);
@ -197,10 +208,11 @@ DefineIndex(char *heapRelationName,
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
NormIndexAttrs(attributeList, attributeNumberA, NormIndexAttrs(attributeList, attributeNumberA,
classObjectId, relationId); classObjectId, relationId,
accessMethodName, accessMethodId);
index_create(heapRelationName, indexRelationName, NULL, index_create(heapRelationName, indexRelationName,
attributeList, NULL, attributeList,
accessMethodId, numberOfAttributes, attributeNumberA, accessMethodId, numberOfAttributes, attributeNumberA,
classObjectId, parameterCount, parameterA, classObjectId, parameterCount, parameterA,
(Node *) cnfPred, (Node *) cnfPred,
@ -247,7 +259,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
elog(ERROR, "ExtendIndex: %s index not found", elog(ERROR, "ExtendIndex: index \"%s\" not found",
indexRelationName); indexRelationName);
} }
indexId = tuple->t_data->t_oid; indexId = tuple->t_data->t_oid;
@ -261,7 +273,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
elog(ERROR, "ExtendIndex: %s is not an index", elog(ERROR, "ExtendIndex: relation \"%s\" is not an index",
indexRelationName); indexRelationName);
} }
@ -289,7 +301,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
pfree(predString); pfree(predString);
} }
if (oldPred == NULL) if (oldPred == NULL)
elog(ERROR, "ExtendIndex: %s is not a partial index", elog(ERROR, "ExtendIndex: \"%s\" is not a partial index",
indexRelationName); indexRelationName);
/* /*
@ -330,7 +342,8 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
ObjectIdGetDatum(indproc), ObjectIdGetDatum(indproc),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "ExtendIndex: index procedure not found"); elog(ERROR, "ExtendIndex: index procedure %u not found",
indproc);
namecpy(&(funcInfo->funcName), namecpy(&(funcInfo->funcName),
&(((Form_pg_proc) GETSTRUCT(tuple))->proname)); &(((Form_pg_proc) GETSTRUCT(tuple))->proname));
@ -413,7 +426,9 @@ FuncIndexArgs(IndexElem *funcIndex,
FuncIndexInfo *funcInfo, FuncIndexInfo *funcInfo,
AttrNumber *attNumP, AttrNumber *attNumP,
Oid *opOidP, Oid *opOidP,
Oid relId) Oid relId,
char *accessMethodName,
Oid accessMethodId)
{ {
List *rest; List *rest;
HeapTuple tuple; HeapTuple tuple;
@ -465,14 +480,17 @@ FuncIndexArgs(IndexElem *funcIndex,
ProcessAttrTypename(funcIndex, retType, -1); ProcessAttrTypename(funcIndex, retType, -1);
*opOidP = GetAttrOpClass(funcIndex, retType); *opOidP = GetAttrOpClass(funcIndex, retType,
accessMethodName, accessMethodId);
} }
static void static void
NormIndexAttrs(List *attList, /* list of IndexElem's */ NormIndexAttrs(List *attList, /* list of IndexElem's */
AttrNumber *attNumP, AttrNumber *attNumP,
Oid *classOidP, Oid *classOidP,
Oid relId) Oid relId,
char *accessMethodName,
Oid accessMethodId)
{ {
List *rest; List *rest;
@ -501,7 +519,8 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */
ProcessAttrTypename(attribute, attform->atttypid, attform->atttypmod); ProcessAttrTypename(attribute, attform->atttypid, attform->atttypmod);
*classOidP++ = GetAttrOpClass(attribute, attform->atttypid); *classOidP++ = GetAttrOpClass(attribute, attform->atttypid,
accessMethodName, accessMethodId);
heap_freetuple(atttuple); heap_freetuple(atttuple);
} }
@ -520,7 +539,7 @@ ProcessAttrTypename(IndexElem *attribute,
ObjectIdGetDatum(defType), ObjectIdGetDatum(defType),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "DefineIndex: type for attribute '%s' undefined", elog(ERROR, "DefineIndex: type for attribute \"%s\" undefined",
attribute->name); attribute->name);
attribute->typename = makeNode(TypeName); attribute->typename = makeNode(TypeName);
@ -530,28 +549,58 @@ ProcessAttrTypename(IndexElem *attribute,
} }
static Oid static Oid
GetAttrOpClass(IndexElem *attribute, Oid attrType) GetAttrOpClass(IndexElem *attribute, Oid attrType,
char *accessMethodName, Oid accessMethodId)
{ {
Relation relation;
HeapScanDesc scan;
ScanKeyData entry[2];
HeapTuple tuple; HeapTuple tuple;
Oid opClassId;
if (attribute->class == NULL) if (attribute->class == NULL)
{ {
/* no operator class specified, so find the default */ /* no operator class specified, so find the default */
attribute->class = GetDefaultOpClass(attrType); attribute->class = GetDefaultOpClass(attrType);
if (attribute->class == NULL) if (attribute->class == NULL)
elog(ERROR, "Can't find a default operator class for type %u", elog(ERROR, "DefineIndex: type %s has no default operator class",
attrType); typeidTypeName(attrType));
} }
tuple = SearchSysCacheTuple(CLANAME, tuple = SearchSysCacheTuple(CLANAME,
PointerGetDatum(attribute->class), PointerGetDatum(attribute->class),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "DefineIndex: %s opclass not found", elog(ERROR, "DefineIndex: opclass \"%s\" not found",
attribute->class); attribute->class);
opClassId = tuple->t_data->t_oid;
return tuple->t_data->t_oid; /*
* Assume the opclass is supported by this index access method
* if we can find at least one relevant entry in pg_amop.
*/
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\"",
attribute->class, accessMethodName);
}
heap_endscan(scan);
heap_close(relation, AccessShareLock);
return opClassId;
} }
static char * static char *
@ -563,7 +612,7 @@ GetDefaultOpClass(Oid atttypid)
ObjectIdGetDatum(atttypid), ObjectIdGetDatum(atttypid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
return 0; return NULL;
return nameout(&((Form_pg_opclass) GETSTRUCT(tuple))->opcname); return nameout(&((Form_pg_opclass) GETSTRUCT(tuple))->opcname);
} }
@ -697,7 +746,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
usertuple = SearchSysCacheTuple(SHADOWNAME, PointerGetDatum(username), usertuple = SearchSysCacheTuple(SHADOWNAME, PointerGetDatum(username),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(usertuple)) if (!HeapTupleIsValid(usertuple))
elog(ERROR, "Current user '%s' is invalid.", username); elog(ERROR, "Current user \"%s\" is invalid.", username);
user_id = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesysid; user_id = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesysid;
superuser = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesuper; superuser = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesuper;
@ -707,7 +756,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scankey); scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scankey);
dbtuple = heap_getnext(scan, 0); dbtuple = heap_getnext(scan, 0);
if (!HeapTupleIsValid(dbtuple)) if (!HeapTupleIsValid(dbtuple))
elog(ERROR, "Database '%s' doesn't exist", dbname); elog(ERROR, "Database \"%s\" doesn't exist", dbname);
db_id = dbtuple->t_data->t_oid; db_id = dbtuple->t_data->t_oid;
db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba; db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
heap_endscan(scan); heap_endscan(scan);