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