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:
parent
a77c4df2c1
commit
97f0521d8e
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user