]> granicus.if.org Git - postgresql/blob - src/backend/commands/opclasscmds.c
Create a 'type cache' that keeps track of the data needed for any particular
[postgresql] / src / backend / commands / opclasscmds.c
1 /*-------------------------------------------------------------------------
2  *
3  * opclasscmds.c
4  *
5  *        Routines for opclass manipulation commands
6  *
7  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.18 2003/08/17 19:58:04 tgl Exp $
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include "access/genam.h"
19 #include "access/heapam.h"
20 #include "catalog/catname.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/namespace.h"
24 #include "catalog/pg_am.h"
25 #include "catalog/pg_amop.h"
26 #include "catalog/pg_amproc.h"
27 #include "catalog/pg_opclass.h"
28 #include "commands/defrem.h"
29 #include "miscadmin.h"
30 #include "parser/parse_func.h"
31 #include "parser/parse_oper.h"
32 #include "parser/parse_type.h"
33 #include "utils/acl.h"
34 #include "utils/builtins.h"
35 #include "utils/fmgroids.h"
36 #include "utils/lsyscache.h"
37 #include "utils/syscache.h"
38
39
40 static void storeOperators(Oid opclassoid, int numOperators,
41                            Oid *operators, bool *recheck);
42 static void storeProcedures(Oid opclassoid, int numProcs, Oid *procedures);
43
44
45 /*
46  * DefineOpClass
47  *              Define a new index operator class.
48  */
49 void
50 DefineOpClass(CreateOpClassStmt *stmt)
51 {
52         char       *opcname;            /* name of opclass we're creating */
53         Oid                     amoid,                  /* our AM's oid */
54                                 typeoid,                /* indexable datatype oid */
55                                 storageoid,             /* storage datatype oid, if any */
56                                 namespaceoid,   /* namespace to create opclass in */
57                                 opclassoid;             /* oid of opclass we create */
58         int                     numOperators,   /* amstrategies value */
59                                 numProcs;               /* amsupport value */
60         Oid                *operators,          /* oids of operators, by strategy num */
61                            *procedures;         /* oids of support procs */
62         bool       *recheck;            /* do operators need recheck */
63         List       *iteml;
64         Relation        rel;
65         HeapTuple       tup;
66         Datum           values[Natts_pg_opclass];
67         char            nulls[Natts_pg_opclass];
68         AclResult       aclresult;
69         NameData        opcName;
70         int                     i;
71         ObjectAddress myself,
72                                 referenced;
73
74         /* Convert list of names to a name and namespace */
75         namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
76                                                                                                          &opcname);
77
78         /* Check we have creation rights in target namespace */
79         aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
80         if (aclresult != ACLCHECK_OK)
81                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
82                                            get_namespace_name(namespaceoid));
83
84         /* Get necessary info about access method */
85         tup = SearchSysCache(AMNAME,
86                                                  CStringGetDatum(stmt->amname),
87                                                  0, 0, 0);
88         if (!HeapTupleIsValid(tup))
89                 ereport(ERROR,
90                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
91                                  errmsg("access method \"%s\" does not exist",
92                                                 stmt->amname)));
93
94         amoid = HeapTupleGetOid(tup);
95         numOperators = ((Form_pg_am) GETSTRUCT(tup))->amstrategies;
96         numProcs = ((Form_pg_am) GETSTRUCT(tup))->amsupport;
97
98         /* XXX Should we make any privilege check against the AM? */
99
100         ReleaseSysCache(tup);
101
102         /*
103          * Currently, we require superuser privileges to create an opclass.
104          * This seems necessary because we have no way to validate that the
105          * offered set of operators and functions are consistent with the AM's
106          * expectations.  It would be nice to provide such a check someday, if
107          * it can be done without solving the halting problem :-(
108          */
109         if (!superuser())
110                 ereport(ERROR,
111                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
112                            errmsg("must be superuser to create an operator class")));
113
114         /* Look up the datatype */
115         typeoid = typenameTypeId(stmt->datatype);
116
117 #ifdef NOT_USED
118         /* XXX this is unnecessary given the superuser check above */
119         /* Check we have ownership of the datatype */
120         if (!pg_type_ownercheck(typeoid, GetUserId()))
121                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
122                                            format_type_be(typeoid));
123 #endif
124
125         /* Storage datatype is optional */
126         storageoid = InvalidOid;
127
128         /*
129          * Create work arrays to hold info about operators and procedures. We
130          * do this mainly so that we can detect duplicate strategy numbers and
131          * support-proc numbers.
132          */
133         operators = (Oid *) palloc0(sizeof(Oid) * numOperators);
134         procedures = (Oid *) palloc0(sizeof(Oid) * numProcs);
135         recheck = (bool *) palloc0(sizeof(bool) * numOperators);
136
137         /*
138          * Scan the "items" list to obtain additional info.
139          */
140         foreach(iteml, stmt->items)
141         {
142                 CreateOpClassItem *item = lfirst(iteml);
143                 Oid                     operOid;
144                 Oid                     funcOid;
145                 AclResult       aclresult;
146
147                 Assert(IsA(item, CreateOpClassItem));
148                 switch (item->itemtype)
149                 {
150                         case OPCLASS_ITEM_OPERATOR:
151                                 if (item->number <= 0 || item->number > numOperators)
152                                         ereport(ERROR,
153                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
154                                                          errmsg("invalid operator number %d,"
155                                                                         " must be between 1 and %d",
156                                                                         item->number, numOperators)));
157                                 if (operators[item->number - 1] != InvalidOid)
158                                         ereport(ERROR,
159                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
160                                           errmsg("operator number %d appears more than once",
161                                                          item->number)));
162                                 if (item->args != NIL)
163                                 {
164                                         TypeName   *typeName1 = (TypeName *) lfirst(item->args);
165                                         TypeName   *typeName2 = (TypeName *) lsecond(item->args);
166
167                                         operOid = LookupOperNameTypeNames(item->name,
168                                                                                                           typeName1,
169                                                                                                           typeName2,
170                                                                                                           false);
171                                 }
172                                 else
173                                 {
174                                         /* Default to binary op on input datatype */
175                                         operOid = LookupOperName(item->name, typeoid, typeoid,
176                                                                                          false);
177                                 }
178                                 /* Caller must have execute permission on operators */
179                                 funcOid = get_opcode(operOid);
180                                 aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
181                                                                                          ACL_EXECUTE);
182                                 if (aclresult != ACLCHECK_OK)
183                                         aclcheck_error(aclresult, ACL_KIND_PROC,
184                                                                    get_func_name(funcOid));
185                                 operators[item->number - 1] = operOid;
186                                 recheck[item->number - 1] = item->recheck;
187                                 break;
188                         case OPCLASS_ITEM_FUNCTION:
189                                 if (item->number <= 0 || item->number > numProcs)
190                                         ereport(ERROR,
191                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
192                                                          errmsg("invalid procedure number %d,"
193                                                                         " must be between 1 and %d",
194                                                                         item->number, numProcs)));
195                                 if (procedures[item->number - 1] != InvalidOid)
196                                         ereport(ERROR,
197                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
198                                                          errmsg("DefineOpClass: procedure number %d appears more than once",
199                                                                         item->number)));
200                                 funcOid = LookupFuncNameTypeNames(item->name, item->args,
201                                                                                                   false);
202                                 /* Caller must have execute permission on functions */
203                                 aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
204                                                                                          ACL_EXECUTE);
205                                 if (aclresult != ACLCHECK_OK)
206                                         aclcheck_error(aclresult, ACL_KIND_PROC,
207                                                                    get_func_name(funcOid));
208                                 procedures[item->number - 1] = funcOid;
209                                 break;
210                         case OPCLASS_ITEM_STORAGETYPE:
211                                 if (OidIsValid(storageoid))
212                                         ereport(ERROR,
213                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
214                                            errmsg("storage type specified more than once")));
215                                 storageoid = typenameTypeId(item->storedtype);
216                                 break;
217                         default:
218                                 elog(ERROR, "unrecognized item type: %d", item->itemtype);
219                                 break;
220                 }
221         }
222
223         /*
224          * If storagetype is specified, make sure it's legal.
225          */
226         if (OidIsValid(storageoid))
227         {
228                 /* Just drop the spec if same as column datatype */
229                 if (storageoid == typeoid)
230                         storageoid = InvalidOid;
231                 else
232                 {
233                         /*
234                          * Currently, only GiST allows storagetype different from
235                          * datatype.  This hardcoded test should be eliminated in
236                          * favor of adding another boolean column to pg_am ...
237                          */
238                         if (amoid != GIST_AM_OID)
239                                 ereport(ERROR,
240                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
241                                                  errmsg("storage type may not be different from datatype for access method \"%s\"",
242                                                                 stmt->amname)));
243                 }
244         }
245
246         rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
247
248         /*
249          * Make sure there is no existing opclass of this name (this is just
250          * to give a more friendly error message than "duplicate key").
251          */
252         if (SearchSysCacheExists(CLAAMNAMENSP,
253                                                          ObjectIdGetDatum(amoid),
254                                                          CStringGetDatum(opcname),
255                                                          ObjectIdGetDatum(namespaceoid),
256                                                          0))
257                 ereport(ERROR,
258                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
259                                  errmsg("operator class \"%s\" for access method \"%s\" already exists",
260                                                 opcname, stmt->amname)));
261
262         /*
263          * If we are creating a default opclass, check there isn't one
264          * already.  (Note we do not restrict this test to visible opclasses;
265          * this ensures that typcache.c can find unique solutions to its
266          * questions.)
267          */
268         if (stmt->isDefault)
269         {
270                 ScanKeyData skey[1];
271                 SysScanDesc scan;
272
273                 ScanKeyEntryInitialize(&skey[0], 0x0,
274                                                            Anum_pg_opclass_opcamid, F_OIDEQ,
275                                                            ObjectIdGetDatum(amoid));
276
277                 scan = systable_beginscan(rel, OpclassAmNameNspIndex, true,
278                                                                   SnapshotNow, 1, skey);
279
280                 while (HeapTupleIsValid(tup = systable_getnext(scan)))
281                 {
282                         Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
283
284                         if (opclass->opcintype == typeoid && opclass->opcdefault)
285                                 ereport(ERROR,
286                                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
287                                                  errmsg("could not make class \"%s\" be default for type %s",
288                                                                 opcname,
289                                                                 TypeNameToString(stmt->datatype)),
290                                                  errdetail("Class \"%s\" already is the default.",
291                                                                    NameStr(opclass->opcname))));
292                 }
293
294                 systable_endscan(scan);
295         }
296
297         /*
298          * Okay, let's create the pg_opclass entry.
299          */
300         for (i = 0; i < Natts_pg_opclass; ++i)
301         {
302                 nulls[i] = ' ';
303                 values[i] = (Datum) NULL;               /* redundant, but safe */
304         }
305
306         i = 0;
307         values[i++] = ObjectIdGetDatum(amoid);          /* opcamid */
308         namestrcpy(&opcName, opcname);
309         values[i++] = NameGetDatum(&opcName);           /* opcname */
310         values[i++] = ObjectIdGetDatum(namespaceoid);           /* opcnamespace */
311         values[i++] = Int32GetDatum(GetUserId());       /* opcowner */
312         values[i++] = ObjectIdGetDatum(typeoid);        /* opcintype */
313         values[i++] = BoolGetDatum(stmt->isDefault);            /* opcdefault */
314         values[i++] = ObjectIdGetDatum(storageoid); /* opckeytype */
315
316         tup = heap_formtuple(rel->rd_att, values, nulls);
317
318         opclassoid = simple_heap_insert(rel, tup);
319
320         CatalogUpdateIndexes(rel, tup);
321
322         heap_freetuple(tup);
323
324         /*
325          * Now add tuples to pg_amop and pg_amproc tying in the operators and
326          * functions.
327          */
328         storeOperators(opclassoid, numOperators, operators, recheck);
329         storeProcedures(opclassoid, numProcs, procedures);
330
331         /*
332          * Create dependencies.  Note: we do not create a dependency link to
333          * the AM, because we don't currently support DROP ACCESS METHOD.
334          */
335         myself.classId = RelationGetRelid(rel);
336         myself.objectId = opclassoid;
337         myself.objectSubId = 0;
338
339         /* dependency on namespace */
340         referenced.classId = get_system_catalog_relid(NamespaceRelationName);
341         referenced.objectId = namespaceoid;
342         referenced.objectSubId = 0;
343         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
344
345         /* dependency on indexed datatype */
346         referenced.classId = RelOid_pg_type;
347         referenced.objectId = typeoid;
348         referenced.objectSubId = 0;
349         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
350
351         /* dependency on storage datatype */
352         if (OidIsValid(storageoid))
353         {
354                 referenced.classId = RelOid_pg_type;
355                 referenced.objectId = storageoid;
356                 referenced.objectSubId = 0;
357                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
358         }
359
360         /* dependencies on operators */
361         referenced.classId = get_system_catalog_relid(OperatorRelationName);
362         for (i = 0; i < numOperators; i++)
363         {
364                 if (operators[i] == InvalidOid)
365                         continue;
366                 referenced.objectId = operators[i];
367                 referenced.objectSubId = 0;
368                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
369         }
370
371         /* dependencies on procedures */
372         for (i = 0; i < numProcs; i++)
373         {
374                 if (procedures[i] == InvalidOid)
375                         continue;
376                 referenced.classId = RelOid_pg_proc;
377                 referenced.objectId = procedures[i];
378                 referenced.objectSubId = 0;
379                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
380         }
381
382         heap_close(rel, RowExclusiveLock);
383 }
384
385 /*
386  * Dump the operators to pg_amop
387  */
388 static void
389 storeOperators(Oid opclassoid, int numOperators,
390                            Oid *operators, bool *recheck)
391 {
392         Relation        rel;
393         Datum           values[Natts_pg_amop];
394         char            nulls[Natts_pg_amop];
395         HeapTuple       tup;
396         int                     i,
397                                 j;
398
399         rel = heap_openr(AccessMethodOperatorRelationName, RowExclusiveLock);
400
401         for (j = 0; j < numOperators; j++)
402         {
403                 if (operators[j] == InvalidOid)
404                         continue;
405
406                 for (i = 0; i < Natts_pg_amop; ++i)
407                 {
408                         nulls[i] = ' ';
409                         values[i] = (Datum) NULL;
410                 }
411
412                 i = 0;
413                 values[i++] = ObjectIdGetDatum(opclassoid);             /* amopclaid */
414                 values[i++] = Int16GetDatum(j + 1);             /* amopstrategy */
415                 values[i++] = BoolGetDatum(recheck[j]); /* amopreqcheck */
416                 values[i++] = ObjectIdGetDatum(operators[j]);   /* amopopr */
417
418                 tup = heap_formtuple(rel->rd_att, values, nulls);
419
420                 simple_heap_insert(rel, tup);
421
422                 CatalogUpdateIndexes(rel, tup);
423
424                 heap_freetuple(tup);
425         }
426
427         heap_close(rel, RowExclusiveLock);
428 }
429
430 /*
431  * Dump the procedures (support routines) to pg_amproc
432  */
433 static void
434 storeProcedures(Oid opclassoid, int numProcs, Oid *procedures)
435 {
436         Relation        rel;
437         Datum           values[Natts_pg_amproc];
438         char            nulls[Natts_pg_amproc];
439         HeapTuple       tup;
440         int                     i,
441                                 j;
442
443         rel = heap_openr(AccessMethodProcedureRelationName, RowExclusiveLock);
444
445         for (j = 0; j < numProcs; j++)
446         {
447                 if (procedures[j] == InvalidOid)
448                         continue;
449
450                 for (i = 0; i < Natts_pg_amproc; ++i)
451                 {
452                         nulls[i] = ' ';
453                         values[i] = (Datum) NULL;
454                 }
455
456                 i = 0;
457                 values[i++] = ObjectIdGetDatum(opclassoid);             /* amopclaid */
458                 values[i++] = Int16GetDatum(j + 1);             /* amprocnum */
459                 values[i++] = ObjectIdGetDatum(procedures[j]);  /* amproc */
460
461                 tup = heap_formtuple(rel->rd_att, values, nulls);
462
463                 simple_heap_insert(rel, tup);
464
465                 CatalogUpdateIndexes(rel, tup);
466
467                 heap_freetuple(tup);
468         }
469
470         heap_close(rel, RowExclusiveLock);
471 }
472
473
474 /*
475  * RemoveOpClass
476  *              Deletes an opclass.
477  */
478 void
479 RemoveOpClass(RemoveOpClassStmt *stmt)
480 {
481         Oid                     amID,
482                                 opcID;
483         char       *schemaname;
484         char       *opcname;
485         HeapTuple       tuple;
486         ObjectAddress object;
487
488         /*
489          * Get the access method's OID.
490          */
491         amID = GetSysCacheOid(AMNAME,
492                                                   CStringGetDatum(stmt->amname),
493                                                   0, 0, 0);
494         if (!OidIsValid(amID))
495                 ereport(ERROR,
496                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
497                                  errmsg("access method \"%s\" does not exist",
498                                                 stmt->amname)));
499
500         /*
501          * Look up the opclass.
502          */
503
504         /* deconstruct the name list */
505         DeconstructQualifiedName(stmt->opclassname, &schemaname, &opcname);
506
507         if (schemaname)
508         {
509                 /* Look in specific schema only */
510                 Oid                     namespaceId;
511
512                 namespaceId = LookupExplicitNamespace(schemaname);
513                 tuple = SearchSysCache(CLAAMNAMENSP,
514                                                            ObjectIdGetDatum(amID),
515                                                            PointerGetDatum(opcname),
516                                                            ObjectIdGetDatum(namespaceId),
517                                                            0);
518         }
519         else
520         {
521                 /* Unqualified opclass name, so search the search path */
522                 opcID = OpclassnameGetOpcid(amID, opcname);
523                 if (!OidIsValid(opcID))
524                         ereport(ERROR,
525                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
526                                          errmsg("operator class \"%s\" does not exist for access method \"%s\"",
527                                                         opcname, stmt->amname)));
528                 tuple = SearchSysCache(CLAOID,
529                                                            ObjectIdGetDatum(opcID),
530                                                            0, 0, 0);
531         }
532
533         if (!HeapTupleIsValid(tuple))
534                 ereport(ERROR,
535                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
536                                  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
537                                         NameListToString(stmt->opclassname), stmt->amname)));
538
539         opcID = HeapTupleGetOid(tuple);
540
541         /* Permission check: must own opclass or its namespace */
542         if (!pg_opclass_ownercheck(opcID, GetUserId()) &&
543                 !pg_namespace_ownercheck(((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace,
544                                                                  GetUserId()))
545                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
546                                            NameListToString(stmt->opclassname));
547
548         ReleaseSysCache(tuple);
549
550         /*
551          * Do the deletion
552          */
553         object.classId = get_system_catalog_relid(OperatorClassRelationName);
554         object.objectId = opcID;
555         object.objectSubId = 0;
556
557         performDeletion(&object, stmt->behavior);
558 }
559
560 /*
561  * Guts of opclass deletion.
562  */
563 void
564 RemoveOpClassById(Oid opclassOid)
565 {
566         Relation        rel;
567         HeapTuple       tup;
568         ScanKeyData skey[1];
569         SysScanDesc scan;
570
571         /*
572          * First remove the pg_opclass entry itself.
573          */
574         rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
575
576         tup = SearchSysCache(CLAOID,
577                                                  ObjectIdGetDatum(opclassOid),
578                                                  0, 0, 0);
579         if (!HeapTupleIsValid(tup)) /* should not happen */
580                 elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
581
582         simple_heap_delete(rel, &tup->t_self);
583
584         ReleaseSysCache(tup);
585
586         heap_close(rel, RowExclusiveLock);
587
588         /*
589          * Remove associated entries in pg_amop.
590          */
591         ScanKeyEntryInitialize(&skey[0], 0,
592                                                    Anum_pg_amop_amopclaid, F_OIDEQ,
593                                                    ObjectIdGetDatum(opclassOid));
594
595         rel = heap_openr(AccessMethodOperatorRelationName, RowExclusiveLock);
596
597         scan = systable_beginscan(rel, AccessMethodStrategyIndex, true,
598                                                           SnapshotNow, 1, skey);
599
600         while (HeapTupleIsValid(tup = systable_getnext(scan)))
601                 simple_heap_delete(rel, &tup->t_self);
602
603         systable_endscan(scan);
604         heap_close(rel, RowExclusiveLock);
605
606         /*
607          * Remove associated entries in pg_amproc.
608          */
609         ScanKeyEntryInitialize(&skey[0], 0,
610                                                    Anum_pg_amproc_amopclaid, F_OIDEQ,
611                                                    ObjectIdGetDatum(opclassOid));
612
613         rel = heap_openr(AccessMethodProcedureRelationName, RowExclusiveLock);
614
615         scan = systable_beginscan(rel, AccessMethodProcedureIndex, true,
616                                                           SnapshotNow, 1, skey);
617
618         while (HeapTupleIsValid(tup = systable_getnext(scan)))
619                 simple_heap_delete(rel, &tup->t_self);
620
621         systable_endscan(scan);
622         heap_close(rel, RowExclusiveLock);
623 }
624
625
626 /*
627  * Rename opclass
628  */
629 void
630 RenameOpClass(List *name, const char *access_method, const char *newname)
631 {
632         Oid                     opcOid;
633         Oid                     amOid;
634         Oid                     namespaceOid;
635         char       *schemaname;
636         char       *opcname;
637         HeapTuple       tup;
638         Relation        rel;
639         AclResult       aclresult;
640
641         amOid = GetSysCacheOid(AMNAME,
642                                                    CStringGetDatum(access_method),
643                                                    0, 0, 0);
644         if (!OidIsValid(amOid))
645                 ereport(ERROR,
646                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
647                                  errmsg("access method \"%s\" does not exist",
648                                                 access_method)));
649
650         rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
651
652         /*
653          * Look up the opclass
654          */
655         DeconstructQualifiedName(name, &schemaname, &opcname);
656
657         if (schemaname)
658         {
659                 namespaceOid = LookupExplicitNamespace(schemaname);
660
661                 tup = SearchSysCacheCopy(CLAAMNAMENSP,
662                                                                  ObjectIdGetDatum(amOid),
663                                                                  PointerGetDatum(opcname),
664                                                                  ObjectIdGetDatum(namespaceOid),
665                                                                  0);
666                 if (!HeapTupleIsValid(tup))
667                         ereport(ERROR,
668                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
669                                          errmsg("operator class \"%s\" does not exist for access method \"%s\"",
670                                                         opcname, access_method)));
671
672                 opcOid = HeapTupleGetOid(tup);
673         }
674         else
675         {
676                 opcOid = OpclassnameGetOpcid(amOid, opcname);
677                 if (!OidIsValid(opcOid))
678                         ereport(ERROR,
679                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
680                                          errmsg("operator class \"%s\" does not exist for access method \"%s\"",
681                                                         opcname, access_method)));
682
683                 tup = SearchSysCacheCopy(CLAOID,
684                                                                  ObjectIdGetDatum(opcOid),
685                                                                  0, 0, 0);
686                 if (!HeapTupleIsValid(tup))             /* should not happen */
687                         elog(ERROR, "cache lookup failed for opclass %u", opcOid);
688
689                 namespaceOid = ((Form_pg_opclass) GETSTRUCT(tup))->opcnamespace;
690         }
691
692         /* make sure the new name doesn't exist */
693         if (SearchSysCacheExists(CLAAMNAMENSP,
694                                                          ObjectIdGetDatum(amOid),
695                                                          CStringGetDatum(newname),
696                                                          ObjectIdGetDatum(namespaceOid),
697                                                          0))
698         {
699                 ereport(ERROR,
700                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
701                                  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
702                                                 newname, access_method,
703                                                 get_namespace_name(namespaceOid))));
704         }
705
706         /* must be owner */
707         if (!pg_opclass_ownercheck(opcOid, GetUserId()))
708                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
709                                            NameListToString(name));
710
711         /* must have CREATE privilege on namespace */
712         aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
713         if (aclresult != ACLCHECK_OK)
714                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
715                                            get_namespace_name(namespaceOid));
716
717         /* rename */
718         namestrcpy(&(((Form_pg_opclass) GETSTRUCT(tup))->opcname), newname);
719         simple_heap_update(rel, &tup->t_self, tup);
720         CatalogUpdateIndexes(rel, tup);
721
722         heap_close(rel, NoLock);
723         heap_freetuple(tup);
724 }