]> granicus.if.org Git - postgresql/blob - src/backend/commands/opclasscmds.c
Create a "sort support" interface API for faster sorting.
[postgresql] / src / backend / commands / opclasscmds.c
1 /*-------------------------------------------------------------------------
2  *
3  * opclasscmds.c
4  *
5  *        Routines for opclass (and opfamily) manipulation commands
6  *
7  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        src/backend/commands/opclasscmds.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include <limits.h>
19
20 #include "access/genam.h"
21 #include "access/heapam.h"
22 #include "access/nbtree.h"
23 #include "access/sysattr.h"
24 #include "catalog/dependency.h"
25 #include "catalog/indexing.h"
26 #include "catalog/objectaccess.h"
27 #include "catalog/pg_amop.h"
28 #include "catalog/pg_amproc.h"
29 #include "catalog/pg_namespace.h"
30 #include "catalog/pg_opclass.h"
31 #include "catalog/pg_operator.h"
32 #include "catalog/pg_opfamily.h"
33 #include "catalog/pg_proc.h"
34 #include "catalog/pg_type.h"
35 #include "commands/alter.h"
36 #include "commands/defrem.h"
37 #include "miscadmin.h"
38 #include "parser/parse_func.h"
39 #include "parser/parse_oper.h"
40 #include "parser/parse_type.h"
41 #include "utils/builtins.h"
42 #include "utils/fmgroids.h"
43 #include "utils/lsyscache.h"
44 #include "utils/rel.h"
45 #include "utils/syscache.h"
46 #include "utils/tqual.h"
47
48
49 /*
50  * We use lists of this struct type to keep track of both operators and
51  * procedures while building or adding to an opfamily.
52  */
53 typedef struct
54 {
55         Oid                     object;                 /* operator or support proc's OID */
56         int                     number;                 /* strategy or support proc number */
57         Oid                     lefttype;               /* lefttype */
58         Oid                     righttype;              /* righttype */
59         Oid                     sortfamily;             /* ordering operator's sort opfamily, or 0 */
60 } OpFamilyMember;
61
62
63 static void AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
64                                  int maxOpNumber, int maxProcNumber,
65                                  List *items);
66 static void AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
67                                   int maxOpNumber, int maxProcNumber,
68                                   List *items);
69 static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
70 static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
71 static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
72 static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
73 static void storeOperators(List *opfamilyname, Oid amoid,
74                            Oid opfamilyoid, Oid opclassoid,
75                            List *operators, bool isAdd);
76 static void storeProcedures(List *opfamilyname, Oid amoid,
77                                 Oid opfamilyoid, Oid opclassoid,
78                                 List *procedures, bool isAdd);
79 static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
80                           List *operators);
81 static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
82                            List *procedures);
83 static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
84                                                    Oid newOwnerId);
85 static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
86                                                         Oid newOwnerId);
87
88
89 /*
90  * OpFamilyCacheLookup
91  *              Look up an existing opfamily by name.
92  *
93  * Returns a syscache tuple reference, or NULL if not found.
94  */
95 static HeapTuple
96 OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
97 {
98         char       *schemaname;
99         char       *opfname;
100         HeapTuple       htup;
101
102         /* deconstruct the name list */
103         DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
104
105         if (schemaname)
106         {
107                 /* Look in specific schema only */
108                 Oid                     namespaceId;
109
110                 namespaceId = LookupExplicitNamespace(schemaname);
111                 htup = SearchSysCache3(OPFAMILYAMNAMENSP,
112                                                            ObjectIdGetDatum(amID),
113                                                            PointerGetDatum(opfname),
114                                                            ObjectIdGetDatum(namespaceId));
115         }
116         else
117         {
118                 /* Unqualified opfamily name, so search the search path */
119                 Oid                     opfID = OpfamilynameGetOpfid(amID, opfname);
120
121                 if (!OidIsValid(opfID))
122                         htup = NULL;
123                 else
124                         htup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfID));
125         }
126
127         if (!HeapTupleIsValid(htup) && !missing_ok)
128         {
129                 HeapTuple       amtup;
130
131                 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
132                 if (!HeapTupleIsValid(amtup))
133                         elog(ERROR, "cache lookup failed for access method %u", amID);
134                 ereport(ERROR,
135                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
136                                  errmsg("operator family \"%s\" does not exist for access method \"%s\"",
137                                                 NameListToString(opfamilyname),
138                                                 NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
139         }
140
141         return htup;
142 }
143
144 /*
145  * get_opfamily_oid
146  *        find an opfamily OID by possibly qualified name
147  *
148  * If not found, returns InvalidOid if missing_ok, else throws error.
149  */
150 Oid
151 get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
152 {
153         HeapTuple       htup;
154         Oid                     opfID;
155
156         htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
157         if (!HeapTupleIsValid(htup))
158                 return InvalidOid;
159         opfID = HeapTupleGetOid(htup);
160         ReleaseSysCache(htup);
161
162         return opfID;
163 }
164
165 /*
166  * OpClassCacheLookup
167  *              Look up an existing opclass by name.
168  *
169  * Returns a syscache tuple reference, or NULL if not found.
170  */
171 static HeapTuple
172 OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
173 {
174         char       *schemaname;
175         char       *opcname;
176         HeapTuple       htup;
177
178         /* deconstruct the name list */
179         DeconstructQualifiedName(opclassname, &schemaname, &opcname);
180
181         if (schemaname)
182         {
183                 /* Look in specific schema only */
184                 Oid                     namespaceId;
185
186                 namespaceId = LookupExplicitNamespace(schemaname);
187                 htup = SearchSysCache3(CLAAMNAMENSP,
188                                                            ObjectIdGetDatum(amID),
189                                                            PointerGetDatum(opcname),
190                                                            ObjectIdGetDatum(namespaceId));
191         }
192         else
193         {
194                 /* Unqualified opclass name, so search the search path */
195                 Oid                     opcID = OpclassnameGetOpcid(amID, opcname);
196
197                 if (!OidIsValid(opcID))
198                         htup = NULL;
199                 else
200                         htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
201         }
202
203         if (!HeapTupleIsValid(htup) && !missing_ok)
204         {
205                 HeapTuple       amtup;
206
207                 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
208                 if (!HeapTupleIsValid(amtup))
209                         elog(ERROR, "cache lookup failed for access method %u", amID);
210                 ereport(ERROR,
211                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
212                                  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
213                                                 NameListToString(opclassname),
214                                                 NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
215         }
216
217         return htup;
218 }
219
220 /*
221  * get_opclass_oid
222  *        find an opclass OID by possibly qualified name
223  *
224  * If not found, returns InvalidOid if missing_ok, else throws error.
225  */
226 Oid
227 get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
228 {
229         HeapTuple       htup;
230         Oid                     opcID;
231
232         htup = OpClassCacheLookup(amID, opclassname, missing_ok);
233         if (!HeapTupleIsValid(htup))
234                 return InvalidOid;
235         opcID = HeapTupleGetOid(htup);
236         ReleaseSysCache(htup);
237
238         return opcID;
239 }
240
241 /*
242  * CreateOpFamily
243  *              Internal routine to make the catalog entry for a new operator family.
244  *
245  * Caller must have done permissions checks etc. already.
246  */
247 static Oid
248 CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
249 {
250         Oid                     opfamilyoid;
251         Relation        rel;
252         HeapTuple       tup;
253         Datum           values[Natts_pg_opfamily];
254         bool            nulls[Natts_pg_opfamily];
255         NameData        opfName;
256         ObjectAddress myself,
257                                 referenced;
258
259         rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
260
261         /*
262          * Make sure there is no existing opfamily of this name (this is just to
263          * give a more friendly error message than "duplicate key").
264          */
265         if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
266                                                           ObjectIdGetDatum(amoid),
267                                                           CStringGetDatum(opfname),
268                                                           ObjectIdGetDatum(namespaceoid)))
269                 ereport(ERROR,
270                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
271                                  errmsg("operator family \"%s\" for access method \"%s\" already exists",
272                                                 opfname, amname)));
273
274         /*
275          * Okay, let's create the pg_opfamily entry.
276          */
277         memset(values, 0, sizeof(values));
278         memset(nulls, false, sizeof(nulls));
279
280         values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
281         namestrcpy(&opfName, opfname);
282         values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
283         values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
284         values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
285
286         tup = heap_form_tuple(rel->rd_att, values, nulls);
287
288         opfamilyoid = simple_heap_insert(rel, tup);
289
290         CatalogUpdateIndexes(rel, tup);
291
292         heap_freetuple(tup);
293
294         /*
295          * Create dependencies for the opfamily proper.  Note: we do not create a
296          * dependency link to the AM, because we don't currently support DROP
297          * ACCESS METHOD.
298          */
299         myself.classId = OperatorFamilyRelationId;
300         myself.objectId = opfamilyoid;
301         myself.objectSubId = 0;
302
303         /* dependency on namespace */
304         referenced.classId = NamespaceRelationId;
305         referenced.objectId = namespaceoid;
306         referenced.objectSubId = 0;
307         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
308
309         /* dependency on owner */
310         recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
311
312         /* dependency on extension */
313         recordDependencyOnCurrentExtension(&myself, false);
314
315         /* Post creation hook for new operator family */
316         InvokeObjectAccessHook(OAT_POST_CREATE,
317                                                    OperatorFamilyRelationId, opfamilyoid, 0);
318
319         heap_close(rel, RowExclusiveLock);
320
321         return opfamilyoid;
322 }
323
324 /*
325  * DefineOpClass
326  *              Define a new index operator class.
327  */
328 void
329 DefineOpClass(CreateOpClassStmt *stmt)
330 {
331         char       *opcname;            /* name of opclass we're creating */
332         Oid                     amoid,                  /* our AM's oid */
333                                 typeoid,                /* indexable datatype oid */
334                                 storageoid,             /* storage datatype oid, if any */
335                                 namespaceoid,   /* namespace to create opclass in */
336                                 opfamilyoid,    /* oid of containing opfamily */
337                                 opclassoid;             /* oid of opclass we create */
338         int                     maxOpNumber,    /* amstrategies value */
339                                 maxProcNumber;  /* amsupport value */
340         bool            amstorage;              /* amstorage flag */
341         List       *operators;          /* OpFamilyMember list for operators */
342         List       *procedures;         /* OpFamilyMember list for support procs */
343         ListCell   *l;
344         Relation        rel;
345         HeapTuple       tup;
346         Form_pg_am      pg_am;
347         Datum           values[Natts_pg_opclass];
348         bool            nulls[Natts_pg_opclass];
349         AclResult       aclresult;
350         NameData        opcName;
351         ObjectAddress myself,
352                                 referenced;
353
354         /* Convert list of names to a name and namespace */
355         namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
356                                                                                                          &opcname);
357
358         /* Check we have creation rights in target namespace */
359         aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
360         if (aclresult != ACLCHECK_OK)
361                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
362                                            get_namespace_name(namespaceoid));
363
364         /* Get necessary info about access method */
365         tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
366         if (!HeapTupleIsValid(tup))
367                 ereport(ERROR,
368                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
369                                  errmsg("access method \"%s\" does not exist",
370                                                 stmt->amname)));
371
372         amoid = HeapTupleGetOid(tup);
373         pg_am = (Form_pg_am) GETSTRUCT(tup);
374         maxOpNumber = pg_am->amstrategies;
375         /* if amstrategies is zero, just enforce that op numbers fit in int16 */
376         if (maxOpNumber <= 0)
377                 maxOpNumber = SHRT_MAX;
378         maxProcNumber = pg_am->amsupport;
379         amstorage = pg_am->amstorage;
380
381         /* XXX Should we make any privilege check against the AM? */
382
383         ReleaseSysCache(tup);
384
385         /*
386          * The question of appropriate permissions for CREATE OPERATOR CLASS is
387          * interesting.  Creating an opclass is tantamount to granting public
388          * execute access on the functions involved, since the index machinery
389          * generally does not check access permission before using the functions.
390          * A minimum expectation therefore is that the caller have execute
391          * privilege with grant option.  Since we don't have a way to make the
392          * opclass go away if the grant option is revoked, we choose instead to
393          * require ownership of the functions.  It's also not entirely clear what
394          * permissions should be required on the datatype, but ownership seems
395          * like a safe choice.
396          *
397          * Currently, we require superuser privileges to create an opclass. This
398          * seems necessary because we have no way to validate that the offered set
399          * of operators and functions are consistent with the AM's expectations.
400          * It would be nice to provide such a check someday, if it can be done
401          * without solving the halting problem :-(
402          *
403          * XXX re-enable NOT_USED code sections below if you remove this test.
404          */
405         if (!superuser())
406                 ereport(ERROR,
407                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
408                                  errmsg("must be superuser to create an operator class")));
409
410         /* Look up the datatype */
411         typeoid = typenameTypeId(NULL, stmt->datatype);
412
413 #ifdef NOT_USED
414         /* XXX this is unnecessary given the superuser check above */
415         /* Check we have ownership of the datatype */
416         if (!pg_type_ownercheck(typeoid, GetUserId()))
417                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
418                                            format_type_be(typeoid));
419 #endif
420
421         /*
422          * Look up the containing operator family, or create one if FAMILY option
423          * was omitted and there's not a match already.
424          */
425         if (stmt->opfamilyname)
426         {
427                 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
428         }
429         else
430         {
431                 /* Lookup existing family of same name and namespace */
432                 tup = SearchSysCache3(OPFAMILYAMNAMENSP,
433                                                           ObjectIdGetDatum(amoid),
434                                                           PointerGetDatum(opcname),
435                                                           ObjectIdGetDatum(namespaceoid));
436                 if (HeapTupleIsValid(tup))
437                 {
438                         opfamilyoid = HeapTupleGetOid(tup);
439
440                         /*
441                          * XXX given the superuser check above, there's no need for an
442                          * ownership check here
443                          */
444                         ReleaseSysCache(tup);
445                 }
446                 else
447                 {
448                         /*
449                          * Create it ... again no need for more permissions ...
450                          */
451                         opfamilyoid = CreateOpFamily(stmt->amname, opcname,
452                                                                                  namespaceoid, amoid);
453                 }
454         }
455
456         operators = NIL;
457         procedures = NIL;
458
459         /* Storage datatype is optional */
460         storageoid = InvalidOid;
461
462         /*
463          * Scan the "items" list to obtain additional info.
464          */
465         foreach(l, stmt->items)
466         {
467                 CreateOpClassItem *item = lfirst(l);
468                 Oid                     operOid;
469                 Oid                     funcOid;
470                 Oid                     sortfamilyOid;
471                 OpFamilyMember *member;
472
473                 Assert(IsA(item, CreateOpClassItem));
474                 switch (item->itemtype)
475                 {
476                         case OPCLASS_ITEM_OPERATOR:
477                                 if (item->number <= 0 || item->number > maxOpNumber)
478                                         ereport(ERROR,
479                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
480                                                          errmsg("invalid operator number %d,"
481                                                                         " must be between 1 and %d",
482                                                                         item->number, maxOpNumber)));
483                                 if (item->args != NIL)
484                                 {
485                                         TypeName   *typeName1 = (TypeName *) linitial(item->args);
486                                         TypeName   *typeName2 = (TypeName *) lsecond(item->args);
487
488                                         operOid = LookupOperNameTypeNames(NULL, item->name,
489                                                                                                           typeName1, typeName2,
490                                                                                                           false, -1);
491                                 }
492                                 else
493                                 {
494                                         /* Default to binary op on input datatype */
495                                         operOid = LookupOperName(NULL, item->name,
496                                                                                          typeoid, typeoid,
497                                                                                          false, -1);
498                                 }
499
500                                 if (item->order_family)
501                                         sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
502                                                                                                          item->order_family,
503                                                                                                          false);
504                                 else
505                                         sortfamilyOid = InvalidOid;
506
507 #ifdef NOT_USED
508                                 /* XXX this is unnecessary given the superuser check above */
509                                 /* Caller must own operator and its underlying function */
510                                 if (!pg_oper_ownercheck(operOid, GetUserId()))
511                                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
512                                                                    get_opname(operOid));
513                                 funcOid = get_opcode(operOid);
514                                 if (!pg_proc_ownercheck(funcOid, GetUserId()))
515                                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
516                                                                    get_func_name(funcOid));
517 #endif
518
519                                 /* Save the info */
520                                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
521                                 member->object = operOid;
522                                 member->number = item->number;
523                                 member->sortfamily = sortfamilyOid;
524                                 assignOperTypes(member, amoid, typeoid);
525                                 addFamilyMember(&operators, member, false);
526                                 break;
527                         case OPCLASS_ITEM_FUNCTION:
528                                 if (item->number <= 0 || item->number > maxProcNumber)
529                                         ereport(ERROR,
530                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
531                                                          errmsg("invalid procedure number %d,"
532                                                                         " must be between 1 and %d",
533                                                                         item->number, maxProcNumber)));
534                                 funcOid = LookupFuncNameTypeNames(item->name, item->args,
535                                                                                                   false);
536 #ifdef NOT_USED
537                                 /* XXX this is unnecessary given the superuser check above */
538                                 /* Caller must own function */
539                                 if (!pg_proc_ownercheck(funcOid, GetUserId()))
540                                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
541                                                                    get_func_name(funcOid));
542 #endif
543
544                                 /* Save the info */
545                                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
546                                 member->object = funcOid;
547                                 member->number = item->number;
548
549                                 /* allow overriding of the function's actual arg types */
550                                 if (item->class_args)
551                                         processTypesSpec(item->class_args,
552                                                                          &member->lefttype, &member->righttype);
553
554                                 assignProcTypes(member, amoid, typeoid);
555                                 addFamilyMember(&procedures, member, true);
556                                 break;
557                         case OPCLASS_ITEM_STORAGETYPE:
558                                 if (OidIsValid(storageoid))
559                                         ereport(ERROR,
560                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
561                                                    errmsg("storage type specified more than once")));
562                                 storageoid = typenameTypeId(NULL, item->storedtype);
563
564 #ifdef NOT_USED
565                                 /* XXX this is unnecessary given the superuser check above */
566                                 /* Check we have ownership of the datatype */
567                                 if (!pg_type_ownercheck(storageoid, GetUserId()))
568                                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
569                                                                    format_type_be(storageoid));
570 #endif
571                                 break;
572                         default:
573                                 elog(ERROR, "unrecognized item type: %d", item->itemtype);
574                                 break;
575                 }
576         }
577
578         /*
579          * If storagetype is specified, make sure it's legal.
580          */
581         if (OidIsValid(storageoid))
582         {
583                 /* Just drop the spec if same as column datatype */
584                 if (storageoid == typeoid)
585                         storageoid = InvalidOid;
586                 else if (!amstorage)
587                         ereport(ERROR,
588                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
589                                          errmsg("storage type cannot be different from data type for access method \"%s\"",
590                                                         stmt->amname)));
591         }
592
593         rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
594
595         /*
596          * Make sure there is no existing opclass of this name (this is just to
597          * give a more friendly error message than "duplicate key").
598          */
599         if (SearchSysCacheExists3(CLAAMNAMENSP,
600                                                           ObjectIdGetDatum(amoid),
601                                                           CStringGetDatum(opcname),
602                                                           ObjectIdGetDatum(namespaceoid)))
603                 ereport(ERROR,
604                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
605                                  errmsg("operator class \"%s\" for access method \"%s\" already exists",
606                                                 opcname, stmt->amname)));
607
608         /*
609          * If we are creating a default opclass, check there isn't one already.
610          * (Note we do not restrict this test to visible opclasses; this ensures
611          * that typcache.c can find unique solutions to its questions.)
612          */
613         if (stmt->isDefault)
614         {
615                 ScanKeyData skey[1];
616                 SysScanDesc scan;
617
618                 ScanKeyInit(&skey[0],
619                                         Anum_pg_opclass_opcmethod,
620                                         BTEqualStrategyNumber, F_OIDEQ,
621                                         ObjectIdGetDatum(amoid));
622
623                 scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
624                                                                   SnapshotNow, 1, skey);
625
626                 while (HeapTupleIsValid(tup = systable_getnext(scan)))
627                 {
628                         Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
629
630                         if (opclass->opcintype == typeoid && opclass->opcdefault)
631                                 ereport(ERROR,
632                                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
633                                                  errmsg("could not make operator class \"%s\" be default for type %s",
634                                                                 opcname,
635                                                                 TypeNameToString(stmt->datatype)),
636                                    errdetail("Operator class \"%s\" already is the default.",
637                                                          NameStr(opclass->opcname))));
638                 }
639
640                 systable_endscan(scan);
641         }
642
643         /*
644          * Okay, let's create the pg_opclass entry.
645          */
646         memset(values, 0, sizeof(values));
647         memset(nulls, false, sizeof(nulls));
648
649         values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
650         namestrcpy(&opcName, opcname);
651         values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
652         values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
653         values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
654         values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
655         values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
656         values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
657         values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
658
659         tup = heap_form_tuple(rel->rd_att, values, nulls);
660
661         opclassoid = simple_heap_insert(rel, tup);
662
663         CatalogUpdateIndexes(rel, tup);
664
665         heap_freetuple(tup);
666
667         /*
668          * Now add tuples to pg_amop and pg_amproc tying in the operators and
669          * functions.  Dependencies on them are inserted, too.
670          */
671         storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
672                                    opclassoid, operators, false);
673         storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
674                                         opclassoid, procedures, false);
675
676         /*
677          * Create dependencies for the opclass proper.  Note: we do not create a
678          * dependency link to the AM, because we don't currently support DROP
679          * ACCESS METHOD.
680          */
681         myself.classId = OperatorClassRelationId;
682         myself.objectId = opclassoid;
683         myself.objectSubId = 0;
684
685         /* dependency on namespace */
686         referenced.classId = NamespaceRelationId;
687         referenced.objectId = namespaceoid;
688         referenced.objectSubId = 0;
689         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
690
691         /* dependency on opfamily */
692         referenced.classId = OperatorFamilyRelationId;
693         referenced.objectId = opfamilyoid;
694         referenced.objectSubId = 0;
695         recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
696
697         /* dependency on indexed datatype */
698         referenced.classId = TypeRelationId;
699         referenced.objectId = typeoid;
700         referenced.objectSubId = 0;
701         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
702
703         /* dependency on storage datatype */
704         if (OidIsValid(storageoid))
705         {
706                 referenced.classId = TypeRelationId;
707                 referenced.objectId = storageoid;
708                 referenced.objectSubId = 0;
709                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
710         }
711
712         /* dependency on owner */
713         recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
714
715         /* dependency on extension */
716         recordDependencyOnCurrentExtension(&myself, false);
717
718         /* Post creation hook for new operator class */
719         InvokeObjectAccessHook(OAT_POST_CREATE,
720                                                    OperatorClassRelationId, opclassoid, 0);
721
722         heap_close(rel, RowExclusiveLock);
723 }
724
725
726 /*
727  * DefineOpFamily
728  *              Define a new index operator family.
729  */
730 void
731 DefineOpFamily(CreateOpFamilyStmt *stmt)
732 {
733         char       *opfname;            /* name of opfamily we're creating */
734         Oid                     amoid,                  /* our AM's oid */
735                                 namespaceoid;   /* namespace to create opfamily in */
736         AclResult       aclresult;
737
738         /* Convert list of names to a name and namespace */
739         namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
740                                                                                                          &opfname);
741
742         /* Check we have creation rights in target namespace */
743         aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
744         if (aclresult != ACLCHECK_OK)
745                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
746                                            get_namespace_name(namespaceoid));
747
748         /* Get access method OID, throwing an error if it doesn't exist. */
749         amoid = get_am_oid(stmt->amname, false);
750
751         /* XXX Should we make any privilege check against the AM? */
752
753         /*
754          * Currently, we require superuser privileges to create an opfamily. See
755          * comments in DefineOpClass.
756          */
757         if (!superuser())
758                 ereport(ERROR,
759                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
760                                  errmsg("must be superuser to create an operator family")));
761
762         /* Insert pg_opfamily catalog entry */
763         (void) CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
764 }
765
766
767 /*
768  * AlterOpFamily
769  *              Add or remove operators/procedures within an existing operator family.
770  *
771  * Note: this implements only ALTER OPERATOR FAMILY ... ADD/DROP.  Some
772  * other commands called ALTER OPERATOR FAMILY exist, but go through
773  * different code paths.
774  */
775 void
776 AlterOpFamily(AlterOpFamilyStmt *stmt)
777 {
778         Oid                     amoid,                  /* our AM's oid */
779                                 opfamilyoid;    /* oid of opfamily */
780         int                     maxOpNumber,    /* amstrategies value */
781                                 maxProcNumber;  /* amsupport value */
782         HeapTuple       tup;
783         Form_pg_am      pg_am;
784
785         /* Get necessary info about access method */
786         tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
787         if (!HeapTupleIsValid(tup))
788                 ereport(ERROR,
789                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
790                                  errmsg("access method \"%s\" does not exist",
791                                                 stmt->amname)));
792
793         amoid = HeapTupleGetOid(tup);
794         pg_am = (Form_pg_am) GETSTRUCT(tup);
795         maxOpNumber = pg_am->amstrategies;
796         /* if amstrategies is zero, just enforce that op numbers fit in int16 */
797         if (maxOpNumber <= 0)
798                 maxOpNumber = SHRT_MAX;
799         maxProcNumber = pg_am->amsupport;
800
801         /* XXX Should we make any privilege check against the AM? */
802
803         ReleaseSysCache(tup);
804
805         /* Look up the opfamily */
806         opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
807
808         /*
809          * Currently, we require superuser privileges to alter an opfamily.
810          *
811          * XXX re-enable NOT_USED code sections below if you remove this test.
812          */
813         if (!superuser())
814                 ereport(ERROR,
815                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
816                                  errmsg("must be superuser to alter an operator family")));
817
818         /*
819          * ADD and DROP cases need separate code from here on down.
820          */
821         if (stmt->isDrop)
822                 AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
823                                                   maxOpNumber, maxProcNumber,
824                                                   stmt->items);
825         else
826                 AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
827                                                  maxOpNumber, maxProcNumber,
828                                                  stmt->items);
829 }
830
831 /*
832  * ADD part of ALTER OP FAMILY
833  */
834 static void
835 AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
836                                  int maxOpNumber, int maxProcNumber,
837                                  List *items)
838 {
839         List       *operators;          /* OpFamilyMember list for operators */
840         List       *procedures;         /* OpFamilyMember list for support procs */
841         ListCell   *l;
842
843         operators = NIL;
844         procedures = NIL;
845
846         /*
847          * Scan the "items" list to obtain additional info.
848          */
849         foreach(l, items)
850         {
851                 CreateOpClassItem *item = lfirst(l);
852                 Oid                     operOid;
853                 Oid                     funcOid;
854                 Oid                     sortfamilyOid;
855                 OpFamilyMember *member;
856
857                 Assert(IsA(item, CreateOpClassItem));
858                 switch (item->itemtype)
859                 {
860                         case OPCLASS_ITEM_OPERATOR:
861                                 if (item->number <= 0 || item->number > maxOpNumber)
862                                         ereport(ERROR,
863                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
864                                                          errmsg("invalid operator number %d,"
865                                                                         " must be between 1 and %d",
866                                                                         item->number, maxOpNumber)));
867                                 if (item->args != NIL)
868                                 {
869                                         TypeName   *typeName1 = (TypeName *) linitial(item->args);
870                                         TypeName   *typeName2 = (TypeName *) lsecond(item->args);
871
872                                         operOid = LookupOperNameTypeNames(NULL, item->name,
873                                                                                                           typeName1, typeName2,
874                                                                                                           false, -1);
875                                 }
876                                 else
877                                 {
878                                         ereport(ERROR,
879                                                         (errcode(ERRCODE_SYNTAX_ERROR),
880                                                          errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
881                                         operOid = InvalidOid;           /* keep compiler quiet */
882                                 }
883
884                                 if (item->order_family)
885                                         sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
886                                                                                                          item->order_family,
887                                                                                                          false);
888                                 else
889                                         sortfamilyOid = InvalidOid;
890
891 #ifdef NOT_USED
892                                 /* XXX this is unnecessary given the superuser check above */
893                                 /* Caller must own operator and its underlying function */
894                                 if (!pg_oper_ownercheck(operOid, GetUserId()))
895                                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
896                                                                    get_opname(operOid));
897                                 funcOid = get_opcode(operOid);
898                                 if (!pg_proc_ownercheck(funcOid, GetUserId()))
899                                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
900                                                                    get_func_name(funcOid));
901 #endif
902
903                                 /* Save the info */
904                                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
905                                 member->object = operOid;
906                                 member->number = item->number;
907                                 member->sortfamily = sortfamilyOid;
908                                 assignOperTypes(member, amoid, InvalidOid);
909                                 addFamilyMember(&operators, member, false);
910                                 break;
911                         case OPCLASS_ITEM_FUNCTION:
912                                 if (item->number <= 0 || item->number > maxProcNumber)
913                                         ereport(ERROR,
914                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
915                                                          errmsg("invalid procedure number %d,"
916                                                                         " must be between 1 and %d",
917                                                                         item->number, maxProcNumber)));
918                                 funcOid = LookupFuncNameTypeNames(item->name, item->args,
919                                                                                                   false);
920 #ifdef NOT_USED
921                                 /* XXX this is unnecessary given the superuser check above */
922                                 /* Caller must own function */
923                                 if (!pg_proc_ownercheck(funcOid, GetUserId()))
924                                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
925                                                                    get_func_name(funcOid));
926 #endif
927
928                                 /* Save the info */
929                                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
930                                 member->object = funcOid;
931                                 member->number = item->number;
932
933                                 /* allow overriding of the function's actual arg types */
934                                 if (item->class_args)
935                                         processTypesSpec(item->class_args,
936                                                                          &member->lefttype, &member->righttype);
937
938                                 assignProcTypes(member, amoid, InvalidOid);
939                                 addFamilyMember(&procedures, member, true);
940                                 break;
941                         case OPCLASS_ITEM_STORAGETYPE:
942                                 ereport(ERROR,
943                                                 (errcode(ERRCODE_SYNTAX_ERROR),
944                                                  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
945                                 break;
946                         default:
947                                 elog(ERROR, "unrecognized item type: %d", item->itemtype);
948                                 break;
949                 }
950         }
951
952         /*
953          * Add tuples to pg_amop and pg_amproc tying in the operators and
954          * functions.  Dependencies on them are inserted, too.
955          */
956         storeOperators(opfamilyname, amoid, opfamilyoid,
957                                    InvalidOid, operators, true);
958         storeProcedures(opfamilyname, amoid, opfamilyoid,
959                                         InvalidOid, procedures, true);
960 }
961
962 /*
963  * DROP part of ALTER OP FAMILY
964  */
965 static void
966 AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
967                                   int maxOpNumber, int maxProcNumber,
968                                   List *items)
969 {
970         List       *operators;          /* OpFamilyMember list for operators */
971         List       *procedures;         /* OpFamilyMember list for support procs */
972         ListCell   *l;
973
974         operators = NIL;
975         procedures = NIL;
976
977         /*
978          * Scan the "items" list to obtain additional info.
979          */
980         foreach(l, items)
981         {
982                 CreateOpClassItem *item = lfirst(l);
983                 Oid                     lefttype,
984                                         righttype;
985                 OpFamilyMember *member;
986
987                 Assert(IsA(item, CreateOpClassItem));
988                 switch (item->itemtype)
989                 {
990                         case OPCLASS_ITEM_OPERATOR:
991                                 if (item->number <= 0 || item->number > maxOpNumber)
992                                         ereport(ERROR,
993                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
994                                                          errmsg("invalid operator number %d,"
995                                                                         " must be between 1 and %d",
996                                                                         item->number, maxOpNumber)));
997                                 processTypesSpec(item->args, &lefttype, &righttype);
998                                 /* Save the info */
999                                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1000                                 member->number = item->number;
1001                                 member->lefttype = lefttype;
1002                                 member->righttype = righttype;
1003                                 addFamilyMember(&operators, member, false);
1004                                 break;
1005                         case OPCLASS_ITEM_FUNCTION:
1006                                 if (item->number <= 0 || item->number > maxProcNumber)
1007                                         ereport(ERROR,
1008                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1009                                                          errmsg("invalid procedure number %d,"
1010                                                                         " must be between 1 and %d",
1011                                                                         item->number, maxProcNumber)));
1012                                 processTypesSpec(item->args, &lefttype, &righttype);
1013                                 /* Save the info */
1014                                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1015                                 member->number = item->number;
1016                                 member->lefttype = lefttype;
1017                                 member->righttype = righttype;
1018                                 addFamilyMember(&procedures, member, true);
1019                                 break;
1020                         case OPCLASS_ITEM_STORAGETYPE:
1021                                 /* grammar prevents this from appearing */
1022                         default:
1023                                 elog(ERROR, "unrecognized item type: %d", item->itemtype);
1024                                 break;
1025                 }
1026         }
1027
1028         /*
1029          * Remove tuples from pg_amop and pg_amproc.
1030          */
1031         dropOperators(opfamilyname, amoid, opfamilyoid, operators);
1032         dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
1033 }
1034
1035
1036 /*
1037  * Deal with explicit arg types used in ALTER ADD/DROP
1038  */
1039 static void
1040 processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
1041 {
1042         TypeName   *typeName;
1043
1044         Assert(args != NIL);
1045
1046         typeName = (TypeName *) linitial(args);
1047         *lefttype = typenameTypeId(NULL, typeName);
1048
1049         if (list_length(args) > 1)
1050         {
1051                 typeName = (TypeName *) lsecond(args);
1052                 *righttype = typenameTypeId(NULL, typeName);
1053         }
1054         else
1055                 *righttype = *lefttype;
1056
1057         if (list_length(args) > 2)
1058                 ereport(ERROR,
1059                                 (errcode(ERRCODE_SYNTAX_ERROR),
1060                                  errmsg("one or two argument types must be specified")));
1061 }
1062
1063
1064 /*
1065  * Determine the lefttype/righttype to assign to an operator,
1066  * and do any validity checking we can manage.
1067  */
1068 static void
1069 assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
1070 {
1071         Operator        optup;
1072         Form_pg_operator opform;
1073
1074         /* Fetch the operator definition */
1075         optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
1076         if (optup == NULL)
1077                 elog(ERROR, "cache lookup failed for operator %u", member->object);
1078         opform = (Form_pg_operator) GETSTRUCT(optup);
1079
1080         /*
1081          * Opfamily operators must be binary.
1082          */
1083         if (opform->oprkind != 'b')
1084                 ereport(ERROR,
1085                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1086                                  errmsg("index operators must be binary")));
1087
1088         if (OidIsValid(member->sortfamily))
1089         {
1090                 /*
1091                  * Ordering op, check index supports that.      (We could perhaps also
1092                  * check that the operator returns a type supported by the sortfamily,
1093                  * but that seems more trouble than it's worth here.  If it does not,
1094                  * the operator will never be matchable to any ORDER BY clause, but no
1095                  * worse consequences can ensue.  Also, trying to check that would
1096                  * create an ordering hazard during dump/reload: it's possible that
1097                  * the family has been created but not yet populated with the required
1098                  * operators.)
1099                  */
1100                 HeapTuple       amtup;
1101                 Form_pg_am      pg_am;
1102
1103                 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
1104                 if (amtup == NULL)
1105                         elog(ERROR, "cache lookup failed for access method %u", amoid);
1106                 pg_am = (Form_pg_am) GETSTRUCT(amtup);
1107
1108                 if (!pg_am->amcanorderbyop)
1109                         ereport(ERROR,
1110                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1111                         errmsg("access method \"%s\" does not support ordering operators",
1112                                    NameStr(pg_am->amname))));
1113
1114                 ReleaseSysCache(amtup);
1115         }
1116         else
1117         {
1118                 /*
1119                  * Search operators must return boolean.
1120                  */
1121                 if (opform->oprresult != BOOLOID)
1122                         ereport(ERROR,
1123                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1124                                          errmsg("index search operators must return boolean")));
1125         }
1126
1127         /*
1128          * If lefttype/righttype isn't specified, use the operator's input types
1129          */
1130         if (!OidIsValid(member->lefttype))
1131                 member->lefttype = opform->oprleft;
1132         if (!OidIsValid(member->righttype))
1133                 member->righttype = opform->oprright;
1134
1135         ReleaseSysCache(optup);
1136 }
1137
1138 /*
1139  * Determine the lefttype/righttype to assign to a support procedure,
1140  * and do any validity checking we can manage.
1141  */
1142 static void
1143 assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
1144 {
1145         HeapTuple       proctup;
1146         Form_pg_proc procform;
1147
1148         /* Fetch the procedure definition */
1149         proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
1150         if (proctup == NULL)
1151                 elog(ERROR, "cache lookup failed for function %u", member->object);
1152         procform = (Form_pg_proc) GETSTRUCT(proctup);
1153
1154         /*
1155          * btree comparison procs must be 2-arg procs returning int4, while btree
1156          * sortsupport procs must take internal and return void.  hash support
1157          * procs must be 1-arg procs returning int4.  Otherwise we don't know.
1158          */
1159         if (amoid == BTREE_AM_OID)
1160         {
1161                 if (member->number == BTORDER_PROC)
1162                 {
1163                         if (procform->pronargs != 2)
1164                                 ereport(ERROR,
1165                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1166                                                  errmsg("btree comparison procedures must have two arguments")));
1167                         if (procform->prorettype != INT4OID)
1168                                 ereport(ERROR,
1169                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1170                                                  errmsg("btree comparison procedures must return integer")));
1171
1172                         /*
1173                          * If lefttype/righttype isn't specified, use the proc's input
1174                          * types
1175                          */
1176                         if (!OidIsValid(member->lefttype))
1177                                 member->lefttype = procform->proargtypes.values[0];
1178                         if (!OidIsValid(member->righttype))
1179                                 member->righttype = procform->proargtypes.values[1];
1180                 }
1181                 else if (member->number == BTSORTSUPPORT_PROC)
1182                 {
1183                         if (procform->pronargs != 1 ||
1184                                 procform->proargtypes.values[0] != INTERNALOID)
1185                                 ereport(ERROR,
1186                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1187                                                  errmsg("btree sort support procedures must accept type \"internal\"")));
1188                         if (procform->prorettype != VOIDOID)
1189                                 ereport(ERROR,
1190                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1191                                                  errmsg("btree sort support procedures must return void")));
1192
1193                         /*
1194                          * Can't infer lefttype/righttype from proc, so use default rule
1195                          */
1196                 }
1197         }
1198         else if (amoid == HASH_AM_OID)
1199         {
1200                 if (procform->pronargs != 1)
1201                         ereport(ERROR,
1202                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1203                                          errmsg("hash procedures must have one argument")));
1204                 if (procform->prorettype != INT4OID)
1205                         ereport(ERROR,
1206                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1207                                          errmsg("hash procedures must return integer")));
1208
1209                 /*
1210                  * If lefttype/righttype isn't specified, use the proc's input type
1211                  */
1212                 if (!OidIsValid(member->lefttype))
1213                         member->lefttype = procform->proargtypes.values[0];
1214                 if (!OidIsValid(member->righttype))
1215                         member->righttype = procform->proargtypes.values[0];
1216         }
1217
1218         /*
1219          * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
1220          * lefttype and righttype.  In CREATE or ALTER OPERATOR FAMILY, opcintype
1221          * isn't available, so make the user specify the types.
1222          */
1223         if (!OidIsValid(member->lefttype))
1224                 member->lefttype = typeoid;
1225         if (!OidIsValid(member->righttype))
1226                 member->righttype = typeoid;
1227
1228         if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1229                 ereport(ERROR,
1230                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1231                                  errmsg("associated data types must be specified for index support procedure")));
1232
1233         ReleaseSysCache(proctup);
1234 }
1235
1236 /*
1237  * Add a new family member to the appropriate list, after checking for
1238  * duplicated strategy or proc number.
1239  */
1240 static void
1241 addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
1242 {
1243         ListCell   *l;
1244
1245         foreach(l, *list)
1246         {
1247                 OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1248
1249                 if (old->number == member->number &&
1250                         old->lefttype == member->lefttype &&
1251                         old->righttype == member->righttype)
1252                 {
1253                         if (isProc)
1254                                 ereport(ERROR,
1255                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1256                                                  errmsg("procedure number %d for (%s,%s) appears more than once",
1257                                                                 member->number,
1258                                                                 format_type_be(member->lefttype),
1259                                                                 format_type_be(member->righttype))));
1260                         else
1261                                 ereport(ERROR,
1262                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1263                                                  errmsg("operator number %d for (%s,%s) appears more than once",
1264                                                                 member->number,
1265                                                                 format_type_be(member->lefttype),
1266                                                                 format_type_be(member->righttype))));
1267                 }
1268         }
1269         *list = lappend(*list, member);
1270 }
1271
1272 /*
1273  * Dump the operators to pg_amop
1274  *
1275  * We also make dependency entries in pg_depend for the opfamily entries.
1276  * If opclassoid is valid then make an INTERNAL dependency on that opclass,
1277  * else make an AUTO dependency on the opfamily.
1278  */
1279 static void
1280 storeOperators(List *opfamilyname, Oid amoid,
1281                            Oid opfamilyoid, Oid opclassoid,
1282                            List *operators, bool isAdd)
1283 {
1284         Relation        rel;
1285         Datum           values[Natts_pg_amop];
1286         bool            nulls[Natts_pg_amop];
1287         HeapTuple       tup;
1288         Oid                     entryoid;
1289         ObjectAddress myself,
1290                                 referenced;
1291         ListCell   *l;
1292
1293         rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1294
1295         foreach(l, operators)
1296         {
1297                 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1298                 char            oppurpose;
1299
1300                 /*
1301                  * If adding to an existing family, check for conflict with an
1302                  * existing pg_amop entry (just to give a nicer error message)
1303                  */
1304                 if (isAdd &&
1305                         SearchSysCacheExists4(AMOPSTRATEGY,
1306                                                                   ObjectIdGetDatum(opfamilyoid),
1307                                                                   ObjectIdGetDatum(op->lefttype),
1308                                                                   ObjectIdGetDatum(op->righttype),
1309                                                                   Int16GetDatum(op->number)))
1310                         ereport(ERROR,
1311                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
1312                                          errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1313                                                         op->number,
1314                                                         format_type_be(op->lefttype),
1315                                                         format_type_be(op->righttype),
1316                                                         NameListToString(opfamilyname))));
1317
1318                 oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1319
1320                 /* Create the pg_amop entry */
1321                 memset(values, 0, sizeof(values));
1322                 memset(nulls, false, sizeof(nulls));
1323
1324                 values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1325                 values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
1326                 values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
1327                 values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
1328                 values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
1329                 values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
1330                 values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
1331                 values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
1332
1333                 tup = heap_form_tuple(rel->rd_att, values, nulls);
1334
1335                 entryoid = simple_heap_insert(rel, tup);
1336
1337                 CatalogUpdateIndexes(rel, tup);
1338
1339                 heap_freetuple(tup);
1340
1341                 /* Make its dependencies */
1342                 myself.classId = AccessMethodOperatorRelationId;
1343                 myself.objectId = entryoid;
1344                 myself.objectSubId = 0;
1345
1346                 referenced.classId = OperatorRelationId;
1347                 referenced.objectId = op->object;
1348                 referenced.objectSubId = 0;
1349
1350                 if (OidIsValid(opclassoid))
1351                 {
1352                         /* if contained in an opclass, use a NORMAL dep on operator */
1353                         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1354
1355                         /* ... and an INTERNAL dep on the opclass */
1356                         referenced.classId = OperatorClassRelationId;
1357                         referenced.objectId = opclassoid;
1358                         referenced.objectSubId = 0;
1359                         recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1360                 }
1361                 else
1362                 {
1363                         /* if "loose" in the opfamily, use a AUTO dep on operator */
1364                         recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1365
1366                         /* ... and an AUTO dep on the opfamily */
1367                         referenced.classId = OperatorFamilyRelationId;
1368                         referenced.objectId = opfamilyoid;
1369                         referenced.objectSubId = 0;
1370                         recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1371                 }
1372
1373                 /* A search operator also needs a dep on the referenced opfamily */
1374                 if (OidIsValid(op->sortfamily))
1375                 {
1376                         referenced.classId = OperatorFamilyRelationId;
1377                         referenced.objectId = op->sortfamily;
1378                         referenced.objectSubId = 0;
1379                         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1380                 }
1381         }
1382
1383         heap_close(rel, RowExclusiveLock);
1384 }
1385
1386 /*
1387  * Dump the procedures (support routines) to pg_amproc
1388  *
1389  * We also make dependency entries in pg_depend for the opfamily entries.
1390  * If opclassoid is valid then make an INTERNAL dependency on that opclass,
1391  * else make an AUTO dependency on the opfamily.
1392  */
1393 static void
1394 storeProcedures(List *opfamilyname, Oid amoid,
1395                                 Oid opfamilyoid, Oid opclassoid,
1396                                 List *procedures, bool isAdd)
1397 {
1398         Relation        rel;
1399         Datum           values[Natts_pg_amproc];
1400         bool            nulls[Natts_pg_amproc];
1401         HeapTuple       tup;
1402         Oid                     entryoid;
1403         ObjectAddress myself,
1404                                 referenced;
1405         ListCell   *l;
1406
1407         rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1408
1409         foreach(l, procedures)
1410         {
1411                 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1412
1413                 /*
1414                  * If adding to an existing family, check for conflict with an
1415                  * existing pg_amproc entry (just to give a nicer error message)
1416                  */
1417                 if (isAdd &&
1418                         SearchSysCacheExists4(AMPROCNUM,
1419                                                                   ObjectIdGetDatum(opfamilyoid),
1420                                                                   ObjectIdGetDatum(proc->lefttype),
1421                                                                   ObjectIdGetDatum(proc->righttype),
1422                                                                   Int16GetDatum(proc->number)))
1423                         ereport(ERROR,
1424                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
1425                                          errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1426                                                         proc->number,
1427                                                         format_type_be(proc->lefttype),
1428                                                         format_type_be(proc->righttype),
1429                                                         NameListToString(opfamilyname))));
1430
1431                 /* Create the pg_amproc entry */
1432                 memset(values, 0, sizeof(values));
1433                 memset(nulls, false, sizeof(nulls));
1434
1435                 values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1436                 values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1437                 values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1438                 values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1439                 values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1440
1441                 tup = heap_form_tuple(rel->rd_att, values, nulls);
1442
1443                 entryoid = simple_heap_insert(rel, tup);
1444
1445                 CatalogUpdateIndexes(rel, tup);
1446
1447                 heap_freetuple(tup);
1448
1449                 /* Make its dependencies */
1450                 myself.classId = AccessMethodProcedureRelationId;
1451                 myself.objectId = entryoid;
1452                 myself.objectSubId = 0;
1453
1454                 referenced.classId = ProcedureRelationId;
1455                 referenced.objectId = proc->object;
1456                 referenced.objectSubId = 0;
1457
1458                 if (OidIsValid(opclassoid))
1459                 {
1460                         /* if contained in an opclass, use a NORMAL dep on procedure */
1461                         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1462
1463                         /* ... and an INTERNAL dep on the opclass */
1464                         referenced.classId = OperatorClassRelationId;
1465                         referenced.objectId = opclassoid;
1466                         referenced.objectSubId = 0;
1467                         recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1468                 }
1469                 else
1470                 {
1471                         /* if "loose" in the opfamily, use a AUTO dep on procedure */
1472                         recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1473
1474                         /* ... and an AUTO dep on the opfamily */
1475                         referenced.classId = OperatorFamilyRelationId;
1476                         referenced.objectId = opfamilyoid;
1477                         referenced.objectSubId = 0;
1478                         recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1479                 }
1480         }
1481
1482         heap_close(rel, RowExclusiveLock);
1483 }
1484
1485
1486 /*
1487  * Remove operator entries from an opfamily.
1488  *
1489  * Note: this is only allowed for "loose" members of an opfamily, hence
1490  * behavior is always RESTRICT.
1491  */
1492 static void
1493 dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1494                           List *operators)
1495 {
1496         ListCell   *l;
1497
1498         foreach(l, operators)
1499         {
1500                 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1501                 Oid                     amopid;
1502                 ObjectAddress object;
1503
1504                 amopid = GetSysCacheOid4(AMOPSTRATEGY,
1505                                                                  ObjectIdGetDatum(opfamilyoid),
1506                                                                  ObjectIdGetDatum(op->lefttype),
1507                                                                  ObjectIdGetDatum(op->righttype),
1508                                                                  Int16GetDatum(op->number));
1509                 if (!OidIsValid(amopid))
1510                         ereport(ERROR,
1511                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
1512                                          errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1513                                                         op->number,
1514                                                         format_type_be(op->lefttype),
1515                                                         format_type_be(op->righttype),
1516                                                         NameListToString(opfamilyname))));
1517
1518                 object.classId = AccessMethodOperatorRelationId;
1519                 object.objectId = amopid;
1520                 object.objectSubId = 0;
1521
1522                 performDeletion(&object, DROP_RESTRICT);
1523         }
1524 }
1525
1526 /*
1527  * Remove procedure entries from an opfamily.
1528  *
1529  * Note: this is only allowed for "loose" members of an opfamily, hence
1530  * behavior is always RESTRICT.
1531  */
1532 static void
1533 dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1534                            List *procedures)
1535 {
1536         ListCell   *l;
1537
1538         foreach(l, procedures)
1539         {
1540                 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1541                 Oid                     amprocid;
1542                 ObjectAddress object;
1543
1544                 amprocid = GetSysCacheOid4(AMPROCNUM,
1545                                                                    ObjectIdGetDatum(opfamilyoid),
1546                                                                    ObjectIdGetDatum(op->lefttype),
1547                                                                    ObjectIdGetDatum(op->righttype),
1548                                                                    Int16GetDatum(op->number));
1549                 if (!OidIsValid(amprocid))
1550                         ereport(ERROR,
1551                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
1552                                          errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1553                                                         op->number,
1554                                                         format_type_be(op->lefttype),
1555                                                         format_type_be(op->righttype),
1556                                                         NameListToString(opfamilyname))));
1557
1558                 object.classId = AccessMethodProcedureRelationId;
1559                 object.objectId = amprocid;
1560                 object.objectSubId = 0;
1561
1562                 performDeletion(&object, DROP_RESTRICT);
1563         }
1564 }
1565
1566 /*
1567  * Deletion subroutines for use by dependency.c.
1568  */
1569 void
1570 RemoveOpFamilyById(Oid opfamilyOid)
1571 {
1572         Relation        rel;
1573         HeapTuple       tup;
1574
1575         rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
1576
1577         tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
1578         if (!HeapTupleIsValid(tup)) /* should not happen */
1579                 elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1580
1581         simple_heap_delete(rel, &tup->t_self);
1582
1583         ReleaseSysCache(tup);
1584
1585         heap_close(rel, RowExclusiveLock);
1586 }
1587
1588 void
1589 RemoveOpClassById(Oid opclassOid)
1590 {
1591         Relation        rel;
1592         HeapTuple       tup;
1593
1594         rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1595
1596         tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
1597         if (!HeapTupleIsValid(tup)) /* should not happen */
1598                 elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1599
1600         simple_heap_delete(rel, &tup->t_self);
1601
1602         ReleaseSysCache(tup);
1603
1604         heap_close(rel, RowExclusiveLock);
1605 }
1606
1607 void
1608 RemoveAmOpEntryById(Oid entryOid)
1609 {
1610         Relation        rel;
1611         HeapTuple       tup;
1612         ScanKeyData skey[1];
1613         SysScanDesc scan;
1614
1615         ScanKeyInit(&skey[0],
1616                                 ObjectIdAttributeNumber,
1617                                 BTEqualStrategyNumber, F_OIDEQ,
1618                                 ObjectIdGetDatum(entryOid));
1619
1620         rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1621
1622         scan = systable_beginscan(rel, AccessMethodOperatorOidIndexId, true,
1623                                                           SnapshotNow, 1, skey);
1624
1625         /* we expect exactly one match */
1626         tup = systable_getnext(scan);
1627         if (!HeapTupleIsValid(tup))
1628                 elog(ERROR, "could not find tuple for amop entry %u", entryOid);
1629
1630         simple_heap_delete(rel, &tup->t_self);
1631
1632         systable_endscan(scan);
1633         heap_close(rel, RowExclusiveLock);
1634 }
1635
1636 void
1637 RemoveAmProcEntryById(Oid entryOid)
1638 {
1639         Relation        rel;
1640         HeapTuple       tup;
1641         ScanKeyData skey[1];
1642         SysScanDesc scan;
1643
1644         ScanKeyInit(&skey[0],
1645                                 ObjectIdAttributeNumber,
1646                                 BTEqualStrategyNumber, F_OIDEQ,
1647                                 ObjectIdGetDatum(entryOid));
1648
1649         rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1650
1651         scan = systable_beginscan(rel, AccessMethodProcedureOidIndexId, true,
1652                                                           SnapshotNow, 1, skey);
1653
1654         /* we expect exactly one match */
1655         tup = systable_getnext(scan);
1656         if (!HeapTupleIsValid(tup))
1657                 elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
1658
1659         simple_heap_delete(rel, &tup->t_self);
1660
1661         systable_endscan(scan);
1662         heap_close(rel, RowExclusiveLock);
1663 }
1664
1665
1666 /*
1667  * Rename opclass
1668  */
1669 void
1670 RenameOpClass(List *name, const char *access_method, const char *newname)
1671 {
1672         Oid                     opcOid;
1673         Oid                     amOid;
1674         Oid                     namespaceOid;
1675         HeapTuple       origtup;
1676         HeapTuple       tup;
1677         Relation        rel;
1678         AclResult       aclresult;
1679
1680         amOid = get_am_oid(access_method, false);
1681
1682         rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1683
1684         /* Look up the opclass. */
1685         origtup = OpClassCacheLookup(amOid, name, false);
1686         tup = heap_copytuple(origtup);
1687         ReleaseSysCache(origtup);
1688         opcOid = HeapTupleGetOid(tup);
1689         namespaceOid = ((Form_pg_opclass) GETSTRUCT(tup))->opcnamespace;
1690
1691         /* make sure the new name doesn't exist */
1692         if (SearchSysCacheExists3(CLAAMNAMENSP,
1693                                                           ObjectIdGetDatum(amOid),
1694                                                           CStringGetDatum(newname),
1695                                                           ObjectIdGetDatum(namespaceOid)))
1696         {
1697                 ereport(ERROR,
1698                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
1699                                  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1700                                                 newname, access_method,
1701                                                 get_namespace_name(namespaceOid))));
1702         }
1703
1704         /* must be owner */
1705         if (!pg_opclass_ownercheck(opcOid, GetUserId()))
1706                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
1707                                            NameListToString(name));
1708
1709         /* must have CREATE privilege on namespace */
1710         aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
1711         if (aclresult != ACLCHECK_OK)
1712                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1713                                            get_namespace_name(namespaceOid));
1714
1715         /* rename */
1716         namestrcpy(&(((Form_pg_opclass) GETSTRUCT(tup))->opcname), newname);
1717         simple_heap_update(rel, &tup->t_self, tup);
1718         CatalogUpdateIndexes(rel, tup);
1719
1720         heap_close(rel, NoLock);
1721         heap_freetuple(tup);
1722 }
1723
1724 /*
1725  * Rename opfamily
1726  */
1727 void
1728 RenameOpFamily(List *name, const char *access_method, const char *newname)
1729 {
1730         Oid                     opfOid;
1731         Oid                     amOid;
1732         Oid                     namespaceOid;
1733         char       *schemaname;
1734         char       *opfname;
1735         HeapTuple       tup;
1736         Relation        rel;
1737         AclResult       aclresult;
1738
1739         amOid = get_am_oid(access_method, false);
1740
1741         rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
1742
1743         /*
1744          * Look up the opfamily
1745          */
1746         DeconstructQualifiedName(name, &schemaname, &opfname);
1747
1748         if (schemaname)
1749         {
1750                 namespaceOid = LookupExplicitNamespace(schemaname);
1751
1752                 tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
1753                                                                   ObjectIdGetDatum(amOid),
1754                                                                   PointerGetDatum(opfname),
1755                                                                   ObjectIdGetDatum(namespaceOid));
1756                 if (!HeapTupleIsValid(tup))
1757                         ereport(ERROR,
1758                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
1759                                          errmsg("operator family \"%s\" does not exist for access method \"%s\"",
1760                                                         opfname, access_method)));
1761
1762                 opfOid = HeapTupleGetOid(tup);
1763         }
1764         else
1765         {
1766                 opfOid = OpfamilynameGetOpfid(amOid, opfname);
1767                 if (!OidIsValid(opfOid))
1768                         ereport(ERROR,
1769                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
1770                                          errmsg("operator family \"%s\" does not exist for access method \"%s\"",
1771                                                         opfname, access_method)));
1772
1773                 tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
1774                 if (!HeapTupleIsValid(tup))             /* should not happen */
1775                         elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
1776
1777                 namespaceOid = ((Form_pg_opfamily) GETSTRUCT(tup))->opfnamespace;
1778         }
1779
1780         /* make sure the new name doesn't exist */
1781         if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
1782                                                           ObjectIdGetDatum(amOid),
1783                                                           CStringGetDatum(newname),
1784                                                           ObjectIdGetDatum(namespaceOid)))
1785         {
1786                 ereport(ERROR,
1787                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
1788                                  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1789                                                 newname, access_method,
1790                                                 get_namespace_name(namespaceOid))));
1791         }
1792
1793         /* must be owner */
1794         if (!pg_opfamily_ownercheck(opfOid, GetUserId()))
1795                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
1796                                            NameListToString(name));
1797
1798         /* must have CREATE privilege on namespace */
1799         aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
1800         if (aclresult != ACLCHECK_OK)
1801                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1802                                            get_namespace_name(namespaceOid));
1803
1804         /* rename */
1805         namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname);
1806         simple_heap_update(rel, &tup->t_self, tup);
1807         CatalogUpdateIndexes(rel, tup);
1808
1809         heap_close(rel, NoLock);
1810         heap_freetuple(tup);
1811 }
1812
1813 /*
1814  * Change opclass owner by name
1815  */
1816 void
1817 AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
1818 {
1819         Oid                     amOid;
1820         Relation        rel;
1821         HeapTuple       tup;
1822         HeapTuple       origtup;
1823
1824         amOid = get_am_oid(access_method, false);
1825
1826         rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1827
1828         /* Look up the opclass. */
1829         origtup = OpClassCacheLookup(amOid, name, false);
1830         tup = heap_copytuple(origtup);
1831         ReleaseSysCache(origtup);
1832
1833         AlterOpClassOwner_internal(rel, tup, newOwnerId);
1834
1835         heap_freetuple(tup);
1836         heap_close(rel, NoLock);
1837 }
1838
1839 /*
1840  * Change operator class owner, specified by OID
1841  */
1842 void
1843 AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId)
1844 {
1845         HeapTuple       tup;
1846         Relation        rel;
1847
1848         rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1849
1850         tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
1851         if (!HeapTupleIsValid(tup))
1852                 elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1853
1854         AlterOpClassOwner_internal(rel, tup, newOwnerId);
1855
1856         heap_freetuple(tup);
1857         heap_close(rel, NoLock);
1858 }
1859
1860 /*
1861  * The first parameter is pg_opclass, opened and suitably locked.  The second
1862  * parameter is a copy of the tuple from pg_opclass we want to modify.
1863  */
1864 static void
1865 AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
1866 {
1867         Oid                     namespaceOid;
1868         AclResult       aclresult;
1869         Form_pg_opclass opcForm;
1870
1871         Assert(tup->t_tableOid == OperatorClassRelationId);
1872         Assert(RelationGetRelid(rel) == OperatorClassRelationId);
1873
1874         opcForm = (Form_pg_opclass) GETSTRUCT(tup);
1875
1876         namespaceOid = opcForm->opcnamespace;
1877
1878         /*
1879          * If the new owner is the same as the existing owner, consider the
1880          * command to have succeeded.  This is for dump restoration purposes.
1881          */
1882         if (opcForm->opcowner != newOwnerId)
1883         {
1884                 /* Superusers can always do it */
1885                 if (!superuser())
1886                 {
1887                         /* Otherwise, must be owner of the existing object */
1888                         if (!pg_opclass_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1889                                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
1890                                                            NameStr(opcForm->opcname));
1891
1892                         /* Must be able to become new owner */
1893                         check_is_member_of_role(GetUserId(), newOwnerId);
1894
1895                         /* New owner must have CREATE privilege on namespace */
1896                         aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
1897                                                                                           ACL_CREATE);
1898                         if (aclresult != ACLCHECK_OK)
1899                                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1900                                                            get_namespace_name(namespaceOid));
1901                 }
1902
1903                 /*
1904                  * Modify the owner --- okay to scribble on tup because it's a copy
1905                  */
1906                 opcForm->opcowner = newOwnerId;
1907
1908                 simple_heap_update(rel, &tup->t_self, tup);
1909
1910                 CatalogUpdateIndexes(rel, tup);
1911
1912                 /* Update owner dependency reference */
1913                 changeDependencyOnOwner(OperatorClassRelationId, HeapTupleGetOid(tup),
1914                                                                 newOwnerId);
1915         }
1916 }
1917
1918 /*
1919  * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
1920  */
1921 void
1922 AlterOpClassNamespace(List *name, char *access_method, const char *newschema)
1923 {
1924         Oid                     amOid;
1925         Relation        rel;
1926         Oid                     opclassOid;
1927         Oid                     nspOid;
1928
1929         amOid = get_am_oid(access_method, false);
1930
1931         rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1932
1933         /* Look up the opclass */
1934         opclassOid = get_opclass_oid(amOid, name, false);
1935
1936         /* get schema OID */
1937         nspOid = LookupCreationNamespace(newschema);
1938
1939         AlterObjectNamespace(rel, CLAOID, -1,
1940                                                  opclassOid, nspOid,
1941                                                  Anum_pg_opclass_opcname,
1942                                                  Anum_pg_opclass_opcnamespace,
1943                                                  Anum_pg_opclass_opcowner,
1944                                                  ACL_KIND_OPCLASS);
1945
1946         heap_close(rel, RowExclusiveLock);
1947 }
1948
1949 Oid
1950 AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
1951 {
1952         Oid                     oldNspOid;
1953         Relation        rel;
1954
1955         rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1956
1957         oldNspOid =
1958                 AlterObjectNamespace(rel, CLAOID, -1,
1959                                                          opclassOid, newNspOid,
1960                                                          Anum_pg_opclass_opcname,
1961                                                          Anum_pg_opclass_opcnamespace,
1962                                                          Anum_pg_opclass_opcowner,
1963                                                          ACL_KIND_OPCLASS);
1964
1965         heap_close(rel, RowExclusiveLock);
1966
1967         return oldNspOid;
1968 }
1969
1970 /*
1971  * Change opfamily owner by name
1972  */
1973 void
1974 AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId)
1975 {
1976         Oid                     amOid;
1977         Relation        rel;
1978         HeapTuple       tup;
1979         char       *opfname;
1980         char       *schemaname;
1981
1982         amOid = get_am_oid(access_method, false);
1983
1984         rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
1985
1986         /*
1987          * Look up the opfamily
1988          */
1989         DeconstructQualifiedName(name, &schemaname, &opfname);
1990
1991         if (schemaname)
1992         {
1993                 Oid                     namespaceOid;
1994
1995                 namespaceOid = LookupExplicitNamespace(schemaname);
1996
1997                 tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
1998                                                                   ObjectIdGetDatum(amOid),
1999                                                                   PointerGetDatum(opfname),
2000                                                                   ObjectIdGetDatum(namespaceOid));
2001                 if (!HeapTupleIsValid(tup))
2002                         ereport(ERROR,
2003                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
2004                                          errmsg("operator family \"%s\" does not exist for access method \"%s\"",
2005                                                         opfname, access_method)));
2006         }
2007         else
2008         {
2009                 Oid                     opfOid;
2010
2011                 opfOid = OpfamilynameGetOpfid(amOid, opfname);
2012                 if (!OidIsValid(opfOid))
2013                         ereport(ERROR,
2014                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
2015                                          errmsg("operator family \"%s\" does not exist for access method \"%s\"",
2016                                                         opfname, access_method)));
2017
2018                 tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
2019                 if (!HeapTupleIsValid(tup))             /* should not happen */
2020                         elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
2021         }
2022
2023         AlterOpFamilyOwner_internal(rel, tup, newOwnerId);
2024
2025         heap_freetuple(tup);
2026         heap_close(rel, NoLock);
2027 }
2028
2029 /*
2030  * Change operator family owner, specified by OID
2031  */
2032 void
2033 AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId)
2034 {
2035         HeapTuple       tup;
2036         Relation        rel;
2037
2038         rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
2039
2040         tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
2041         if (!HeapTupleIsValid(tup))
2042                 elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
2043
2044         AlterOpFamilyOwner_internal(rel, tup, newOwnerId);
2045
2046         heap_freetuple(tup);
2047         heap_close(rel, NoLock);
2048 }
2049
2050 /*
2051  * The first parameter is pg_opfamily, opened and suitably locked.      The second
2052  * parameter is a copy of the tuple from pg_opfamily we want to modify.
2053  */
2054 static void
2055 AlterOpFamilyOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
2056 {
2057         Oid                     namespaceOid;
2058         AclResult       aclresult;
2059         Form_pg_opfamily opfForm;
2060
2061         Assert(tup->t_tableOid == OperatorFamilyRelationId);
2062         Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
2063
2064         opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
2065
2066         namespaceOid = opfForm->opfnamespace;
2067
2068         /*
2069          * If the new owner is the same as the existing owner, consider the
2070          * command to have succeeded.  This is for dump restoration purposes.
2071          */
2072         if (opfForm->opfowner != newOwnerId)
2073         {
2074                 /* Superusers can always do it */
2075                 if (!superuser())
2076                 {
2077                         /* Otherwise, must be owner of the existing object */
2078                         if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2079                                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
2080                                                            NameStr(opfForm->opfname));
2081
2082                         /* Must be able to become new owner */
2083                         check_is_member_of_role(GetUserId(), newOwnerId);
2084
2085                         /* New owner must have CREATE privilege on namespace */
2086                         aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
2087                                                                                           ACL_CREATE);
2088                         if (aclresult != ACLCHECK_OK)
2089                                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2090                                                            get_namespace_name(namespaceOid));
2091                 }
2092
2093                 /*
2094                  * Modify the owner --- okay to scribble on tup because it's a copy
2095                  */
2096                 opfForm->opfowner = newOwnerId;
2097
2098                 simple_heap_update(rel, &tup->t_self, tup);
2099
2100                 CatalogUpdateIndexes(rel, tup);
2101
2102                 /* Update owner dependency reference */
2103                 changeDependencyOnOwner(OperatorFamilyRelationId, HeapTupleGetOid(tup),
2104                                                                 newOwnerId);
2105         }
2106 }
2107
2108 /*
2109  * get_am_oid - given an access method name, look up the OID
2110  *
2111  * If missing_ok is false, throw an error if access method not found.  If
2112  * true, just return InvalidOid.
2113  */
2114 Oid
2115 get_am_oid(const char *amname, bool missing_ok)
2116 {
2117         Oid                     oid;
2118
2119         oid = GetSysCacheOid1(AMNAME, CStringGetDatum(amname));
2120         if (!OidIsValid(oid) && !missing_ok)
2121                 ereport(ERROR,
2122                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2123                                  errmsg("access method \"%s\" does not exist", amname)));
2124         return oid;
2125 }
2126
2127 /*
2128  * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
2129  */
2130 void
2131 AlterOpFamilyNamespace(List *name, char *access_method, const char *newschema)
2132 {
2133         Oid                     amOid;
2134         Relation        rel;
2135         Oid                     opfamilyOid;
2136         Oid                     nspOid;
2137
2138         amOid = get_am_oid(access_method, false);
2139
2140         rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
2141
2142         /* Look up the opfamily */
2143         opfamilyOid = get_opfamily_oid(amOid, name, false);
2144
2145         /* get schema OID */
2146         nspOid = LookupCreationNamespace(newschema);
2147
2148         AlterObjectNamespace(rel, OPFAMILYOID, -1,
2149                                                  opfamilyOid, nspOid,
2150                                                  Anum_pg_opfamily_opfname,
2151                                                  Anum_pg_opfamily_opfnamespace,
2152                                                  Anum_pg_opfamily_opfowner,
2153                                                  ACL_KIND_OPFAMILY);
2154
2155         heap_close(rel, RowExclusiveLock);
2156 }
2157
2158 Oid
2159 AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
2160 {
2161         Oid                     oldNspOid;
2162         Relation        rel;
2163
2164         rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
2165
2166         oldNspOid =
2167                 AlterObjectNamespace(rel, OPFAMILYOID, -1,
2168                                                          opfamilyOid, newNspOid,
2169                                                          Anum_pg_opfamily_opfname,
2170                                                          Anum_pg_opfamily_opfnamespace,
2171                                                          Anum_pg_opfamily_opfowner,
2172                                                          ACL_KIND_OPFAMILY);
2173
2174         heap_close(rel, RowExclusiveLock);
2175
2176         return oldNspOid;
2177 }