1 /*-------------------------------------------------------------------------
5 * Routines for opclass (and opfamily) manipulation commands
7 * Portions Copyright (c) 1996-2013, 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/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"
51 * We use lists of this struct type to keep track of both operators and
52 * procedures while building or adding to an opfamily.
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 */
64 static void AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
65 int maxOpNumber, int maxProcNumber,
67 static void AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
68 int maxOpNumber, int maxProcNumber,
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,
82 static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
87 * Look up an existing opfamily by name.
89 * Returns a syscache tuple reference, or NULL if not found.
92 OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
98 /* deconstruct the name list */
99 DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
103 /* Look in specific schema only */
106 namespaceId = LookupExplicitNamespace(schemaname, false);
107 htup = SearchSysCache3(OPFAMILYAMNAMENSP,
108 ObjectIdGetDatum(amID),
109 PointerGetDatum(opfname),
110 ObjectIdGetDatum(namespaceId));
114 /* Unqualified opfamily name, so search the search path */
115 Oid opfID = OpfamilynameGetOpfid(amID, opfname);
117 if (!OidIsValid(opfID))
120 htup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfID));
123 if (!HeapTupleIsValid(htup) && !missing_ok)
127 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
128 if (!HeapTupleIsValid(amtup))
129 elog(ERROR, "cache lookup failed for access method %u", amID);
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))));
142 * find an opfamily OID by possibly qualified name
144 * If not found, returns InvalidOid if missing_ok, else throws error.
147 get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
152 htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
153 if (!HeapTupleIsValid(htup))
155 opfID = HeapTupleGetOid(htup);
156 ReleaseSysCache(htup);
163 * Look up an existing opclass by name.
165 * Returns a syscache tuple reference, or NULL if not found.
168 OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
174 /* deconstruct the name list */
175 DeconstructQualifiedName(opclassname, &schemaname, &opcname);
179 /* Look in specific schema only */
182 namespaceId = LookupExplicitNamespace(schemaname, false);
183 htup = SearchSysCache3(CLAAMNAMENSP,
184 ObjectIdGetDatum(amID),
185 PointerGetDatum(opcname),
186 ObjectIdGetDatum(namespaceId));
190 /* Unqualified opclass name, so search the search path */
191 Oid opcID = OpclassnameGetOpcid(amID, opcname);
193 if (!OidIsValid(opcID))
196 htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
199 if (!HeapTupleIsValid(htup) && !missing_ok)
203 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
204 if (!HeapTupleIsValid(amtup))
205 elog(ERROR, "cache lookup failed for access method %u", amID);
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))));
218 * find an opclass OID by possibly qualified name
220 * If not found, returns InvalidOid if missing_ok, else throws error.
223 get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
228 htup = OpClassCacheLookup(amID, opclassname, missing_ok);
229 if (!HeapTupleIsValid(htup))
231 opcID = HeapTupleGetOid(htup);
232 ReleaseSysCache(htup);
239 * Internal routine to make the catalog entry for a new operator family.
241 * Caller must have done permissions checks etc. already.
244 CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
249 Datum values[Natts_pg_opfamily];
250 bool nulls[Natts_pg_opfamily];
252 ObjectAddress myself,
255 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
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").
261 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
262 ObjectIdGetDatum(amoid),
263 CStringGetDatum(opfname),
264 ObjectIdGetDatum(namespaceoid)))
266 (errcode(ERRCODE_DUPLICATE_OBJECT),
267 errmsg("operator family \"%s\" for access method \"%s\" already exists",
271 * Okay, let's create the pg_opfamily entry.
273 memset(values, 0, sizeof(values));
274 memset(nulls, false, sizeof(nulls));
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());
282 tup = heap_form_tuple(rel->rd_att, values, nulls);
284 opfamilyoid = simple_heap_insert(rel, tup);
286 CatalogUpdateIndexes(rel, tup);
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
295 myself.classId = OperatorFamilyRelationId;
296 myself.objectId = opfamilyoid;
297 myself.objectSubId = 0;
299 /* dependency on namespace */
300 referenced.classId = NamespaceRelationId;
301 referenced.objectId = namespaceoid;
302 referenced.objectSubId = 0;
303 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
305 /* dependency on owner */
306 recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
308 /* dependency on extension */
309 recordDependencyOnCurrentExtension(&myself, false);
311 /* Post creation hook for new operator family */
312 InvokeObjectAccessHook(OAT_POST_CREATE,
313 OperatorFamilyRelationId, opfamilyoid, 0, NULL);
315 heap_close(rel, RowExclusiveLock);
322 * Define a new index operator class.
325 DefineOpClass(CreateOpClassStmt *stmt)
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 */
343 Datum values[Natts_pg_opclass];
344 bool nulls[Natts_pg_opclass];
347 ObjectAddress myself,
350 /* Convert list of names to a name and namespace */
351 namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
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));
360 /* Get necessary info about access method */
361 tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
362 if (!HeapTupleIsValid(tup))
364 (errcode(ERRCODE_UNDEFINED_OBJECT),
365 errmsg("access method \"%s\" does not exist",
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;
377 /* XXX Should we make any privilege check against the AM? */
379 ReleaseSysCache(tup);
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.
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 :-(
399 * XXX re-enable NOT_USED code sections below if you remove this test.
403 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
404 errmsg("must be superuser to create an operator class")));
406 /* Look up the datatype */
407 typeoid = typenameTypeId(NULL, stmt->datatype);
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);
417 * Look up the containing operator family, or create one if FAMILY option
418 * was omitted and there's not a match already.
420 if (stmt->opfamilyname)
422 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
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))
433 opfamilyoid = HeapTupleGetOid(tup);
436 * XXX given the superuser check above, there's no need for an
437 * ownership check here
439 ReleaseSysCache(tup);
444 * Create it ... again no need for more permissions ...
446 opfamilyoid = CreateOpFamily(stmt->amname, opcname,
447 namespaceoid, amoid);
454 /* Storage datatype is optional */
455 storageoid = InvalidOid;
458 * Scan the "items" list to obtain additional info.
460 foreach(l, stmt->items)
462 CreateOpClassItem *item = lfirst(l);
466 OpFamilyMember *member;
468 Assert(IsA(item, CreateOpClassItem));
469 switch (item->itemtype)
471 case OPCLASS_ITEM_OPERATOR:
472 if (item->number <= 0 || item->number > maxOpNumber)
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)
480 TypeName *typeName1 = (TypeName *) linitial(item->args);
481 TypeName *typeName2 = (TypeName *) lsecond(item->args);
483 operOid = LookupOperNameTypeNames(NULL, item->name,
484 typeName1, typeName2,
489 /* Default to binary op on input datatype */
490 operOid = LookupOperName(NULL, item->name,
495 if (item->order_family)
496 sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
500 sortfamilyOid = InvalidOid;
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));
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);
522 case OPCLASS_ITEM_FUNCTION:
523 if (item->number <= 0 || item->number > maxProcNumber)
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,
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));
540 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
541 member->object = funcOid;
542 member->number = item->number;
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);
549 assignProcTypes(member, amoid, typeoid);
550 addFamilyMember(&procedures, member, true);
552 case OPCLASS_ITEM_STORAGETYPE:
553 if (OidIsValid(storageoid))
555 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
556 errmsg("storage type specified more than once")));
557 storageoid = typenameTypeId(NULL, item->storedtype);
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);
567 elog(ERROR, "unrecognized item type: %d", item->itemtype);
573 * If storagetype is specified, make sure it's legal.
575 if (OidIsValid(storageoid))
577 /* Just drop the spec if same as column datatype */
578 if (storageoid == typeoid)
579 storageoid = InvalidOid;
582 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
583 errmsg("storage type cannot be different from data type for access method \"%s\"",
587 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
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").
593 if (SearchSysCacheExists3(CLAAMNAMENSP,
594 ObjectIdGetDatum(amoid),
595 CStringGetDatum(opcname),
596 ObjectIdGetDatum(namespaceoid)))
598 (errcode(ERRCODE_DUPLICATE_OBJECT),
599 errmsg("operator class \"%s\" for access method \"%s\" already exists",
600 opcname, stmt->amname)));
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.)
612 ScanKeyInit(&skey[0],
613 Anum_pg_opclass_opcmethod,
614 BTEqualStrategyNumber, F_OIDEQ,
615 ObjectIdGetDatum(amoid));
617 scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
618 SnapshotNow, 1, skey);
620 while (HeapTupleIsValid(tup = systable_getnext(scan)))
622 Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
624 if (opclass->opcintype == typeoid && opclass->opcdefault)
626 (errcode(ERRCODE_DUPLICATE_OBJECT),
627 errmsg("could not make operator class \"%s\" be default for type %s",
629 TypeNameToString(stmt->datatype)),
630 errdetail("Operator class \"%s\" already is the default.",
631 NameStr(opclass->opcname))));
634 systable_endscan(scan);
638 * Okay, let's create the pg_opclass entry.
640 memset(values, 0, sizeof(values));
641 memset(nulls, false, sizeof(nulls));
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);
653 tup = heap_form_tuple(rel->rd_att, values, nulls);
655 opclassoid = simple_heap_insert(rel, tup);
657 CatalogUpdateIndexes(rel, tup);
662 * Now add tuples to pg_amop and pg_amproc tying in the operators and
663 * functions. Dependencies on them are inserted, too.
665 storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
666 opclassoid, operators, false);
667 storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
668 opclassoid, procedures, false);
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
675 myself.classId = OperatorClassRelationId;
676 myself.objectId = opclassoid;
677 myself.objectSubId = 0;
679 /* dependency on namespace */
680 referenced.classId = NamespaceRelationId;
681 referenced.objectId = namespaceoid;
682 referenced.objectSubId = 0;
683 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
685 /* dependency on opfamily */
686 referenced.classId = OperatorFamilyRelationId;
687 referenced.objectId = opfamilyoid;
688 referenced.objectSubId = 0;
689 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
691 /* dependency on indexed datatype */
692 referenced.classId = TypeRelationId;
693 referenced.objectId = typeoid;
694 referenced.objectSubId = 0;
695 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
697 /* dependency on storage datatype */
698 if (OidIsValid(storageoid))
700 referenced.classId = TypeRelationId;
701 referenced.objectId = storageoid;
702 referenced.objectSubId = 0;
703 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
706 /* dependency on owner */
707 recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
709 /* dependency on extension */
710 recordDependencyOnCurrentExtension(&myself, false);
712 /* Post creation hook for new operator class */
713 InvokeObjectAccessHook(OAT_POST_CREATE,
714 OperatorClassRelationId, opclassoid, 0, NULL);
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->opfamilyname, amoid, opfamilyoid,
819 maxOpNumber, maxProcNumber,
822 AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
823 maxOpNumber, maxProcNumber,
830 * ADD part of ALTER OP FAMILY
833 AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
834 int maxOpNumber, int maxProcNumber,
837 List *operators; /* OpFamilyMember list for operators */
838 List *procedures; /* OpFamilyMember list for support procs */
845 * Scan the "items" list to obtain additional info.
849 CreateOpClassItem *item = lfirst(l);
853 OpFamilyMember *member;
855 Assert(IsA(item, CreateOpClassItem));
856 switch (item->itemtype)
858 case OPCLASS_ITEM_OPERATOR:
859 if (item->number <= 0 || item->number > maxOpNumber)
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)
867 TypeName *typeName1 = (TypeName *) linitial(item->args);
868 TypeName *typeName2 = (TypeName *) lsecond(item->args);
870 operOid = LookupOperNameTypeNames(NULL, item->name,
871 typeName1, typeName2,
877 (errcode(ERRCODE_SYNTAX_ERROR),
878 errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
879 operOid = InvalidOid; /* keep compiler quiet */
882 if (item->order_family)
883 sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
887 sortfamilyOid = InvalidOid;
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));
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);
909 case OPCLASS_ITEM_FUNCTION:
910 if (item->number <= 0 || item->number > maxProcNumber)
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,
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));
927 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
928 member->object = funcOid;
929 member->number = item->number;
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);
936 assignProcTypes(member, amoid, InvalidOid);
937 addFamilyMember(&procedures, member, true);
939 case OPCLASS_ITEM_STORAGETYPE:
941 (errcode(ERRCODE_SYNTAX_ERROR),
942 errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
945 elog(ERROR, "unrecognized item type: %d", item->itemtype);
951 * Add tuples to pg_amop and pg_amproc tying in the operators and
952 * functions. Dependencies on them are inserted, too.
954 storeOperators(opfamilyname, amoid, opfamilyoid,
955 InvalidOid, operators, true);
956 storeProcedures(opfamilyname, amoid, opfamilyoid,
957 InvalidOid, procedures, true);
961 * DROP part of ALTER OP FAMILY
964 AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
965 int maxOpNumber, int maxProcNumber,
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(opfamilyname, amoid, opfamilyoid, operators);
1030 dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
1035 * Deal with explicit arg types used in ALTER ADD/DROP
1038 processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
1042 Assert(args != NIL);
1044 typeName = (TypeName *) linitial(args);
1045 *lefttype = typenameTypeId(NULL, typeName);
1047 if (list_length(args) > 1)
1049 typeName = (TypeName *) lsecond(args);
1050 *righttype = typenameTypeId(NULL, typeName);
1053 *righttype = *lefttype;
1055 if (list_length(args) > 2)
1057 (errcode(ERRCODE_SYNTAX_ERROR),
1058 errmsg("one or two argument types must be specified")));
1063 * Determine the lefttype/righttype to assign to an operator,
1064 * and do any validity checking we can manage.
1067 assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
1070 Form_pg_operator opform;
1072 /* Fetch the operator definition */
1073 optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
1075 elog(ERROR, "cache lookup failed for operator %u", member->object);
1076 opform = (Form_pg_operator) GETSTRUCT(optup);
1079 * Opfamily operators must be binary.
1081 if (opform->oprkind != 'b')
1083 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1084 errmsg("index operators must be binary")));
1086 if (OidIsValid(member->sortfamily))
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
1101 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
1103 elog(ERROR, "cache lookup failed for access method %u", amoid);
1104 pg_am = (Form_pg_am) GETSTRUCT(amtup);
1106 if (!pg_am->amcanorderbyop)
1108 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1109 errmsg("access method \"%s\" does not support ordering operators",
1110 NameStr(pg_am->amname))));
1112 ReleaseSysCache(amtup);
1117 * Search operators must return boolean.
1119 if (opform->oprresult != BOOLOID)
1121 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1122 errmsg("index search operators must return boolean")));
1126 * If lefttype/righttype isn't specified, use the operator's input types
1128 if (!OidIsValid(member->lefttype))
1129 member->lefttype = opform->oprleft;
1130 if (!OidIsValid(member->righttype))
1131 member->righttype = opform->oprright;
1133 ReleaseSysCache(optup);
1137 * Determine the lefttype/righttype to assign to a support procedure,
1138 * and do any validity checking we can manage.
1141 assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
1144 Form_pg_proc procform;
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);
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.
1157 if (amoid == BTREE_AM_OID)
1159 if (member->number == BTORDER_PROC)
1161 if (procform->pronargs != 2)
1163 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1164 errmsg("btree comparison procedures must have two arguments")));
1165 if (procform->prorettype != INT4OID)
1167 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1168 errmsg("btree comparison procedures must return integer")));
1171 * If lefttype/righttype isn't specified, use the proc's input
1174 if (!OidIsValid(member->lefttype))
1175 member->lefttype = procform->proargtypes.values[0];
1176 if (!OidIsValid(member->righttype))
1177 member->righttype = procform->proargtypes.values[1];
1179 else if (member->number == BTSORTSUPPORT_PROC)
1181 if (procform->pronargs != 1 ||
1182 procform->proargtypes.values[0] != INTERNALOID)
1184 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1185 errmsg("btree sort support procedures must accept type \"internal\"")));
1186 if (procform->prorettype != VOIDOID)
1188 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1189 errmsg("btree sort support procedures must return void")));
1192 * Can't infer lefttype/righttype from proc, so use default rule
1196 else if (amoid == HASH_AM_OID)
1198 if (procform->pronargs != 1)
1200 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1201 errmsg("hash procedures must have one argument")));
1202 if (procform->prorettype != INT4OID)
1204 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1205 errmsg("hash procedures must return integer")));
1208 * If lefttype/righttype isn't specified, use the proc's input type
1210 if (!OidIsValid(member->lefttype))
1211 member->lefttype = procform->proargtypes.values[0];
1212 if (!OidIsValid(member->righttype))
1213 member->righttype = procform->proargtypes.values[0];
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.
1221 if (!OidIsValid(member->lefttype))
1222 member->lefttype = typeoid;
1223 if (!OidIsValid(member->righttype))
1224 member->righttype = typeoid;
1226 if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1228 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1229 errmsg("associated data types must be specified for index support procedure")));
1231 ReleaseSysCache(proctup);
1235 * Add a new family member to the appropriate list, after checking for
1236 * duplicated strategy or proc number.
1239 addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
1245 OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1247 if (old->number == member->number &&
1248 old->lefttype == member->lefttype &&
1249 old->righttype == member->righttype)
1253 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1254 errmsg("procedure number %d for (%s,%s) appears more than once",
1256 format_type_be(member->lefttype),
1257 format_type_be(member->righttype))));
1260 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1261 errmsg("operator number %d for (%s,%s) appears more than once",
1263 format_type_be(member->lefttype),
1264 format_type_be(member->righttype))));
1267 *list = lappend(*list, member);
1271 * Dump the operators to pg_amop
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.
1278 storeOperators(List *opfamilyname, Oid amoid,
1279 Oid opfamilyoid, Oid opclassoid,
1280 List *operators, bool isAdd)
1283 Datum values[Natts_pg_amop];
1284 bool nulls[Natts_pg_amop];
1287 ObjectAddress myself,
1291 rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1293 foreach(l, operators)
1295 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1299 * If adding to an existing family, check for conflict with an
1300 * existing pg_amop entry (just to give a nicer error message)
1303 SearchSysCacheExists4(AMOPSTRATEGY,
1304 ObjectIdGetDatum(opfamilyoid),
1305 ObjectIdGetDatum(op->lefttype),
1306 ObjectIdGetDatum(op->righttype),
1307 Int16GetDatum(op->number)))
1309 (errcode(ERRCODE_DUPLICATE_OBJECT),
1310 errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1312 format_type_be(op->lefttype),
1313 format_type_be(op->righttype),
1314 NameListToString(opfamilyname))));
1316 oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1318 /* Create the pg_amop entry */
1319 memset(values, 0, sizeof(values));
1320 memset(nulls, false, sizeof(nulls));
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);
1331 tup = heap_form_tuple(rel->rd_att, values, nulls);
1333 entryoid = simple_heap_insert(rel, tup);
1335 CatalogUpdateIndexes(rel, tup);
1337 heap_freetuple(tup);
1339 /* Make its dependencies */
1340 myself.classId = AccessMethodOperatorRelationId;
1341 myself.objectId = entryoid;
1342 myself.objectSubId = 0;
1344 referenced.classId = OperatorRelationId;
1345 referenced.objectId = op->object;
1346 referenced.objectSubId = 0;
1348 if (OidIsValid(opclassoid))
1350 /* if contained in an opclass, use a NORMAL dep on operator */
1351 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
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);
1361 /* if "loose" in the opfamily, use a AUTO dep on operator */
1362 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
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);
1371 /* A search operator also needs a dep on the referenced opfamily */
1372 if (OidIsValid(op->sortfamily))
1374 referenced.classId = OperatorFamilyRelationId;
1375 referenced.objectId = op->sortfamily;
1376 referenced.objectSubId = 0;
1377 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1381 heap_close(rel, RowExclusiveLock);
1385 * Dump the procedures (support routines) to pg_amproc
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.
1392 storeProcedures(List *opfamilyname, Oid amoid,
1393 Oid opfamilyoid, Oid opclassoid,
1394 List *procedures, bool isAdd)
1397 Datum values[Natts_pg_amproc];
1398 bool nulls[Natts_pg_amproc];
1401 ObjectAddress myself,
1405 rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1407 foreach(l, procedures)
1409 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1412 * If adding to an existing family, check for conflict with an
1413 * existing pg_amproc entry (just to give a nicer error message)
1416 SearchSysCacheExists4(AMPROCNUM,
1417 ObjectIdGetDatum(opfamilyoid),
1418 ObjectIdGetDatum(proc->lefttype),
1419 ObjectIdGetDatum(proc->righttype),
1420 Int16GetDatum(proc->number)))
1422 (errcode(ERRCODE_DUPLICATE_OBJECT),
1423 errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1425 format_type_be(proc->lefttype),
1426 format_type_be(proc->righttype),
1427 NameListToString(opfamilyname))));
1429 /* Create the pg_amproc entry */
1430 memset(values, 0, sizeof(values));
1431 memset(nulls, false, sizeof(nulls));
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);
1439 tup = heap_form_tuple(rel->rd_att, values, nulls);
1441 entryoid = simple_heap_insert(rel, tup);
1443 CatalogUpdateIndexes(rel, tup);
1445 heap_freetuple(tup);
1447 /* Make its dependencies */
1448 myself.classId = AccessMethodProcedureRelationId;
1449 myself.objectId = entryoid;
1450 myself.objectSubId = 0;
1452 referenced.classId = ProcedureRelationId;
1453 referenced.objectId = proc->object;
1454 referenced.objectSubId = 0;
1456 if (OidIsValid(opclassoid))
1458 /* if contained in an opclass, use a NORMAL dep on procedure */
1459 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
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);
1469 /* if "loose" in the opfamily, use a AUTO dep on procedure */
1470 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
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);
1480 heap_close(rel, RowExclusiveLock);
1485 * Remove operator entries from an opfamily.
1487 * Note: this is only allowed for "loose" members of an opfamily, hence
1488 * behavior is always RESTRICT.
1491 dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1496 foreach(l, operators)
1498 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1500 ObjectAddress object;
1502 amopid = GetSysCacheOid4(AMOPSTRATEGY,
1503 ObjectIdGetDatum(opfamilyoid),
1504 ObjectIdGetDatum(op->lefttype),
1505 ObjectIdGetDatum(op->righttype),
1506 Int16GetDatum(op->number));
1507 if (!OidIsValid(amopid))
1509 (errcode(ERRCODE_UNDEFINED_OBJECT),
1510 errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1512 format_type_be(op->lefttype),
1513 format_type_be(op->righttype),
1514 NameListToString(opfamilyname))));
1516 object.classId = AccessMethodOperatorRelationId;
1517 object.objectId = amopid;
1518 object.objectSubId = 0;
1520 performDeletion(&object, DROP_RESTRICT, 0);
1525 * Remove procedure entries from an opfamily.
1527 * Note: this is only allowed for "loose" members of an opfamily, hence
1528 * behavior is always RESTRICT.
1531 dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1536 foreach(l, procedures)
1538 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1540 ObjectAddress object;
1542 amprocid = GetSysCacheOid4(AMPROCNUM,
1543 ObjectIdGetDatum(opfamilyoid),
1544 ObjectIdGetDatum(op->lefttype),
1545 ObjectIdGetDatum(op->righttype),
1546 Int16GetDatum(op->number));
1547 if (!OidIsValid(amprocid))
1549 (errcode(ERRCODE_UNDEFINED_OBJECT),
1550 errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1552 format_type_be(op->lefttype),
1553 format_type_be(op->righttype),
1554 NameListToString(opfamilyname))));
1556 object.classId = AccessMethodProcedureRelationId;
1557 object.objectId = amprocid;
1558 object.objectSubId = 0;
1560 performDeletion(&object, DROP_RESTRICT, 0);
1565 * Deletion subroutines for use by dependency.c.
1568 RemoveOpFamilyById(Oid opfamilyOid)
1573 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
1575 tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
1576 if (!HeapTupleIsValid(tup)) /* should not happen */
1577 elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1579 simple_heap_delete(rel, &tup->t_self);
1581 ReleaseSysCache(tup);
1583 heap_close(rel, RowExclusiveLock);
1587 RemoveOpClassById(Oid opclassOid)
1592 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1594 tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
1595 if (!HeapTupleIsValid(tup)) /* should not happen */
1596 elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1598 simple_heap_delete(rel, &tup->t_self);
1600 ReleaseSysCache(tup);
1602 heap_close(rel, RowExclusiveLock);
1606 RemoveAmOpEntryById(Oid entryOid)
1610 ScanKeyData skey[1];
1613 ScanKeyInit(&skey[0],
1614 ObjectIdAttributeNumber,
1615 BTEqualStrategyNumber, F_OIDEQ,
1616 ObjectIdGetDatum(entryOid));
1618 rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1620 scan = systable_beginscan(rel, AccessMethodOperatorOidIndexId, true,
1621 SnapshotNow, 1, skey);
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);
1628 simple_heap_delete(rel, &tup->t_self);
1630 systable_endscan(scan);
1631 heap_close(rel, RowExclusiveLock);
1635 RemoveAmProcEntryById(Oid entryOid)
1639 ScanKeyData skey[1];
1642 ScanKeyInit(&skey[0],
1643 ObjectIdAttributeNumber,
1644 BTEqualStrategyNumber, F_OIDEQ,
1645 ObjectIdGetDatum(entryOid));
1647 rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1649 scan = systable_beginscan(rel, AccessMethodProcedureOidIndexId, true,
1650 SnapshotNow, 1, skey);
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);
1657 simple_heap_delete(rel, &tup->t_self);
1659 systable_endscan(scan);
1660 heap_close(rel, RowExclusiveLock);
1664 get_am_name(Oid amOid)
1667 char *result = NULL;
1669 tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
1670 if (HeapTupleIsValid(tup))
1672 result = pstrdup(NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
1673 ReleaseSysCache(tup);
1679 * Subroutine for ALTER OPERATOR CLASS SET SCHEMA/RENAME
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.
1685 IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
1688 /* make sure the new name doesn't exist */
1689 if (SearchSysCacheExists3(CLAAMNAMENSP,
1690 ObjectIdGetDatum(opcmethod),
1691 CStringGetDatum(opcname),
1692 ObjectIdGetDatum(opcnamespace)))
1694 (errcode(ERRCODE_DUPLICATE_OBJECT),
1695 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1697 get_am_name(opcmethod),
1698 get_namespace_name(opcnamespace))));
1702 * Subroutine for ALTER OPERATOR FAMILY SET SCHEMA/RENAME
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.
1708 IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
1711 /* make sure the new name doesn't exist */
1712 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
1713 ObjectIdGetDatum(opfmethod),
1714 CStringGetDatum(opfname),
1715 ObjectIdGetDatum(opfnamespace)))
1717 (errcode(ERRCODE_DUPLICATE_OBJECT),
1718 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1720 get_am_name(opfmethod),
1721 get_namespace_name(opfnamespace))));
1725 * get_am_oid - given an access method name, look up the OID
1727 * If missing_ok is false, throw an error if access method not found. If
1728 * true, just return InvalidOid.
1731 get_am_oid(const char *amname, bool missing_ok)
1735 oid = GetSysCacheOid1(AMNAME, CStringGetDatum(amname));
1736 if (!OidIsValid(oid) && !missing_ok)
1738 (errcode(ERRCODE_UNDEFINED_OBJECT),
1739 errmsg("access method \"%s\" does not exist", amname)));