88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.23 2000/04/12 17:14:58 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.24 2000/04/23 01:44:55 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2020#include "catalog/catname.h"
2121#include "catalog/heap.h"
2222#include "catalog/index.h"
23+ #include "catalog/pg_amop.h"
24+ #include "catalog/pg_database.h"
2325#include "catalog/pg_index.h"
2426#include "catalog/pg_opclass.h"
2527#include "catalog/pg_proc.h"
26- #include "catalog/pg_type.h"
27- #include "catalog/pg_database.h"
2828#include "catalog/pg_shadow.h"
29+ #include "catalog/pg_type.h"
2930#include "commands/defrem.h"
3031#include "optimizer/clauses.h"
3132#include "optimizer/planmain.h"
3233#include "optimizer/prep.h"
3334#include "parser/parsetree.h"
3435#include "parser/parse_func.h"
36+ #include "parser/parse_type.h"
3537#include "utils/builtins.h"
3638#include "utils/syscache.h"
3739#include "miscadmin.h" /* ReindexDatabase() */
@@ -45,12 +47,15 @@ static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
4547static void CheckPredExpr (Node * predicate ,List * rangeTable ,Oid baseRelOid );
4648static void CheckPredClause (Expr * predicate ,List * rangeTable ,Oid baseRelOid );
4749static void FuncIndexArgs (IndexElem * funcIndex ,FuncIndexInfo * funcInfo ,
48- AttrNumber * attNumP ,Oid * opOidP ,Oid relId );
50+ AttrNumber * attNumP ,Oid * opOidP ,Oid relId ,
51+ char * accessMethodName ,Oid accessMethodId );
4952static void NormIndexAttrs (List * attList ,AttrNumber * attNumP ,
50- Oid * opOidP ,Oid relId );
53+ Oid * opOidP ,Oid relId ,
54+ char * accessMethodName ,Oid accessMethodId );
5155static void ProcessAttrTypename (IndexElem * attribute ,
5256Oid defType ,int32 defTypmod );
53- static Oid GetAttrOpClass (IndexElem * attribute ,Oid attrType );
57+ static Oid GetAttrOpClass (IndexElem * attribute ,Oid attrType ,
58+ char * accessMethodName ,Oid accessMethodId );
5459static char * GetDefaultOpClass (Oid atttypid );
5560
5661/*
@@ -91,7 +96,7 @@ DefineIndex(char *heapRelationName,
9196List * pl ;
9297
9398/*
94- *Handle attributes
99+ *count attributes
95100 */
96101numberOfAttributes = length (attributeList );
97102if (numberOfAttributes <=0 )
@@ -105,10 +110,15 @@ DefineIndex(char *heapRelationName,
105110 */
106111if ((relationId = RelnameFindRelid (heapRelationName ))== InvalidOid )
107112{
108- elog (ERROR ,"DefineIndex:%s relation not found" ,
113+ elog (ERROR ,"DefineIndex:relation \"%s\" not found" ,
109114heapRelationName );
110115}
111116
117+ /*
118+ * XXX Hardwired hacks to check for limitations on supported index types.
119+ * We really ought to be learning this info from entries in the pg_am
120+ * table, instead of having it wired in here!
121+ */
112122if (unique && strcmp (accessMethodName ,"btree" )!= 0 )
113123elog (ERROR ,"DefineIndex: unique indices are only available with the btree access method" );
114124
@@ -123,7 +133,7 @@ DefineIndex(char *heapRelationName,
1231330 ,0 ,0 );
124134if (!HeapTupleIsValid (tuple ))
125135{
126- elog (ERROR ,"DefineIndex:%s access method not found" ,
136+ elog (ERROR ,"DefineIndex: access method \"%s\" not found" ,
127137accessMethodName );
128138}
129139accessMethodId = tuple -> t_data -> t_oid ;
@@ -138,7 +148,7 @@ DefineIndex(char *heapRelationName,
138148if (!strcasecmp (param -> defname ,"islossy" ))
139149lossy = TRUE;
140150else
141- elog (NOTICE ,"Unrecognized index attribute'%s' ignored" ,
151+ elog (NOTICE ,"Unrecognized index attribute\"%s\" ignored" ,
142152param -> defname );
143153}
144154
@@ -158,7 +168,8 @@ DefineIndex(char *heapRelationName,
158168}
159169
160170if (!IsBootstrapProcessingMode ()&& !IndexesAreActive (relationId , false))
161- elog (ERROR ,"existent indexes are inactive. REINDEX first" );
171+ elog (ERROR ,"Existing indexes are inactive. REINDEX first" );
172+
162173if (IsFuncIndex (attributeList ))
163174{
164175IndexElem * funcIndex = lfirst (attributeList );
@@ -179,12 +190,12 @@ DefineIndex(char *heapRelationName,
179190classObjectId = (Oid * )palloc (sizeof (Oid ));
180191
181192FuncIndexArgs (funcIndex ,& fInfo ,attributeNumberA ,
182- classObjectId ,relationId );
193+ classObjectId ,relationId ,
194+ accessMethodName ,accessMethodId );
183195
184- index_create (heapRelationName ,
185- indexRelationName ,
186- & fInfo ,NULL ,accessMethodId ,
187- numberOfAttributes ,attributeNumberA ,
196+ index_create (heapRelationName ,indexRelationName ,
197+ & fInfo ,NULL ,
198+ accessMethodId ,numberOfAttributes ,attributeNumberA ,
188199classObjectId ,parameterCount ,parameterA ,
189200 (Node * )cnfPred ,
190201lossy ,unique ,primary );
@@ -197,10 +208,11 @@ DefineIndex(char *heapRelationName,
197208classObjectId = (Oid * )palloc (numberOfAttributes * sizeof (Oid ));
198209
199210NormIndexAttrs (attributeList ,attributeNumberA ,
200- classObjectId ,relationId );
211+ classObjectId ,relationId ,
212+ accessMethodName ,accessMethodId );
201213
202- index_create (heapRelationName ,indexRelationName ,NULL ,
203- attributeList ,
214+ index_create (heapRelationName ,indexRelationName ,
215+ NULL , attributeList ,
204216accessMethodId ,numberOfAttributes ,attributeNumberA ,
205217classObjectId ,parameterCount ,parameterA ,
206218 (Node * )cnfPred ,
@@ -247,7 +259,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
2472590 ,0 ,0 );
248260if (!HeapTupleIsValid (tuple ))
249261{
250- elog (ERROR ,"ExtendIndex:%s index not found" ,
262+ elog (ERROR ,"ExtendIndex:index \"%s\" not found" ,
251263indexRelationName );
252264}
253265indexId = tuple -> t_data -> t_oid ;
@@ -261,7 +273,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
2612730 ,0 ,0 );
262274if (!HeapTupleIsValid (tuple ))
263275{
264- elog (ERROR ,"ExtendIndex:%s is not an index" ,
276+ elog (ERROR ,"ExtendIndex:relation \"%s\" is not an index" ,
265277indexRelationName );
266278}
267279
@@ -289,7 +301,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
289301pfree (predString );
290302}
291303if (oldPred == NULL )
292- elog (ERROR ,"ExtendIndex:%s is not a partial index" ,
304+ elog (ERROR ,"ExtendIndex:\"%s\" is not a partial index" ,
293305indexRelationName );
294306
295307/*
@@ -330,7 +342,8 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
330342ObjectIdGetDatum (indproc ),
3313430 ,0 ,0 );
332344if (!HeapTupleIsValid (tuple ))
333- elog (ERROR ,"ExtendIndex: index procedure not found" );
345+ elog (ERROR ,"ExtendIndex: index procedure %u not found" ,
346+ indproc );
334347
335348namecpy (& (funcInfo -> funcName ),
336349& (((Form_pg_proc )GETSTRUCT (tuple ))-> proname ));
@@ -413,7 +426,9 @@ FuncIndexArgs(IndexElem *funcIndex,
413426FuncIndexInfo * funcInfo ,
414427AttrNumber * attNumP ,
415428Oid * opOidP ,
416- Oid relId )
429+ Oid relId ,
430+ char * accessMethodName ,
431+ Oid accessMethodId )
417432{
418433List * rest ;
419434HeapTuple tuple ;
@@ -465,14 +480,17 @@ FuncIndexArgs(IndexElem *funcIndex,
465480
466481ProcessAttrTypename (funcIndex ,retType ,-1 );
467482
468- * opOidP = GetAttrOpClass (funcIndex ,retType );
483+ * opOidP = GetAttrOpClass (funcIndex ,retType ,
484+ accessMethodName ,accessMethodId );
469485}
470486
471487static void
472488NormIndexAttrs (List * attList ,/* list of IndexElem's */
473489AttrNumber * attNumP ,
474490Oid * classOidP ,
475- Oid relId )
491+ Oid relId ,
492+ char * accessMethodName ,
493+ Oid accessMethodId )
476494{
477495List * rest ;
478496
@@ -501,7 +519,8 @@ NormIndexAttrs(List *attList,/* list of IndexElem's */
501519
502520ProcessAttrTypename (attribute ,attform -> atttypid ,attform -> atttypmod );
503521
504- * classOidP ++ = GetAttrOpClass (attribute ,attform -> atttypid );
522+ * classOidP ++ = GetAttrOpClass (attribute ,attform -> atttypid ,
523+ accessMethodName ,accessMethodId );
505524
506525heap_freetuple (atttuple );
507526}
@@ -520,7 +539,7 @@ ProcessAttrTypename(IndexElem *attribute,
520539ObjectIdGetDatum (defType ),
5215400 ,0 ,0 );
522541if (!HeapTupleIsValid (tuple ))
523- elog (ERROR ,"DefineIndex: type for attribute'%s' undefined" ,
542+ elog (ERROR ,"DefineIndex: type for attribute\"%s\" undefined" ,
524543attribute -> name );
525544
526545attribute -> typename = makeNode (TypeName );
@@ -530,28 +549,58 @@ ProcessAttrTypename(IndexElem *attribute,
530549}
531550
532551static Oid
533- GetAttrOpClass (IndexElem * attribute ,Oid attrType )
552+ GetAttrOpClass (IndexElem * attribute ,Oid attrType ,
553+ char * accessMethodName ,Oid accessMethodId )
534554{
555+ Relation relation ;
556+ HeapScanDesc scan ;
557+ ScanKeyData entry [2 ];
535558HeapTuple tuple ;
559+ Oid opClassId ;
536560
537561if (attribute -> class == NULL )
538562{
539563/* no operator class specified, so find the default */
540564attribute -> class = GetDefaultOpClass (attrType );
541565if (attribute -> class == NULL )
542- elog (ERROR ,"Can't find a default operator class for type %u " ,
543- attrType );
566+ elog (ERROR ,"DefineIndex: type %s has no default operator class" ,
567+ typeidTypeName ( attrType ) );
544568}
545569
546570tuple = SearchSysCacheTuple (CLANAME ,
547571PointerGetDatum (attribute -> class ),
5485720 ,0 ,0 );
549-
550573if (!HeapTupleIsValid (tuple ))
551- elog (ERROR ,"DefineIndex:%s opclass not found" ,
574+ elog (ERROR ,"DefineIndex:opclass \"%s\" not found" ,
552575attribute -> class );
576+ opClassId = tuple -> t_data -> t_oid ;
577+
578+ /*
579+ * Assume the opclass is supported by this index access method
580+ * if we can find at least one relevant entry in pg_amop.
581+ */
582+ ScanKeyEntryInitialize (& entry [0 ],0 ,
583+ Anum_pg_amop_amopid ,
584+ F_OIDEQ ,
585+ ObjectIdGetDatum (accessMethodId ));
586+ ScanKeyEntryInitialize (& entry [1 ],0 ,
587+ Anum_pg_amop_amopclaid ,
588+ F_OIDEQ ,
589+ ObjectIdGetDatum (opClassId ));
590+
591+ relation = heap_openr (AccessMethodOperatorRelationName ,AccessShareLock );
592+ scan = heap_beginscan (relation , false,SnapshotNow ,2 ,entry );
593+
594+ if (!HeapTupleIsValid (tuple = heap_getnext (scan ,0 )))
595+ {
596+ elog (ERROR ,"DefineIndex: opclass \"%s\" not supported by access method \"%s\"" ,
597+ attribute -> class ,accessMethodName );
598+ }
599+
600+ heap_endscan (scan );
601+ heap_close (relation ,AccessShareLock );
553602
554- return tuple -> t_data -> t_oid ;
603+ return opClassId ;
555604}
556605
557606static char *
@@ -563,7 +612,7 @@ GetDefaultOpClass(Oid atttypid)
563612ObjectIdGetDatum (atttypid ),
5646130 ,0 ,0 );
565614if (!HeapTupleIsValid (tuple ))
566- return 0 ;
615+ return NULL ;
567616
568617return nameout (& ((Form_pg_opclass )GETSTRUCT (tuple ))-> opcname );
569618}
@@ -697,7 +746,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
697746usertuple = SearchSysCacheTuple (SHADOWNAME ,PointerGetDatum (username ),
6987470 ,0 ,0 );
699748if (!HeapTupleIsValid (usertuple ))
700- elog (ERROR ,"Current user'%s' is invalid." ,username );
749+ elog (ERROR ,"Current user\"%s\" is invalid." ,username );
701750user_id = ((Form_pg_shadow )GETSTRUCT (usertuple ))-> usesysid ;
702751superuser = ((Form_pg_shadow )GETSTRUCT (usertuple ))-> usesuper ;
703752
@@ -707,7 +756,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
707756scan = heap_beginscan (relation ,0 ,SnapshotNow ,1 ,& scankey );
708757dbtuple = heap_getnext (scan ,0 );
709758if (!HeapTupleIsValid (dbtuple ))
710- elog (ERROR ,"Database'%s' doesn't exist" ,dbname );
759+ elog (ERROR ,"Database\"%s\" doesn't exist" ,dbname );
711760db_id = dbtuple -> t_data -> t_oid ;
712761db_owner = ((Form_pg_database )GETSTRUCT (dbtuple ))-> datdba ;
713762heap_endscan (scan );