1 /*-------------------------------------------------------------------------
5 * Routines for opclass (and opfamily) manipulation commands
7 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/commands/opclasscmds.c
14 *-------------------------------------------------------------------------
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"
52 static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt,
53 Oid amoid, Oid opfamilyoid,
54 int maxOpNumber, int maxProcNumber,
56 static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt,
57 Oid amoid, Oid opfamilyoid,
58 int maxOpNumber, int maxProcNumber,
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,
72 static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
77 * Look up an existing opfamily by name.
79 * Returns a syscache tuple reference, or NULL if not found.
82 OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
88 /* deconstruct the name list */
89 DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
93 /* Look in specific schema only */
96 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
97 if (!OidIsValid(namespaceId))
100 htup = SearchSysCache3(OPFAMILYAMNAMENSP,
101 ObjectIdGetDatum(amID),
102 PointerGetDatum(opfname),
103 ObjectIdGetDatum(namespaceId));
107 /* Unqualified opfamily name, so search the search path */
108 Oid opfID = OpfamilynameGetOpfid(amID, opfname);
110 if (!OidIsValid(opfID))
113 htup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfID));
116 if (!HeapTupleIsValid(htup) && !missing_ok)
120 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
121 if (!HeapTupleIsValid(amtup))
122 elog(ERROR, "cache lookup failed for access method %u", amID);
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))));
135 * find an opfamily OID by possibly qualified name
137 * If not found, returns InvalidOid if missing_ok, else throws error.
140 get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
145 htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
146 if (!HeapTupleIsValid(htup))
148 opfID = HeapTupleGetOid(htup);
149 ReleaseSysCache(htup);
156 * Look up an existing opclass by name.
158 * Returns a syscache tuple reference, or NULL if not found.
161 OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
167 /* deconstruct the name list */
168 DeconstructQualifiedName(opclassname, &schemaname, &opcname);
172 /* Look in specific schema only */
175 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
176 if (!OidIsValid(namespaceId))
179 htup = SearchSysCache3(CLAAMNAMENSP,
180 ObjectIdGetDatum(amID),
181 PointerGetDatum(opcname),
182 ObjectIdGetDatum(namespaceId));
186 /* Unqualified opclass name, so search the search path */
187 Oid opcID = OpclassnameGetOpcid(amID, opcname);
189 if (!OidIsValid(opcID))
192 htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
195 if (!HeapTupleIsValid(htup) && !missing_ok)
199 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
200 if (!HeapTupleIsValid(amtup))
201 elog(ERROR, "cache lookup failed for access method %u", amID);
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))));
214 * find an opclass OID by possibly qualified name
216 * If not found, returns InvalidOid if missing_ok, else throws error.
219 get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
224 htup = OpClassCacheLookup(amID, opclassname, missing_ok);
225 if (!HeapTupleIsValid(htup))
227 opcID = HeapTupleGetOid(htup);
228 ReleaseSysCache(htup);
235 * Internal routine to make the catalog entry for a new operator family.
237 * Caller must have done permissions checks etc. already.
240 CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
245 Datum values[Natts_pg_opfamily];
246 bool nulls[Natts_pg_opfamily];
248 ObjectAddress myself,
251 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
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").
257 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
258 ObjectIdGetDatum(amoid),
259 CStringGetDatum(opfname),
260 ObjectIdGetDatum(namespaceoid)))
262 (errcode(ERRCODE_DUPLICATE_OBJECT),
263 errmsg("operator family \"%s\" for access method \"%s\" already exists",
267 * Okay, let's create the pg_opfamily entry.
269 memset(values, 0, sizeof(values));
270 memset(nulls, false, sizeof(nulls));
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());
278 tup = heap_form_tuple(rel->rd_att, values, nulls);
280 opfamilyoid = simple_heap_insert(rel, tup);
282 CatalogUpdateIndexes(rel, tup);
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
291 myself.classId = OperatorFamilyRelationId;
292 myself.objectId = opfamilyoid;
293 myself.objectSubId = 0;
295 /* dependency on namespace */
296 referenced.classId = NamespaceRelationId;
297 referenced.objectId = namespaceoid;
298 referenced.objectSubId = 0;
299 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
301 /* dependency on owner */
302 recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
304 /* dependency on extension */
305 recordDependencyOnCurrentExtension(&myself, false);
307 /* Post creation hook for new operator family */
308 InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
310 heap_close(rel, RowExclusiveLock);
317 * Define a new index operator class.
320 DefineOpClass(CreateOpClassStmt *stmt)
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 */
338 Datum values[Natts_pg_opclass];
339 bool nulls[Natts_pg_opclass];
342 ObjectAddress myself,
345 /* Convert list of names to a name and namespace */
346 namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
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));
355 /* Get necessary info about access method */
356 tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
357 if (!HeapTupleIsValid(tup))
359 (errcode(ERRCODE_UNDEFINED_OBJECT),
360 errmsg("access method \"%s\" does not exist",
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;
372 /* XXX Should we make any privilege check against the AM? */
374 ReleaseSysCache(tup);
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.
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 :-(
394 * XXX re-enable NOT_USED code sections below if you remove this test.
398 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
399 errmsg("must be superuser to create an operator class")));
401 /* Look up the datatype */
402 typeoid = typenameTypeId(NULL, stmt->datatype);
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);
412 * Look up the containing operator family, or create one if FAMILY option
413 * was omitted and there's not a match already.
415 if (stmt->opfamilyname)
417 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
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))
428 opfamilyoid = HeapTupleGetOid(tup);
431 * XXX given the superuser check above, there's no need for an
432 * ownership check here
434 ReleaseSysCache(tup);
438 ObjectAddress tmpAddr;
441 * Create it ... again no need for more permissions ...
443 tmpAddr = CreateOpFamily(stmt->amname, opcname,
444 namespaceoid, amoid);
445 opfamilyoid = tmpAddr.objectId;
452 /* Storage datatype is optional */
453 storageoid = InvalidOid;
456 * Scan the "items" list to obtain additional info.
458 foreach(l, stmt->items)
460 CreateOpClassItem *item = lfirst(l);
464 OpFamilyMember *member;
466 Assert(IsA(item, CreateOpClassItem));
467 switch (item->itemtype)
469 case OPCLASS_ITEM_OPERATOR:
470 if (item->number <= 0 || item->number > maxOpNumber)
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)
478 TypeName *typeName1 = (TypeName *) linitial(item->args);
479 TypeName *typeName2 = (TypeName *) lsecond(item->args);
481 operOid = LookupOperNameTypeNames(NULL, item->name,
482 typeName1, typeName2,
487 /* Default to binary op on input datatype */
488 operOid = LookupOperName(NULL, item->name,
493 if (item->order_family)
494 sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
498 sortfamilyOid = InvalidOid;
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));
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);
520 case OPCLASS_ITEM_FUNCTION:
521 if (item->number <= 0 || item->number > maxProcNumber)
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,
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));
538 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
539 member->object = funcOid;
540 member->number = item->number;
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);
547 assignProcTypes(member, amoid, typeoid);
548 addFamilyMember(&procedures, member, true);
550 case OPCLASS_ITEM_STORAGETYPE:
551 if (OidIsValid(storageoid))
553 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
554 errmsg("storage type specified more than once")));
555 storageoid = typenameTypeId(NULL, item->storedtype);
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);
565 elog(ERROR, "unrecognized item type: %d", item->itemtype);
571 * If storagetype is specified, make sure it's legal.
573 if (OidIsValid(storageoid))
575 /* Just drop the spec if same as column datatype */
576 if (storageoid == typeoid)
577 storageoid = InvalidOid;
580 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
581 errmsg("storage type cannot be different from data type for access method \"%s\"",
585 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
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").
591 if (SearchSysCacheExists3(CLAAMNAMENSP,
592 ObjectIdGetDatum(amoid),
593 CStringGetDatum(opcname),
594 ObjectIdGetDatum(namespaceoid)))
596 (errcode(ERRCODE_DUPLICATE_OBJECT),
597 errmsg("operator class \"%s\" for access method \"%s\" already exists",
598 opcname, stmt->amname)));
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.)
610 ScanKeyInit(&skey[0],
611 Anum_pg_opclass_opcmethod,
612 BTEqualStrategyNumber, F_OIDEQ,
613 ObjectIdGetDatum(amoid));
615 scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
618 while (HeapTupleIsValid(tup = systable_getnext(scan)))
620 Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
622 if (opclass->opcintype == typeoid && opclass->opcdefault)
624 (errcode(ERRCODE_DUPLICATE_OBJECT),
625 errmsg("could not make operator class \"%s\" be default for type %s",
627 TypeNameToString(stmt->datatype)),
628 errdetail("Operator class \"%s\" already is the default.",
629 NameStr(opclass->opcname))));
632 systable_endscan(scan);
636 * Okay, let's create the pg_opclass entry.
638 memset(values, 0, sizeof(values));
639 memset(nulls, false, sizeof(nulls));
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);
651 tup = heap_form_tuple(rel->rd_att, values, nulls);
653 opclassoid = simple_heap_insert(rel, tup);
655 CatalogUpdateIndexes(rel, tup);
660 * Now add tuples to pg_amop and pg_amproc tying in the operators and
661 * functions. Dependencies on them are inserted, too.
663 storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
664 opclassoid, operators, false);
665 storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
666 opclassoid, procedures, false);
668 /* let event triggers know what happened */
669 EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
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
676 myself.classId = OperatorClassRelationId;
677 myself.objectId = opclassoid;
678 myself.objectSubId = 0;
680 /* dependency on namespace */
681 referenced.classId = NamespaceRelationId;
682 referenced.objectId = namespaceoid;
683 referenced.objectSubId = 0;
684 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
686 /* dependency on opfamily */
687 referenced.classId = OperatorFamilyRelationId;
688 referenced.objectId = opfamilyoid;
689 referenced.objectSubId = 0;
690 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
692 /* dependency on indexed datatype */
693 referenced.classId = TypeRelationId;
694 referenced.objectId = typeoid;
695 referenced.objectSubId = 0;
696 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
698 /* dependency on storage datatype */
699 if (OidIsValid(storageoid))
701 referenced.classId = TypeRelationId;
702 referenced.objectId = storageoid;
703 referenced.objectSubId = 0;
704 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
707 /* dependency on owner */
708 recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
710 /* dependency on extension */
711 recordDependencyOnCurrentExtension(&myself, false);
713 /* Post creation hook for new operator class */
714 InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
716 heap_close(rel, RowExclusiveLock);
724 * Define a new index operator family.
727 DefineOpFamily(CreateOpFamilyStmt *stmt)
729 char *opfname; /* name of opfamily we're creating */
730 Oid amoid, /* our AM's oid */
731 namespaceoid; /* namespace to create opfamily in */
734 /* Convert list of names to a name and namespace */
735 namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
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));
744 /* Get access method OID, throwing an error if it doesn't exist. */
745 amoid = get_am_oid(stmt->amname, false);
747 /* XXX Should we make any privilege check against the AM? */
750 * Currently, we require superuser privileges to create an opfamily. See
751 * comments in DefineOpClass.
755 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
756 errmsg("must be superuser to create an operator family")));
758 /* Insert pg_opfamily catalog entry */
759 return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
765 * Add or remove operators/procedures within an existing operator family.
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.
772 AlterOpFamily(AlterOpFamilyStmt *stmt)
774 Oid amoid, /* our AM's oid */
775 opfamilyoid; /* oid of opfamily */
776 int maxOpNumber, /* amstrategies value */
777 maxProcNumber; /* amsupport value */
781 /* Get necessary info about access method */
782 tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
783 if (!HeapTupleIsValid(tup))
785 (errcode(ERRCODE_UNDEFINED_OBJECT),
786 errmsg("access method \"%s\" does not exist",
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;
797 /* XXX Should we make any privilege check against the AM? */
799 ReleaseSysCache(tup);
801 /* Look up the opfamily */
802 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
805 * Currently, we require superuser privileges to alter an opfamily.
807 * XXX re-enable NOT_USED code sections below if you remove this test.
811 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
812 errmsg("must be superuser to alter an operator family")));
815 * ADD and DROP cases need separate code from here on down.
818 AlterOpFamilyDrop(stmt, amoid, opfamilyoid,
819 maxOpNumber, maxProcNumber, stmt->items);
821 AlterOpFamilyAdd(stmt, amoid, opfamilyoid,
822 maxOpNumber, maxProcNumber, stmt->items);
828 * ADD part of ALTER OP FAMILY
831 AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
832 int maxOpNumber, int maxProcNumber, List *items)
834 List *operators; /* OpFamilyMember list for operators */
835 List *procedures; /* OpFamilyMember list for support procs */
842 * Scan the "items" list to obtain additional info.
846 CreateOpClassItem *item = lfirst(l);
850 OpFamilyMember *member;
852 Assert(IsA(item, CreateOpClassItem));
853 switch (item->itemtype)
855 case OPCLASS_ITEM_OPERATOR:
856 if (item->number <= 0 || item->number > maxOpNumber)
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)
864 TypeName *typeName1 = (TypeName *) linitial(item->args);
865 TypeName *typeName2 = (TypeName *) lsecond(item->args);
867 operOid = LookupOperNameTypeNames(NULL, item->name,
868 typeName1, typeName2,
874 (errcode(ERRCODE_SYNTAX_ERROR),
875 errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
876 operOid = InvalidOid; /* keep compiler quiet */
879 if (item->order_family)
880 sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
884 sortfamilyOid = InvalidOid;
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));
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);
906 case OPCLASS_ITEM_FUNCTION:
907 if (item->number <= 0 || item->number > maxProcNumber)
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,
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));
924 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
925 member->object = funcOid;
926 member->number = item->number;
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);
933 assignProcTypes(member, amoid, InvalidOid);
934 addFamilyMember(&procedures, member, true);
936 case OPCLASS_ITEM_STORAGETYPE:
938 (errcode(ERRCODE_SYNTAX_ERROR),
939 errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
942 elog(ERROR, "unrecognized item type: %d", item->itemtype);
948 * Add tuples to pg_amop and pg_amproc tying in the operators and
949 * functions. Dependencies on them are inserted, too.
951 storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
952 InvalidOid, operators, true);
953 storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
954 InvalidOid, procedures, true);
956 /* make information available to event triggers */
957 EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
958 operators, procedures);
962 * DROP part of ALTER OP FAMILY
965 AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
966 int maxOpNumber, int maxProcNumber, List *items)
968 List *operators; /* OpFamilyMember list for operators */
969 List *procedures; /* OpFamilyMember list for support procs */
976 * Scan the "items" list to obtain additional info.
980 CreateOpClassItem *item = lfirst(l);
983 OpFamilyMember *member;
985 Assert(IsA(item, CreateOpClassItem));
986 switch (item->itemtype)
988 case OPCLASS_ITEM_OPERATOR:
989 if (item->number <= 0 || item->number > maxOpNumber)
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);
997 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
998 member->number = item->number;
999 member->lefttype = lefttype;
1000 member->righttype = righttype;
1001 addFamilyMember(&operators, member, false);
1003 case OPCLASS_ITEM_FUNCTION:
1004 if (item->number <= 0 || item->number > maxProcNumber)
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);
1012 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1013 member->number = item->number;
1014 member->lefttype = lefttype;
1015 member->righttype = righttype;
1016 addFamilyMember(&procedures, member, true);
1018 case OPCLASS_ITEM_STORAGETYPE:
1019 /* grammar prevents this from appearing */
1021 elog(ERROR, "unrecognized item type: %d", item->itemtype);
1027 * Remove tuples from pg_amop and pg_amproc.
1029 dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1030 dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1032 /* make information available to event triggers */
1033 EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1034 operators, procedures);
1039 * Deal with explicit arg types used in ALTER ADD/DROP
1042 processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
1046 Assert(args != NIL);
1048 typeName = (TypeName *) linitial(args);
1049 *lefttype = typenameTypeId(NULL, typeName);
1051 if (list_length(args) > 1)
1053 typeName = (TypeName *) lsecond(args);
1054 *righttype = typenameTypeId(NULL, typeName);
1057 *righttype = *lefttype;
1059 if (list_length(args) > 2)
1061 (errcode(ERRCODE_SYNTAX_ERROR),
1062 errmsg("one or two argument types must be specified")));
1067 * Determine the lefttype/righttype to assign to an operator,
1068 * and do any validity checking we can manage.
1071 assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
1074 Form_pg_operator opform;
1076 /* Fetch the operator definition */
1077 optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
1079 elog(ERROR, "cache lookup failed for operator %u", member->object);
1080 opform = (Form_pg_operator) GETSTRUCT(optup);
1083 * Opfamily operators must be binary.
1085 if (opform->oprkind != 'b')
1087 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1088 errmsg("index operators must be binary")));
1090 if (OidIsValid(member->sortfamily))
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
1105 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
1107 elog(ERROR, "cache lookup failed for access method %u", amoid);
1108 pg_am = (Form_pg_am) GETSTRUCT(amtup);
1110 if (!pg_am->amcanorderbyop)
1112 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1113 errmsg("access method \"%s\" does not support ordering operators",
1114 NameStr(pg_am->amname))));
1116 ReleaseSysCache(amtup);
1121 * Search operators must return boolean.
1123 if (opform->oprresult != BOOLOID)
1125 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1126 errmsg("index search operators must return boolean")));
1130 * If lefttype/righttype isn't specified, use the operator's input types
1132 if (!OidIsValid(member->lefttype))
1133 member->lefttype = opform->oprleft;
1134 if (!OidIsValid(member->righttype))
1135 member->righttype = opform->oprright;
1137 ReleaseSysCache(optup);
1141 * Determine the lefttype/righttype to assign to a support procedure,
1142 * and do any validity checking we can manage.
1145 assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
1148 Form_pg_proc procform;
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);
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.
1161 if (amoid == BTREE_AM_OID)
1163 if (member->number == BTORDER_PROC)
1165 if (procform->pronargs != 2)
1167 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1168 errmsg("btree comparison procedures must have two arguments")));
1169 if (procform->prorettype != INT4OID)
1171 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1172 errmsg("btree comparison procedures must return integer")));
1175 * If lefttype/righttype isn't specified, use the proc's input
1178 if (!OidIsValid(member->lefttype))
1179 member->lefttype = procform->proargtypes.values[0];
1180 if (!OidIsValid(member->righttype))
1181 member->righttype = procform->proargtypes.values[1];
1183 else if (member->number == BTSORTSUPPORT_PROC)
1185 if (procform->pronargs != 1 ||
1186 procform->proargtypes.values[0] != INTERNALOID)
1188 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1189 errmsg("btree sort support procedures must accept type \"internal\"")));
1190 if (procform->prorettype != VOIDOID)
1192 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1193 errmsg("btree sort support procedures must return void")));
1196 * Can't infer lefttype/righttype from proc, so use default rule
1200 else if (amoid == HASH_AM_OID)
1202 if (procform->pronargs != 1)
1204 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1205 errmsg("hash procedures must have one argument")));
1206 if (procform->prorettype != INT4OID)
1208 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1209 errmsg("hash procedures must return integer")));
1212 * If lefttype/righttype isn't specified, use the proc's input type
1214 if (!OidIsValid(member->lefttype))
1215 member->lefttype = procform->proargtypes.values[0];
1216 if (!OidIsValid(member->righttype))
1217 member->righttype = procform->proargtypes.values[0];
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.
1225 if (!OidIsValid(member->lefttype))
1226 member->lefttype = typeoid;
1227 if (!OidIsValid(member->righttype))
1228 member->righttype = typeoid;
1230 if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1232 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1233 errmsg("associated data types must be specified for index support procedure")));
1235 ReleaseSysCache(proctup);
1239 * Add a new family member to the appropriate list, after checking for
1240 * duplicated strategy or proc number.
1243 addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
1249 OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1251 if (old->number == member->number &&
1252 old->lefttype == member->lefttype &&
1253 old->righttype == member->righttype)
1257 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1258 errmsg("procedure number %d for (%s,%s) appears more than once",
1260 format_type_be(member->lefttype),
1261 format_type_be(member->righttype))));
1264 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1265 errmsg("operator number %d for (%s,%s) appears more than once",
1267 format_type_be(member->lefttype),
1268 format_type_be(member->righttype))));
1271 *list = lappend(*list, member);
1275 * Dump the operators to pg_amop
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.
1282 storeOperators(List *opfamilyname, Oid amoid,
1283 Oid opfamilyoid, Oid opclassoid,
1284 List *operators, bool isAdd)
1287 Datum values[Natts_pg_amop];
1288 bool nulls[Natts_pg_amop];
1291 ObjectAddress myself,
1295 rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1297 foreach(l, operators)
1299 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1303 * If adding to an existing family, check for conflict with an
1304 * existing pg_amop entry (just to give a nicer error message)
1307 SearchSysCacheExists4(AMOPSTRATEGY,
1308 ObjectIdGetDatum(opfamilyoid),
1309 ObjectIdGetDatum(op->lefttype),
1310 ObjectIdGetDatum(op->righttype),
1311 Int16GetDatum(op->number)))
1313 (errcode(ERRCODE_DUPLICATE_OBJECT),
1314 errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1316 format_type_be(op->lefttype),
1317 format_type_be(op->righttype),
1318 NameListToString(opfamilyname))));
1320 oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1322 /* Create the pg_amop entry */
1323 memset(values, 0, sizeof(values));
1324 memset(nulls, false, sizeof(nulls));
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);
1335 tup = heap_form_tuple(rel->rd_att, values, nulls);
1337 entryoid = simple_heap_insert(rel, tup);
1339 CatalogUpdateIndexes(rel, tup);
1341 heap_freetuple(tup);
1343 /* Make its dependencies */
1344 myself.classId = AccessMethodOperatorRelationId;
1345 myself.objectId = entryoid;
1346 myself.objectSubId = 0;
1348 referenced.classId = OperatorRelationId;
1349 referenced.objectId = op->object;
1350 referenced.objectSubId = 0;
1352 if (OidIsValid(opclassoid))
1354 /* if contained in an opclass, use a NORMAL dep on operator */
1355 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
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);
1365 /* if "loose" in the opfamily, use a AUTO dep on operator */
1366 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
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);
1375 /* A search operator also needs a dep on the referenced opfamily */
1376 if (OidIsValid(op->sortfamily))
1378 referenced.classId = OperatorFamilyRelationId;
1379 referenced.objectId = op->sortfamily;
1380 referenced.objectSubId = 0;
1381 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1383 /* Post create hook of this access method operator */
1384 InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
1388 heap_close(rel, RowExclusiveLock);
1392 * Dump the procedures (support routines) to pg_amproc
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.
1399 storeProcedures(List *opfamilyname, Oid amoid,
1400 Oid opfamilyoid, Oid opclassoid,
1401 List *procedures, bool isAdd)
1404 Datum values[Natts_pg_amproc];
1405 bool nulls[Natts_pg_amproc];
1408 ObjectAddress myself,
1412 rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1414 foreach(l, procedures)
1416 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1419 * If adding to an existing family, check for conflict with an
1420 * existing pg_amproc entry (just to give a nicer error message)
1423 SearchSysCacheExists4(AMPROCNUM,
1424 ObjectIdGetDatum(opfamilyoid),
1425 ObjectIdGetDatum(proc->lefttype),
1426 ObjectIdGetDatum(proc->righttype),
1427 Int16GetDatum(proc->number)))
1429 (errcode(ERRCODE_DUPLICATE_OBJECT),
1430 errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1432 format_type_be(proc->lefttype),
1433 format_type_be(proc->righttype),
1434 NameListToString(opfamilyname))));
1436 /* Create the pg_amproc entry */
1437 memset(values, 0, sizeof(values));
1438 memset(nulls, false, sizeof(nulls));
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);
1446 tup = heap_form_tuple(rel->rd_att, values, nulls);
1448 entryoid = simple_heap_insert(rel, tup);
1450 CatalogUpdateIndexes(rel, tup);
1452 heap_freetuple(tup);
1454 /* Make its dependencies */
1455 myself.classId = AccessMethodProcedureRelationId;
1456 myself.objectId = entryoid;
1457 myself.objectSubId = 0;
1459 referenced.classId = ProcedureRelationId;
1460 referenced.objectId = proc->object;
1461 referenced.objectSubId = 0;
1463 if (OidIsValid(opclassoid))
1465 /* if contained in an opclass, use a NORMAL dep on procedure */
1466 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
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);
1476 /* if "loose" in the opfamily, use a AUTO dep on procedure */
1477 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
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);
1485 /* Post create hook of access method procedure */
1486 InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
1490 heap_close(rel, RowExclusiveLock);
1495 * Remove operator entries from an opfamily.
1497 * Note: this is only allowed for "loose" members of an opfamily, hence
1498 * behavior is always RESTRICT.
1501 dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1506 foreach(l, operators)
1508 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1510 ObjectAddress object;
1512 amopid = GetSysCacheOid4(AMOPSTRATEGY,
1513 ObjectIdGetDatum(opfamilyoid),
1514 ObjectIdGetDatum(op->lefttype),
1515 ObjectIdGetDatum(op->righttype),
1516 Int16GetDatum(op->number));
1517 if (!OidIsValid(amopid))
1519 (errcode(ERRCODE_UNDEFINED_OBJECT),
1520 errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1522 format_type_be(op->lefttype),
1523 format_type_be(op->righttype),
1524 NameListToString(opfamilyname))));
1526 object.classId = AccessMethodOperatorRelationId;
1527 object.objectId = amopid;
1528 object.objectSubId = 0;
1530 performDeletion(&object, DROP_RESTRICT, 0);
1535 * Remove procedure entries from an opfamily.
1537 * Note: this is only allowed for "loose" members of an opfamily, hence
1538 * behavior is always RESTRICT.
1541 dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1546 foreach(l, procedures)
1548 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1550 ObjectAddress object;
1552 amprocid = GetSysCacheOid4(AMPROCNUM,
1553 ObjectIdGetDatum(opfamilyoid),
1554 ObjectIdGetDatum(op->lefttype),
1555 ObjectIdGetDatum(op->righttype),
1556 Int16GetDatum(op->number));
1557 if (!OidIsValid(amprocid))
1559 (errcode(ERRCODE_UNDEFINED_OBJECT),
1560 errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1562 format_type_be(op->lefttype),
1563 format_type_be(op->righttype),
1564 NameListToString(opfamilyname))));
1566 object.classId = AccessMethodProcedureRelationId;
1567 object.objectId = amprocid;
1568 object.objectSubId = 0;
1570 performDeletion(&object, DROP_RESTRICT, 0);
1575 * Deletion subroutines for use by dependency.c.
1578 RemoveOpFamilyById(Oid opfamilyOid)
1583 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
1585 tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
1586 if (!HeapTupleIsValid(tup)) /* should not happen */
1587 elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1589 simple_heap_delete(rel, &tup->t_self);
1591 ReleaseSysCache(tup);
1593 heap_close(rel, RowExclusiveLock);
1597 RemoveOpClassById(Oid opclassOid)
1602 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1604 tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
1605 if (!HeapTupleIsValid(tup)) /* should not happen */
1606 elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1608 simple_heap_delete(rel, &tup->t_self);
1610 ReleaseSysCache(tup);
1612 heap_close(rel, RowExclusiveLock);
1616 RemoveAmOpEntryById(Oid entryOid)
1620 ScanKeyData skey[1];
1623 ScanKeyInit(&skey[0],
1624 ObjectIdAttributeNumber,
1625 BTEqualStrategyNumber, F_OIDEQ,
1626 ObjectIdGetDatum(entryOid));
1628 rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1630 scan = systable_beginscan(rel, AccessMethodOperatorOidIndexId, true,
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);
1638 simple_heap_delete(rel, &tup->t_self);
1640 systable_endscan(scan);
1641 heap_close(rel, RowExclusiveLock);
1645 RemoveAmProcEntryById(Oid entryOid)
1649 ScanKeyData skey[1];
1652 ScanKeyInit(&skey[0],
1653 ObjectIdAttributeNumber,
1654 BTEqualStrategyNumber, F_OIDEQ,
1655 ObjectIdGetDatum(entryOid));
1657 rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1659 scan = systable_beginscan(rel, AccessMethodProcedureOidIndexId, true,
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);
1667 simple_heap_delete(rel, &tup->t_self);
1669 systable_endscan(scan);
1670 heap_close(rel, RowExclusiveLock);
1674 get_am_name(Oid amOid)
1677 char *result = NULL;
1679 tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
1680 if (HeapTupleIsValid(tup))
1682 result = pstrdup(NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
1683 ReleaseSysCache(tup);
1689 * Subroutine for ALTER OPERATOR CLASS SET SCHEMA/RENAME
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.
1695 IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
1698 /* make sure the new name doesn't exist */
1699 if (SearchSysCacheExists3(CLAAMNAMENSP,
1700 ObjectIdGetDatum(opcmethod),
1701 CStringGetDatum(opcname),
1702 ObjectIdGetDatum(opcnamespace)))
1704 (errcode(ERRCODE_DUPLICATE_OBJECT),
1705 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1707 get_am_name(opcmethod),
1708 get_namespace_name(opcnamespace))));
1712 * Subroutine for ALTER OPERATOR FAMILY SET SCHEMA/RENAME
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.
1718 IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
1721 /* make sure the new name doesn't exist */
1722 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
1723 ObjectIdGetDatum(opfmethod),
1724 CStringGetDatum(opfname),
1725 ObjectIdGetDatum(opfnamespace)))
1727 (errcode(ERRCODE_DUPLICATE_OBJECT),
1728 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1730 get_am_name(opfmethod),
1731 get_namespace_name(opfnamespace))));
1735 * get_am_oid - given an access method name, look up the OID
1737 * If missing_ok is false, throw an error if access method not found. If
1738 * true, just return InvalidOid.
1741 get_am_oid(const char *amname, bool missing_ok)
1745 oid = GetSysCacheOid1(AMNAME, CStringGetDatum(amname));
1746 if (!OidIsValid(oid) && !missing_ok)
1748 (errcode(ERRCODE_UNDEFINED_OBJECT),
1749 errmsg("access method \"%s\" does not exist", amname)));