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