Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / commands / opclasscmds.c
blob733b0269afa418cb2c7fc92bdb4306cbd532e07b
1 /*-------------------------------------------------------------------------
3 * opclasscmds.c
5 * Routines for opclass (and opfamily) manipulation commands
7 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * IDENTIFICATION
12 * $PostgreSQL$
14 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include <limits.h>
20 #include "access/genam.h"
21 #include "access/heapam.h"
22 #include "access/sysattr.h"
23 #include "catalog/dependency.h"
24 #include "catalog/indexing.h"
25 #include "catalog/pg_amop.h"
26 #include "catalog/pg_amproc.h"
27 #include "catalog/pg_namespace.h"
28 #include "catalog/pg_opclass.h"
29 #include "catalog/pg_operator.h"
30 #include "catalog/pg_opfamily.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_type.h"
33 #include "commands/defrem.h"
34 #include "miscadmin.h"
35 #include "parser/parse_func.h"
36 #include "parser/parse_oper.h"
37 #include "parser/parse_type.h"
38 #include "utils/acl.h"
39 #include "utils/builtins.h"
40 #include "utils/fmgroids.h"
41 #include "utils/lsyscache.h"
42 #include "utils/rel.h"
43 #include "utils/syscache.h"
44 #include "utils/tqual.h"
48 * We use lists of this struct type to keep track of both operators and
49 * procedures while building or adding to an opfamily.
51 typedef struct
53 Oid object; /* operator or support proc's OID */
54 int number; /* strategy or support proc number */
55 Oid lefttype; /* lefttype */
56 Oid righttype; /* righttype */
57 } OpFamilyMember;
60 static void AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
61 int maxOpNumber, int maxProcNumber,
62 List *items);
63 static void AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
64 int maxOpNumber, int maxProcNumber,
65 List *items);
66 static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
67 static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
68 static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
69 static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
70 static void storeOperators(List *opfamilyname, Oid amoid,
71 Oid opfamilyoid, Oid opclassoid,
72 List *operators, bool isAdd);
73 static void storeProcedures(List *opfamilyname, Oid amoid,
74 Oid opfamilyoid, Oid opclassoid,
75 List *procedures, bool isAdd);
76 static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
77 List *operators);
78 static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
79 List *procedures);
80 static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
81 Oid newOwnerId);
82 static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
83 Oid newOwnerId);
87 * OpFamilyCacheLookup
88 * Look up an existing opfamily by name.
90 * Returns a syscache tuple reference, or NULL if not found.
92 static HeapTuple
93 OpFamilyCacheLookup(Oid amID, List *opfamilyname)
95 char *schemaname;
96 char *opfname;
98 /* deconstruct the name list */
99 DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
101 if (schemaname)
103 /* Look in specific schema only */
104 Oid namespaceId;
106 namespaceId = LookupExplicitNamespace(schemaname);
107 return SearchSysCache(OPFAMILYAMNAMENSP,
108 ObjectIdGetDatum(amID),
109 PointerGetDatum(opfname),
110 ObjectIdGetDatum(namespaceId),
113 else
115 /* Unqualified opfamily name, so search the search path */
116 Oid opfID = OpfamilynameGetOpfid(amID, opfname);
118 if (!OidIsValid(opfID))
119 return NULL;
120 return SearchSysCache(OPFAMILYOID,
121 ObjectIdGetDatum(opfID),
122 0, 0, 0);
127 * OpClassCacheLookup
128 * Look up an existing opclass by name.
130 * Returns a syscache tuple reference, or NULL if not found.
132 static HeapTuple
133 OpClassCacheLookup(Oid amID, List *opclassname)
135 char *schemaname;
136 char *opcname;
138 /* deconstruct the name list */
139 DeconstructQualifiedName(opclassname, &schemaname, &opcname);
141 if (schemaname)
143 /* Look in specific schema only */
144 Oid namespaceId;
146 namespaceId = LookupExplicitNamespace(schemaname);
147 return SearchSysCache(CLAAMNAMENSP,
148 ObjectIdGetDatum(amID),
149 PointerGetDatum(opcname),
150 ObjectIdGetDatum(namespaceId),
153 else
155 /* Unqualified opclass name, so search the search path */
156 Oid opcID = OpclassnameGetOpcid(amID, opcname);
158 if (!OidIsValid(opcID))
159 return NULL;
160 return SearchSysCache(CLAOID,
161 ObjectIdGetDatum(opcID),
162 0, 0, 0);
167 * CreateOpFamily
168 * Internal routine to make the catalog entry for a new operator family.
170 * Caller must have done permissions checks etc. already.
172 static Oid
173 CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
175 Oid opfamilyoid;
176 Relation rel;
177 HeapTuple tup;
178 Datum values[Natts_pg_opfamily];
179 char nulls[Natts_pg_opfamily];
180 NameData opfName;
181 ObjectAddress myself,
182 referenced;
184 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
187 * Make sure there is no existing opfamily of this name (this is just to
188 * give a more friendly error message than "duplicate key").
190 if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
191 ObjectIdGetDatum(amoid),
192 CStringGetDatum(opfname),
193 ObjectIdGetDatum(namespaceoid),
195 ereport(ERROR,
196 (errcode(ERRCODE_DUPLICATE_OBJECT),
197 errmsg("operator family \"%s\" for access method \"%s\" already exists",
198 opfname, amname)));
201 * Okay, let's create the pg_opfamily entry.
203 memset(values, 0, sizeof(values));
204 memset(nulls, ' ', sizeof(nulls));
206 values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
207 namestrcpy(&opfName, opfname);
208 values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
209 values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
210 values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
212 tup = heap_formtuple(rel->rd_att, values, nulls);
214 opfamilyoid = simple_heap_insert(rel, tup);
216 CatalogUpdateIndexes(rel, tup);
218 heap_freetuple(tup);
221 * Create dependencies for the opfamily proper. Note: we do not create a
222 * dependency link to the AM, because we don't currently support DROP
223 * ACCESS METHOD.
225 myself.classId = OperatorFamilyRelationId;
226 myself.objectId = opfamilyoid;
227 myself.objectSubId = 0;
229 /* dependency on namespace */
230 referenced.classId = NamespaceRelationId;
231 referenced.objectId = namespaceoid;
232 referenced.objectSubId = 0;
233 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
235 /* dependency on owner */
236 recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
238 heap_close(rel, RowExclusiveLock);
240 return opfamilyoid;
244 * DefineOpClass
245 * Define a new index operator class.
247 void
248 DefineOpClass(CreateOpClassStmt *stmt)
250 char *opcname; /* name of opclass we're creating */
251 Oid amoid, /* our AM's oid */
252 typeoid, /* indexable datatype oid */
253 storageoid, /* storage datatype oid, if any */
254 namespaceoid, /* namespace to create opclass in */
255 opfamilyoid, /* oid of containing opfamily */
256 opclassoid; /* oid of opclass we create */
257 int maxOpNumber, /* amstrategies value */
258 maxProcNumber; /* amsupport value */
259 bool amstorage; /* amstorage flag */
260 List *operators; /* OpFamilyMember list for operators */
261 List *procedures; /* OpFamilyMember list for support procs */
262 ListCell *l;
263 Relation rel;
264 HeapTuple tup;
265 Form_pg_am pg_am;
266 Datum values[Natts_pg_opclass];
267 char nulls[Natts_pg_opclass];
268 AclResult aclresult;
269 NameData opcName;
270 ObjectAddress myself,
271 referenced;
273 /* Convert list of names to a name and namespace */
274 namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
275 &opcname);
277 /* Check we have creation rights in target namespace */
278 aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
279 if (aclresult != ACLCHECK_OK)
280 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
281 get_namespace_name(namespaceoid));
283 /* Get necessary info about access method */
284 tup = SearchSysCache(AMNAME,
285 CStringGetDatum(stmt->amname),
286 0, 0, 0);
287 if (!HeapTupleIsValid(tup))
288 ereport(ERROR,
289 (errcode(ERRCODE_UNDEFINED_OBJECT),
290 errmsg("access method \"%s\" does not exist",
291 stmt->amname)));
293 amoid = HeapTupleGetOid(tup);
294 pg_am = (Form_pg_am) GETSTRUCT(tup);
295 maxOpNumber = pg_am->amstrategies;
296 /* if amstrategies is zero, just enforce that op numbers fit in int16 */
297 if (maxOpNumber <= 0)
298 maxOpNumber = SHRT_MAX;
299 maxProcNumber = pg_am->amsupport;
300 amstorage = pg_am->amstorage;
302 /* XXX Should we make any privilege check against the AM? */
304 ReleaseSysCache(tup);
307 * The question of appropriate permissions for CREATE OPERATOR CLASS is
308 * interesting. Creating an opclass is tantamount to granting public
309 * execute access on the functions involved, since the index machinery
310 * generally does not check access permission before using the functions.
311 * A minimum expectation therefore is that the caller have execute
312 * privilege with grant option. Since we don't have a way to make the
313 * opclass go away if the grant option is revoked, we choose instead to
314 * require ownership of the functions. It's also not entirely clear what
315 * permissions should be required on the datatype, but ownership seems
316 * like a safe choice.
318 * Currently, we require superuser privileges to create an opclass. This
319 * seems necessary because we have no way to validate that the offered set
320 * of operators and functions are consistent with the AM's expectations.
321 * It would be nice to provide such a check someday, if it can be done
322 * without solving the halting problem :-(
324 * XXX re-enable NOT_USED code sections below if you remove this test.
326 if (!superuser())
327 ereport(ERROR,
328 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
329 errmsg("must be superuser to create an operator class")));
331 /* Look up the datatype */
332 typeoid = typenameTypeId(NULL, stmt->datatype, NULL);
334 #ifdef NOT_USED
335 /* XXX this is unnecessary given the superuser check above */
336 /* Check we have ownership of the datatype */
337 if (!pg_type_ownercheck(typeoid, GetUserId()))
338 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
339 format_type_be(typeoid));
340 #endif
343 * Look up the containing operator family, or create one if FAMILY option
344 * was omitted and there's not a match already.
346 if (stmt->opfamilyname)
348 tup = OpFamilyCacheLookup(amoid, stmt->opfamilyname);
349 if (!HeapTupleIsValid(tup))
350 ereport(ERROR,
351 (errcode(ERRCODE_UNDEFINED_OBJECT),
352 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
353 NameListToString(stmt->opfamilyname), stmt->amname)));
354 opfamilyoid = HeapTupleGetOid(tup);
357 * XXX given the superuser check above, there's no need for an
358 * ownership check here
360 ReleaseSysCache(tup);
362 else
364 /* Lookup existing family of same name and namespace */
365 tup = SearchSysCache(OPFAMILYAMNAMENSP,
366 ObjectIdGetDatum(amoid),
367 PointerGetDatum(opcname),
368 ObjectIdGetDatum(namespaceoid),
370 if (HeapTupleIsValid(tup))
372 opfamilyoid = HeapTupleGetOid(tup);
375 * XXX given the superuser check above, there's no need for an
376 * ownership check here
378 ReleaseSysCache(tup);
380 else
383 * Create it ... again no need for more permissions ...
385 opfamilyoid = CreateOpFamily(stmt->amname, opcname,
386 namespaceoid, amoid);
390 operators = NIL;
391 procedures = NIL;
393 /* Storage datatype is optional */
394 storageoid = InvalidOid;
397 * Scan the "items" list to obtain additional info.
399 foreach(l, stmt->items)
401 CreateOpClassItem *item = lfirst(l);
402 Oid operOid;
403 Oid funcOid;
404 OpFamilyMember *member;
406 Assert(IsA(item, CreateOpClassItem));
407 switch (item->itemtype)
409 case OPCLASS_ITEM_OPERATOR:
410 if (item->number <= 0 || item->number > maxOpNumber)
411 ereport(ERROR,
412 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
413 errmsg("invalid operator number %d,"
414 " must be between 1 and %d",
415 item->number, maxOpNumber)));
416 if (item->args != NIL)
418 TypeName *typeName1 = (TypeName *) linitial(item->args);
419 TypeName *typeName2 = (TypeName *) lsecond(item->args);
421 operOid = LookupOperNameTypeNames(NULL, item->name,
422 typeName1, typeName2,
423 false, -1);
425 else
427 /* Default to binary op on input datatype */
428 operOid = LookupOperName(NULL, item->name,
429 typeoid, typeoid,
430 false, -1);
433 #ifdef NOT_USED
434 /* XXX this is unnecessary given the superuser check above */
435 /* Caller must own operator and its underlying function */
436 if (!pg_oper_ownercheck(operOid, GetUserId()))
437 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
438 get_opname(operOid));
439 funcOid = get_opcode(operOid);
440 if (!pg_proc_ownercheck(funcOid, GetUserId()))
441 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
442 get_func_name(funcOid));
443 #endif
445 /* Save the info */
446 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
447 member->object = operOid;
448 member->number = item->number;
449 assignOperTypes(member, amoid, typeoid);
450 addFamilyMember(&operators, member, false);
451 break;
452 case OPCLASS_ITEM_FUNCTION:
453 if (item->number <= 0 || item->number > maxProcNumber)
454 ereport(ERROR,
455 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
456 errmsg("invalid procedure number %d,"
457 " must be between 1 and %d",
458 item->number, maxProcNumber)));
459 funcOid = LookupFuncNameTypeNames(item->name, item->args,
460 false);
461 #ifdef NOT_USED
462 /* XXX this is unnecessary given the superuser check above */
463 /* Caller must own function */
464 if (!pg_proc_ownercheck(funcOid, GetUserId()))
465 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
466 get_func_name(funcOid));
467 #endif
469 /* Save the info */
470 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
471 member->object = funcOid;
472 member->number = item->number;
474 /* allow overriding of the function's actual arg types */
475 if (item->class_args)
476 processTypesSpec(item->class_args,
477 &member->lefttype, &member->righttype);
479 assignProcTypes(member, amoid, typeoid);
480 addFamilyMember(&procedures, member, true);
481 break;
482 case OPCLASS_ITEM_STORAGETYPE:
483 if (OidIsValid(storageoid))
484 ereport(ERROR,
485 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
486 errmsg("storage type specified more than once")));
487 storageoid = typenameTypeId(NULL, item->storedtype, NULL);
489 #ifdef NOT_USED
490 /* XXX this is unnecessary given the superuser check above */
491 /* Check we have ownership of the datatype */
492 if (!pg_type_ownercheck(storageoid, GetUserId()))
493 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
494 format_type_be(storageoid));
495 #endif
496 break;
497 default:
498 elog(ERROR, "unrecognized item type: %d", item->itemtype);
499 break;
504 * If storagetype is specified, make sure it's legal.
506 if (OidIsValid(storageoid))
508 /* Just drop the spec if same as column datatype */
509 if (storageoid == typeoid)
510 storageoid = InvalidOid;
511 else if (!amstorage)
512 ereport(ERROR,
513 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
514 errmsg("storage type cannot be different from data type for access method \"%s\"",
515 stmt->amname)));
518 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
521 * Make sure there is no existing opclass of this name (this is just to
522 * give a more friendly error message than "duplicate key").
524 if (SearchSysCacheExists(CLAAMNAMENSP,
525 ObjectIdGetDatum(amoid),
526 CStringGetDatum(opcname),
527 ObjectIdGetDatum(namespaceoid),
529 ereport(ERROR,
530 (errcode(ERRCODE_DUPLICATE_OBJECT),
531 errmsg("operator class \"%s\" for access method \"%s\" already exists",
532 opcname, stmt->amname)));
535 * If we are creating a default opclass, check there isn't one already.
536 * (Note we do not restrict this test to visible opclasses; this ensures
537 * that typcache.c can find unique solutions to its questions.)
539 if (stmt->isDefault)
541 ScanKeyData skey[1];
542 SysScanDesc scan;
544 ScanKeyInit(&skey[0],
545 Anum_pg_opclass_opcmethod,
546 BTEqualStrategyNumber, F_OIDEQ,
547 ObjectIdGetDatum(amoid));
549 scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
550 SnapshotNow, 1, skey);
552 while (HeapTupleIsValid(tup = systable_getnext(scan)))
554 Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
556 if (opclass->opcintype == typeoid && opclass->opcdefault)
557 ereport(ERROR,
558 (errcode(ERRCODE_DUPLICATE_OBJECT),
559 errmsg("could not make operator class \"%s\" be default for type %s",
560 opcname,
561 TypeNameToString(stmt->datatype)),
562 errdetail("Operator class \"%s\" already is the default.",
563 NameStr(opclass->opcname))));
566 systable_endscan(scan);
570 * Okay, let's create the pg_opclass entry.
572 memset(values, 0, sizeof(values));
573 memset(nulls, ' ', sizeof(nulls));
575 values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
576 namestrcpy(&opcName, opcname);
577 values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
578 values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
579 values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
580 values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
581 values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
582 values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
583 values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
585 tup = heap_formtuple(rel->rd_att, values, nulls);
587 opclassoid = simple_heap_insert(rel, tup);
589 CatalogUpdateIndexes(rel, tup);
591 heap_freetuple(tup);
594 * Now add tuples to pg_amop and pg_amproc tying in the operators and
595 * functions. Dependencies on them are inserted, too.
597 storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
598 opclassoid, operators, false);
599 storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
600 opclassoid, procedures, false);
603 * Create dependencies for the opclass proper. Note: we do not create a
604 * dependency link to the AM, because we don't currently support DROP
605 * ACCESS METHOD.
607 myself.classId = OperatorClassRelationId;
608 myself.objectId = opclassoid;
609 myself.objectSubId = 0;
611 /* dependency on namespace */
612 referenced.classId = NamespaceRelationId;
613 referenced.objectId = namespaceoid;
614 referenced.objectSubId = 0;
615 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
617 /* dependency on opfamily */
618 referenced.classId = OperatorFamilyRelationId;
619 referenced.objectId = opfamilyoid;
620 referenced.objectSubId = 0;
621 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
623 /* dependency on indexed datatype */
624 referenced.classId = TypeRelationId;
625 referenced.objectId = typeoid;
626 referenced.objectSubId = 0;
627 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
629 /* dependency on storage datatype */
630 if (OidIsValid(storageoid))
632 referenced.classId = TypeRelationId;
633 referenced.objectId = storageoid;
634 referenced.objectSubId = 0;
635 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
638 /* dependency on owner */
639 recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
641 heap_close(rel, RowExclusiveLock);
646 * DefineOpFamily
647 * Define a new index operator family.
649 void
650 DefineOpFamily(CreateOpFamilyStmt *stmt)
652 char *opfname; /* name of opfamily we're creating */
653 Oid amoid, /* our AM's oid */
654 namespaceoid, /* namespace to create opfamily in */
655 opfamilyoid; /* oid of opfamily we create */
656 Relation rel;
657 HeapTuple tup;
658 Datum values[Natts_pg_opfamily];
659 char nulls[Natts_pg_opfamily];
660 AclResult aclresult;
661 NameData opfName;
662 ObjectAddress myself,
663 referenced;
665 /* Convert list of names to a name and namespace */
666 namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
667 &opfname);
669 /* Check we have creation rights in target namespace */
670 aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
671 if (aclresult != ACLCHECK_OK)
672 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
673 get_namespace_name(namespaceoid));
675 /* Get necessary info about access method */
676 tup = SearchSysCache(AMNAME,
677 CStringGetDatum(stmt->amname),
678 0, 0, 0);
679 if (!HeapTupleIsValid(tup))
680 ereport(ERROR,
681 (errcode(ERRCODE_UNDEFINED_OBJECT),
682 errmsg("access method \"%s\" does not exist",
683 stmt->amname)));
685 amoid = HeapTupleGetOid(tup);
687 /* XXX Should we make any privilege check against the AM? */
689 ReleaseSysCache(tup);
692 * Currently, we require superuser privileges to create an opfamily. See
693 * comments in DefineOpClass.
695 * XXX re-enable NOT_USED code sections below if you remove this test.
697 if (!superuser())
698 ereport(ERROR,
699 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
700 errmsg("must be superuser to create an operator family")));
702 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
705 * Make sure there is no existing opfamily of this name (this is just to
706 * give a more friendly error message than "duplicate key").
708 if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
709 ObjectIdGetDatum(amoid),
710 CStringGetDatum(opfname),
711 ObjectIdGetDatum(namespaceoid),
713 ereport(ERROR,
714 (errcode(ERRCODE_DUPLICATE_OBJECT),
715 errmsg("operator family \"%s\" for access method \"%s\" already exists",
716 opfname, stmt->amname)));
719 * Okay, let's create the pg_opfamily entry.
721 memset(values, 0, sizeof(values));
722 memset(nulls, ' ', sizeof(nulls));
724 values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
725 namestrcpy(&opfName, opfname);
726 values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
727 values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
728 values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
730 tup = heap_formtuple(rel->rd_att, values, nulls);
732 opfamilyoid = simple_heap_insert(rel, tup);
734 CatalogUpdateIndexes(rel, tup);
736 heap_freetuple(tup);
739 * Create dependencies for the opfamily proper. Note: we do not create a
740 * dependency link to the AM, because we don't currently support DROP
741 * ACCESS METHOD.
743 myself.classId = OperatorFamilyRelationId;
744 myself.objectId = opfamilyoid;
745 myself.objectSubId = 0;
747 /* dependency on namespace */
748 referenced.classId = NamespaceRelationId;
749 referenced.objectId = namespaceoid;
750 referenced.objectSubId = 0;
751 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
753 /* dependency on owner */
754 recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
756 heap_close(rel, RowExclusiveLock);
761 * AlterOpFamily
762 * Add or remove operators/procedures within an existing operator family.
764 * Note: this implements only ALTER OPERATOR FAMILY ... ADD/DROP. Some
765 * other commands called ALTER OPERATOR FAMILY exist, but go through
766 * different code paths.
768 void
769 AlterOpFamily(AlterOpFamilyStmt *stmt)
771 Oid amoid, /* our AM's oid */
772 opfamilyoid; /* oid of opfamily */
773 int maxOpNumber, /* amstrategies value */
774 maxProcNumber; /* amsupport value */
775 HeapTuple tup;
776 Form_pg_am pg_am;
778 /* Get necessary info about access method */
779 tup = SearchSysCache(AMNAME,
780 CStringGetDatum(stmt->amname),
781 0, 0, 0);
782 if (!HeapTupleIsValid(tup))
783 ereport(ERROR,
784 (errcode(ERRCODE_UNDEFINED_OBJECT),
785 errmsg("access method \"%s\" does not exist",
786 stmt->amname)));
788 amoid = HeapTupleGetOid(tup);
789 pg_am = (Form_pg_am) GETSTRUCT(tup);
790 maxOpNumber = pg_am->amstrategies;
791 /* if amstrategies is zero, just enforce that op numbers fit in int16 */
792 if (maxOpNumber <= 0)
793 maxOpNumber = SHRT_MAX;
794 maxProcNumber = pg_am->amsupport;
796 /* XXX Should we make any privilege check against the AM? */
798 ReleaseSysCache(tup);
800 /* Look up the opfamily */
801 tup = OpFamilyCacheLookup(amoid, stmt->opfamilyname);
802 if (!HeapTupleIsValid(tup))
803 ereport(ERROR,
804 (errcode(ERRCODE_UNDEFINED_OBJECT),
805 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
806 NameListToString(stmt->opfamilyname), stmt->amname)));
807 opfamilyoid = HeapTupleGetOid(tup);
808 ReleaseSysCache(tup);
811 * Currently, we require superuser privileges to alter an opfamily.
813 * XXX re-enable NOT_USED code sections below if you remove this test.
815 if (!superuser())
816 ereport(ERROR,
817 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
818 errmsg("must be superuser to alter an operator family")));
821 * ADD and DROP cases need separate code from here on down.
823 if (stmt->isDrop)
824 AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
825 maxOpNumber, maxProcNumber,
826 stmt->items);
827 else
828 AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
829 maxOpNumber, maxProcNumber,
830 stmt->items);
834 * ADD part of ALTER OP FAMILY
836 static void
837 AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
838 int maxOpNumber, int maxProcNumber,
839 List *items)
841 List *operators; /* OpFamilyMember list for operators */
842 List *procedures; /* OpFamilyMember list for support procs */
843 ListCell *l;
845 operators = NIL;
846 procedures = NIL;
849 * Scan the "items" list to obtain additional info.
851 foreach(l, items)
853 CreateOpClassItem *item = lfirst(l);
854 Oid operOid;
855 Oid funcOid;
856 OpFamilyMember *member;
858 Assert(IsA(item, CreateOpClassItem));
859 switch (item->itemtype)
861 case OPCLASS_ITEM_OPERATOR:
862 if (item->number <= 0 || item->number > maxOpNumber)
863 ereport(ERROR,
864 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
865 errmsg("invalid operator number %d,"
866 " must be between 1 and %d",
867 item->number, maxOpNumber)));
868 if (item->args != NIL)
870 TypeName *typeName1 = (TypeName *) linitial(item->args);
871 TypeName *typeName2 = (TypeName *) lsecond(item->args);
873 operOid = LookupOperNameTypeNames(NULL, item->name,
874 typeName1, typeName2,
875 false, -1);
877 else
879 ereport(ERROR,
880 (errcode(ERRCODE_SYNTAX_ERROR),
881 errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
882 operOid = InvalidOid; /* keep compiler quiet */
885 #ifdef NOT_USED
886 /* XXX this is unnecessary given the superuser check above */
887 /* Caller must own operator and its underlying function */
888 if (!pg_oper_ownercheck(operOid, GetUserId()))
889 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
890 get_opname(operOid));
891 funcOid = get_opcode(operOid);
892 if (!pg_proc_ownercheck(funcOid, GetUserId()))
893 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
894 get_func_name(funcOid));
895 #endif
897 /* Save the info */
898 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
899 member->object = operOid;
900 member->number = item->number;
901 assignOperTypes(member, amoid, InvalidOid);
902 addFamilyMember(&operators, member, false);
903 break;
904 case OPCLASS_ITEM_FUNCTION:
905 if (item->number <= 0 || item->number > maxProcNumber)
906 ereport(ERROR,
907 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
908 errmsg("invalid procedure number %d,"
909 " must be between 1 and %d",
910 item->number, maxProcNumber)));
911 funcOid = LookupFuncNameTypeNames(item->name, item->args,
912 false);
913 #ifdef NOT_USED
914 /* XXX this is unnecessary given the superuser check above */
915 /* Caller must own function */
916 if (!pg_proc_ownercheck(funcOid, GetUserId()))
917 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
918 get_func_name(funcOid));
919 #endif
921 /* Save the info */
922 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
923 member->object = funcOid;
924 member->number = item->number;
926 /* allow overriding of the function's actual arg types */
927 if (item->class_args)
928 processTypesSpec(item->class_args,
929 &member->lefttype, &member->righttype);
931 assignProcTypes(member, amoid, InvalidOid);
932 addFamilyMember(&procedures, member, true);
933 break;
934 case OPCLASS_ITEM_STORAGETYPE:
935 ereport(ERROR,
936 (errcode(ERRCODE_SYNTAX_ERROR),
937 errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
938 break;
939 default:
940 elog(ERROR, "unrecognized item type: %d", item->itemtype);
941 break;
946 * Add tuples to pg_amop and pg_amproc tying in the operators and
947 * functions. Dependencies on them are inserted, too.
949 storeOperators(opfamilyname, amoid, opfamilyoid,
950 InvalidOid, operators, true);
951 storeProcedures(opfamilyname, amoid, opfamilyoid,
952 InvalidOid, procedures, true);
956 * DROP part of ALTER OP FAMILY
958 static void
959 AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
960 int maxOpNumber, int maxProcNumber,
961 List *items)
963 List *operators; /* OpFamilyMember list for operators */
964 List *procedures; /* OpFamilyMember list for support procs */
965 ListCell *l;
967 operators = NIL;
968 procedures = NIL;
971 * Scan the "items" list to obtain additional info.
973 foreach(l, items)
975 CreateOpClassItem *item = lfirst(l);
976 Oid lefttype,
977 righttype;
978 OpFamilyMember *member;
980 Assert(IsA(item, CreateOpClassItem));
981 switch (item->itemtype)
983 case OPCLASS_ITEM_OPERATOR:
984 if (item->number <= 0 || item->number > maxOpNumber)
985 ereport(ERROR,
986 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
987 errmsg("invalid operator number %d,"
988 " must be between 1 and %d",
989 item->number, maxOpNumber)));
990 processTypesSpec(item->args, &lefttype, &righttype);
991 /* Save the info */
992 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
993 member->number = item->number;
994 member->lefttype = lefttype;
995 member->righttype = righttype;
996 addFamilyMember(&operators, member, false);
997 break;
998 case OPCLASS_ITEM_FUNCTION:
999 if (item->number <= 0 || item->number > maxProcNumber)
1000 ereport(ERROR,
1001 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1002 errmsg("invalid procedure number %d,"
1003 " must be between 1 and %d",
1004 item->number, maxProcNumber)));
1005 processTypesSpec(item->args, &lefttype, &righttype);
1006 /* Save the info */
1007 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1008 member->number = item->number;
1009 member->lefttype = lefttype;
1010 member->righttype = righttype;
1011 addFamilyMember(&procedures, member, true);
1012 break;
1013 case OPCLASS_ITEM_STORAGETYPE:
1014 /* grammar prevents this from appearing */
1015 default:
1016 elog(ERROR, "unrecognized item type: %d", item->itemtype);
1017 break;
1022 * Remove tuples from pg_amop and pg_amproc.
1024 dropOperators(opfamilyname, amoid, opfamilyoid, operators);
1025 dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
1030 * Deal with explicit arg types used in ALTER ADD/DROP
1032 static void
1033 processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
1035 TypeName *typeName;
1037 Assert(args != NIL);
1039 typeName = (TypeName *) linitial(args);
1040 *lefttype = typenameTypeId(NULL, typeName, NULL);
1042 if (list_length(args) > 1)
1044 typeName = (TypeName *) lsecond(args);
1045 *righttype = typenameTypeId(NULL, typeName, NULL);
1047 else
1048 *righttype = *lefttype;
1050 if (list_length(args) > 2)
1051 ereport(ERROR,
1052 (errcode(ERRCODE_SYNTAX_ERROR),
1053 errmsg("one or two argument types must be specified")));
1058 * Determine the lefttype/righttype to assign to an operator,
1059 * and do any validity checking we can manage.
1061 static void
1062 assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
1064 Operator optup;
1065 Form_pg_operator opform;
1067 /* Fetch the operator definition */
1068 optup = SearchSysCache(OPEROID,
1069 ObjectIdGetDatum(member->object),
1070 0, 0, 0);
1071 if (optup == NULL)
1072 elog(ERROR, "cache lookup failed for operator %u", member->object);
1073 opform = (Form_pg_operator) GETSTRUCT(optup);
1076 * Opfamily operators must be binary ops returning boolean.
1078 if (opform->oprkind != 'b')
1079 ereport(ERROR,
1080 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1081 errmsg("index operators must be binary")));
1082 if (opform->oprresult != BOOLOID)
1083 ereport(ERROR,
1084 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1085 errmsg("index operators must return boolean")));
1088 * If lefttype/righttype isn't specified, use the operator's input types
1090 if (!OidIsValid(member->lefttype))
1091 member->lefttype = opform->oprleft;
1092 if (!OidIsValid(member->righttype))
1093 member->righttype = opform->oprright;
1095 ReleaseSysCache(optup);
1099 * Determine the lefttype/righttype to assign to a support procedure,
1100 * and do any validity checking we can manage.
1102 static void
1103 assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
1105 HeapTuple proctup;
1106 Form_pg_proc procform;
1108 /* Fetch the procedure definition */
1109 proctup = SearchSysCache(PROCOID,
1110 ObjectIdGetDatum(member->object),
1111 0, 0, 0);
1112 if (proctup == NULL)
1113 elog(ERROR, "cache lookup failed for function %u", member->object);
1114 procform = (Form_pg_proc) GETSTRUCT(proctup);
1117 * btree support procs must be 2-arg procs returning int4; hash support
1118 * procs must be 1-arg procs returning int4; otherwise we don't know.
1120 if (amoid == BTREE_AM_OID)
1122 if (procform->pronargs != 2)
1123 ereport(ERROR,
1124 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1125 errmsg("btree procedures must have two arguments")));
1126 if (procform->prorettype != INT4OID)
1127 ereport(ERROR,
1128 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1129 errmsg("btree procedures must return integer")));
1132 * If lefttype/righttype isn't specified, use the proc's input types
1134 if (!OidIsValid(member->lefttype))
1135 member->lefttype = procform->proargtypes.values[0];
1136 if (!OidIsValid(member->righttype))
1137 member->righttype = procform->proargtypes.values[1];
1139 else if (amoid == HASH_AM_OID)
1141 if (procform->pronargs != 1)
1142 ereport(ERROR,
1143 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1144 errmsg("hash procedures must have one argument")));
1145 if (procform->prorettype != INT4OID)
1146 ereport(ERROR,
1147 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1148 errmsg("hash procedures must return integer")));
1151 * If lefttype/righttype isn't specified, use the proc's input type
1153 if (!OidIsValid(member->lefttype))
1154 member->lefttype = procform->proargtypes.values[0];
1155 if (!OidIsValid(member->righttype))
1156 member->righttype = procform->proargtypes.values[0];
1158 else
1161 * The default for GiST and GIN in CREATE OPERATOR CLASS is to use the
1162 * class' opcintype as lefttype and righttype. In CREATE or ALTER
1163 * OPERATOR FAMILY, opcintype isn't available, so make the user
1164 * specify the types.
1166 if (!OidIsValid(member->lefttype))
1167 member->lefttype = typeoid;
1168 if (!OidIsValid(member->righttype))
1169 member->righttype = typeoid;
1170 if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1171 ereport(ERROR,
1172 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1173 errmsg("associated data types must be specified for index support procedure")));
1176 ReleaseSysCache(proctup);
1180 * Add a new family member to the appropriate list, after checking for
1181 * duplicated strategy or proc number.
1183 static void
1184 addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
1186 ListCell *l;
1188 foreach(l, *list)
1190 OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1192 if (old->number == member->number &&
1193 old->lefttype == member->lefttype &&
1194 old->righttype == member->righttype)
1196 if (isProc)
1197 ereport(ERROR,
1198 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1199 errmsg("procedure number %d for (%s,%s) appears more than once",
1200 member->number,
1201 format_type_be(member->lefttype),
1202 format_type_be(member->righttype))));
1203 else
1204 ereport(ERROR,
1205 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1206 errmsg("operator number %d for (%s,%s) appears more than once",
1207 member->number,
1208 format_type_be(member->lefttype),
1209 format_type_be(member->righttype))));
1212 *list = lappend(*list, member);
1216 * Dump the operators to pg_amop
1218 * We also make dependency entries in pg_depend for the opfamily entries.
1219 * If opclassoid is valid then make an INTERNAL dependency on that opclass,
1220 * else make an AUTO dependency on the opfamily.
1222 static void
1223 storeOperators(List *opfamilyname, Oid amoid,
1224 Oid opfamilyoid, Oid opclassoid,
1225 List *operators, bool isAdd)
1227 Relation rel;
1228 Datum values[Natts_pg_amop];
1229 char nulls[Natts_pg_amop];
1230 HeapTuple tup;
1231 Oid entryoid;
1232 ObjectAddress myself,
1233 referenced;
1234 ListCell *l;
1236 rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1238 foreach(l, operators)
1240 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1243 * If adding to an existing family, check for conflict with an
1244 * existing pg_amop entry (just to give a nicer error message)
1246 if (isAdd &&
1247 SearchSysCacheExists(AMOPSTRATEGY,
1248 ObjectIdGetDatum(opfamilyoid),
1249 ObjectIdGetDatum(op->lefttype),
1250 ObjectIdGetDatum(op->righttype),
1251 Int16GetDatum(op->number)))
1252 ereport(ERROR,
1253 (errcode(ERRCODE_DUPLICATE_OBJECT),
1254 errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1255 op->number,
1256 format_type_be(op->lefttype),
1257 format_type_be(op->righttype),
1258 NameListToString(opfamilyname))));
1260 /* Create the pg_amop entry */
1261 memset(values, 0, sizeof(values));
1262 memset(nulls, ' ', sizeof(nulls));
1264 values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1265 values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
1266 values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
1267 values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
1268 values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
1269 values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
1271 tup = heap_formtuple(rel->rd_att, values, nulls);
1273 entryoid = simple_heap_insert(rel, tup);
1275 CatalogUpdateIndexes(rel, tup);
1277 heap_freetuple(tup);
1279 /* Make its dependencies */
1280 myself.classId = AccessMethodOperatorRelationId;
1281 myself.objectId = entryoid;
1282 myself.objectSubId = 0;
1284 referenced.classId = OperatorRelationId;
1285 referenced.objectId = op->object;
1286 referenced.objectSubId = 0;
1288 if (OidIsValid(opclassoid))
1290 /* if contained in an opclass, use a NORMAL dep on operator */
1291 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1293 /* ... and an INTERNAL dep on the opclass */
1294 referenced.classId = OperatorClassRelationId;
1295 referenced.objectId = opclassoid;
1296 referenced.objectSubId = 0;
1297 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1299 else
1301 /* if "loose" in the opfamily, use a AUTO dep on operator */
1302 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1304 /* ... and an AUTO dep on the opfamily */
1305 referenced.classId = OperatorFamilyRelationId;
1306 referenced.objectId = opfamilyoid;
1307 referenced.objectSubId = 0;
1308 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1312 heap_close(rel, RowExclusiveLock);
1316 * Dump the procedures (support routines) to pg_amproc
1318 * We also make dependency entries in pg_depend for the opfamily entries.
1319 * If opclassoid is valid then make an INTERNAL dependency on that opclass,
1320 * else make an AUTO dependency on the opfamily.
1322 static void
1323 storeProcedures(List *opfamilyname, Oid amoid,
1324 Oid opfamilyoid, Oid opclassoid,
1325 List *procedures, bool isAdd)
1327 Relation rel;
1328 Datum values[Natts_pg_amproc];
1329 char nulls[Natts_pg_amproc];
1330 HeapTuple tup;
1331 Oid entryoid;
1332 ObjectAddress myself,
1333 referenced;
1334 ListCell *l;
1336 rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1338 foreach(l, procedures)
1340 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1343 * If adding to an existing family, check for conflict with an
1344 * existing pg_amproc entry (just to give a nicer error message)
1346 if (isAdd &&
1347 SearchSysCacheExists(AMPROCNUM,
1348 ObjectIdGetDatum(opfamilyoid),
1349 ObjectIdGetDatum(proc->lefttype),
1350 ObjectIdGetDatum(proc->righttype),
1351 Int16GetDatum(proc->number)))
1352 ereport(ERROR,
1353 (errcode(ERRCODE_DUPLICATE_OBJECT),
1354 errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1355 proc->number,
1356 format_type_be(proc->lefttype),
1357 format_type_be(proc->righttype),
1358 NameListToString(opfamilyname))));
1360 /* Create the pg_amproc entry */
1361 memset(values, 0, sizeof(values));
1362 memset(nulls, ' ', sizeof(nulls));
1364 values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1365 values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1366 values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1367 values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1368 values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1370 tup = heap_formtuple(rel->rd_att, values, nulls);
1372 entryoid = simple_heap_insert(rel, tup);
1374 CatalogUpdateIndexes(rel, tup);
1376 heap_freetuple(tup);
1378 /* Make its dependencies */
1379 myself.classId = AccessMethodProcedureRelationId;
1380 myself.objectId = entryoid;
1381 myself.objectSubId = 0;
1383 referenced.classId = ProcedureRelationId;
1384 referenced.objectId = proc->object;
1385 referenced.objectSubId = 0;
1387 if (OidIsValid(opclassoid))
1389 /* if contained in an opclass, use a NORMAL dep on procedure */
1390 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1392 /* ... and an INTERNAL dep on the opclass */
1393 referenced.classId = OperatorClassRelationId;
1394 referenced.objectId = opclassoid;
1395 referenced.objectSubId = 0;
1396 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1398 else
1400 /* if "loose" in the opfamily, use a AUTO dep on procedure */
1401 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1403 /* ... and an AUTO dep on the opfamily */
1404 referenced.classId = OperatorFamilyRelationId;
1405 referenced.objectId = opfamilyoid;
1406 referenced.objectSubId = 0;
1407 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1411 heap_close(rel, RowExclusiveLock);
1416 * Remove operator entries from an opfamily.
1418 * Note: this is only allowed for "loose" members of an opfamily, hence
1419 * behavior is always RESTRICT.
1421 static void
1422 dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1423 List *operators)
1425 ListCell *l;
1427 foreach(l, operators)
1429 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1430 Oid amopid;
1431 ObjectAddress object;
1433 amopid = GetSysCacheOid(AMOPSTRATEGY,
1434 ObjectIdGetDatum(opfamilyoid),
1435 ObjectIdGetDatum(op->lefttype),
1436 ObjectIdGetDatum(op->righttype),
1437 Int16GetDatum(op->number));
1438 if (!OidIsValid(amopid))
1439 ereport(ERROR,
1440 (errcode(ERRCODE_UNDEFINED_OBJECT),
1441 errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1442 op->number,
1443 format_type_be(op->lefttype),
1444 format_type_be(op->righttype),
1445 NameListToString(opfamilyname))));
1447 object.classId = AccessMethodOperatorRelationId;
1448 object.objectId = amopid;
1449 object.objectSubId = 0;
1451 performDeletion(&object, DROP_RESTRICT);
1456 * Remove procedure entries from an opfamily.
1458 * Note: this is only allowed for "loose" members of an opfamily, hence
1459 * behavior is always RESTRICT.
1461 static void
1462 dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1463 List *procedures)
1465 ListCell *l;
1467 foreach(l, procedures)
1469 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1470 Oid amprocid;
1471 ObjectAddress object;
1473 amprocid = GetSysCacheOid(AMPROCNUM,
1474 ObjectIdGetDatum(opfamilyoid),
1475 ObjectIdGetDatum(op->lefttype),
1476 ObjectIdGetDatum(op->righttype),
1477 Int16GetDatum(op->number));
1478 if (!OidIsValid(amprocid))
1479 ereport(ERROR,
1480 (errcode(ERRCODE_UNDEFINED_OBJECT),
1481 errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1482 op->number,
1483 format_type_be(op->lefttype),
1484 format_type_be(op->righttype),
1485 NameListToString(opfamilyname))));
1487 object.classId = AccessMethodProcedureRelationId;
1488 object.objectId = amprocid;
1489 object.objectSubId = 0;
1491 performDeletion(&object, DROP_RESTRICT);
1497 * RemoveOpClass
1498 * Deletes an opclass.
1500 void
1501 RemoveOpClass(RemoveOpClassStmt *stmt)
1503 Oid amID,
1504 opcID;
1505 HeapTuple tuple;
1506 ObjectAddress object;
1509 * Get the access method's OID.
1511 amID = GetSysCacheOid(AMNAME,
1512 CStringGetDatum(stmt->amname),
1513 0, 0, 0);
1514 if (!OidIsValid(amID))
1515 ereport(ERROR,
1516 (errcode(ERRCODE_UNDEFINED_OBJECT),
1517 errmsg("access method \"%s\" does not exist",
1518 stmt->amname)));
1521 * Look up the opclass.
1523 tuple = OpClassCacheLookup(amID, stmt->opclassname);
1524 if (!HeapTupleIsValid(tuple))
1526 if (!stmt->missing_ok)
1527 ereport(ERROR,
1528 (errcode(ERRCODE_UNDEFINED_OBJECT),
1529 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1530 NameListToString(stmt->opclassname), stmt->amname)));
1531 else
1532 ereport(NOTICE,
1533 (errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1534 NameListToString(stmt->opclassname), stmt->amname)));
1535 return;
1538 opcID = HeapTupleGetOid(tuple);
1540 /* Permission check: must own opclass or its namespace */
1541 if (!pg_opclass_ownercheck(opcID, GetUserId()) &&
1542 !pg_namespace_ownercheck(((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace,
1543 GetUserId()))
1544 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
1545 NameListToString(stmt->opclassname));
1547 ReleaseSysCache(tuple);
1550 * Do the deletion
1552 object.classId = OperatorClassRelationId;
1553 object.objectId = opcID;
1554 object.objectSubId = 0;
1556 performDeletion(&object, stmt->behavior);
1560 * RemoveOpFamily
1561 * Deletes an opfamily.
1563 void
1564 RemoveOpFamily(RemoveOpFamilyStmt *stmt)
1566 Oid amID,
1567 opfID;
1568 HeapTuple tuple;
1569 ObjectAddress object;
1572 * Get the access method's OID.
1574 amID = GetSysCacheOid(AMNAME,
1575 CStringGetDatum(stmt->amname),
1576 0, 0, 0);
1577 if (!OidIsValid(amID))
1578 ereport(ERROR,
1579 (errcode(ERRCODE_UNDEFINED_OBJECT),
1580 errmsg("access method \"%s\" does not exist",
1581 stmt->amname)));
1584 * Look up the opfamily.
1586 tuple = OpFamilyCacheLookup(amID, stmt->opfamilyname);
1587 if (!HeapTupleIsValid(tuple))
1589 if (!stmt->missing_ok)
1590 ereport(ERROR,
1591 (errcode(ERRCODE_UNDEFINED_OBJECT),
1592 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
1593 NameListToString(stmt->opfamilyname), stmt->amname)));
1594 else
1595 ereport(NOTICE,
1596 (errmsg("operator family \"%s\" does not exist for access method \"%s\"",
1597 NameListToString(stmt->opfamilyname), stmt->amname)));
1598 return;
1601 opfID = HeapTupleGetOid(tuple);
1603 /* Permission check: must own opfamily or its namespace */
1604 if (!pg_opfamily_ownercheck(opfID, GetUserId()) &&
1605 !pg_namespace_ownercheck(((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace,
1606 GetUserId()))
1607 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
1608 NameListToString(stmt->opfamilyname));
1610 ReleaseSysCache(tuple);
1613 * Do the deletion
1615 object.classId = OperatorFamilyRelationId;
1616 object.objectId = opfID;
1617 object.objectSubId = 0;
1619 performDeletion(&object, stmt->behavior);
1624 * Deletion subroutines for use by dependency.c.
1626 void
1627 RemoveOpFamilyById(Oid opfamilyOid)
1629 Relation rel;
1630 HeapTuple tup;
1632 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
1634 tup = SearchSysCache(OPFAMILYOID,
1635 ObjectIdGetDatum(opfamilyOid),
1636 0, 0, 0);
1637 if (!HeapTupleIsValid(tup)) /* should not happen */
1638 elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1640 simple_heap_delete(rel, &tup->t_self);
1642 ReleaseSysCache(tup);
1644 heap_close(rel, RowExclusiveLock);
1647 void
1648 RemoveOpClassById(Oid opclassOid)
1650 Relation rel;
1651 HeapTuple tup;
1653 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1655 tup = SearchSysCache(CLAOID,
1656 ObjectIdGetDatum(opclassOid),
1657 0, 0, 0);
1658 if (!HeapTupleIsValid(tup)) /* should not happen */
1659 elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1661 simple_heap_delete(rel, &tup->t_self);
1663 ReleaseSysCache(tup);
1665 heap_close(rel, RowExclusiveLock);
1668 void
1669 RemoveAmOpEntryById(Oid entryOid)
1671 Relation rel;
1672 HeapTuple tup;
1673 ScanKeyData skey[1];
1674 SysScanDesc scan;
1676 ScanKeyInit(&skey[0],
1677 ObjectIdAttributeNumber,
1678 BTEqualStrategyNumber, F_OIDEQ,
1679 ObjectIdGetDatum(entryOid));
1681 rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1683 scan = systable_beginscan(rel, AccessMethodOperatorOidIndexId, true,
1684 SnapshotNow, 1, skey);
1686 /* we expect exactly one match */
1687 tup = systable_getnext(scan);
1688 if (!HeapTupleIsValid(tup))
1689 elog(ERROR, "could not find tuple for amop entry %u", entryOid);
1691 simple_heap_delete(rel, &tup->t_self);
1693 systable_endscan(scan);
1694 heap_close(rel, RowExclusiveLock);
1697 void
1698 RemoveAmProcEntryById(Oid entryOid)
1700 Relation rel;
1701 HeapTuple tup;
1702 ScanKeyData skey[1];
1703 SysScanDesc scan;
1705 ScanKeyInit(&skey[0],
1706 ObjectIdAttributeNumber,
1707 BTEqualStrategyNumber, F_OIDEQ,
1708 ObjectIdGetDatum(entryOid));
1710 rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1712 scan = systable_beginscan(rel, AccessMethodProcedureOidIndexId, true,
1713 SnapshotNow, 1, skey);
1715 /* we expect exactly one match */
1716 tup = systable_getnext(scan);
1717 if (!HeapTupleIsValid(tup))
1718 elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
1720 simple_heap_delete(rel, &tup->t_self);
1722 systable_endscan(scan);
1723 heap_close(rel, RowExclusiveLock);
1728 * Rename opclass
1730 void
1731 RenameOpClass(List *name, const char *access_method, const char *newname)
1733 Oid opcOid;
1734 Oid amOid;
1735 Oid namespaceOid;
1736 char *schemaname;
1737 char *opcname;
1738 HeapTuple tup;
1739 Relation rel;
1740 AclResult aclresult;
1742 amOid = GetSysCacheOid(AMNAME,
1743 CStringGetDatum(access_method),
1744 0, 0, 0);
1745 if (!OidIsValid(amOid))
1746 ereport(ERROR,
1747 (errcode(ERRCODE_UNDEFINED_OBJECT),
1748 errmsg("access method \"%s\" does not exist",
1749 access_method)));
1751 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1754 * Look up the opclass
1756 DeconstructQualifiedName(name, &schemaname, &opcname);
1758 if (schemaname)
1760 namespaceOid = LookupExplicitNamespace(schemaname);
1762 tup = SearchSysCacheCopy(CLAAMNAMENSP,
1763 ObjectIdGetDatum(amOid),
1764 PointerGetDatum(opcname),
1765 ObjectIdGetDatum(namespaceOid),
1767 if (!HeapTupleIsValid(tup))
1768 ereport(ERROR,
1769 (errcode(ERRCODE_UNDEFINED_OBJECT),
1770 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1771 opcname, access_method)));
1773 opcOid = HeapTupleGetOid(tup);
1775 else
1777 opcOid = OpclassnameGetOpcid(amOid, opcname);
1778 if (!OidIsValid(opcOid))
1779 ereport(ERROR,
1780 (errcode(ERRCODE_UNDEFINED_OBJECT),
1781 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1782 opcname, access_method)));
1784 tup = SearchSysCacheCopy(CLAOID,
1785 ObjectIdGetDatum(opcOid),
1786 0, 0, 0);
1787 if (!HeapTupleIsValid(tup)) /* should not happen */
1788 elog(ERROR, "cache lookup failed for opclass %u", opcOid);
1790 namespaceOid = ((Form_pg_opclass) GETSTRUCT(tup))->opcnamespace;
1793 /* make sure the new name doesn't exist */
1794 if (SearchSysCacheExists(CLAAMNAMENSP,
1795 ObjectIdGetDatum(amOid),
1796 CStringGetDatum(newname),
1797 ObjectIdGetDatum(namespaceOid),
1800 ereport(ERROR,
1801 (errcode(ERRCODE_DUPLICATE_OBJECT),
1802 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1803 newname, access_method,
1804 get_namespace_name(namespaceOid))));
1807 /* must be owner */
1808 if (!pg_opclass_ownercheck(opcOid, GetUserId()))
1809 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
1810 NameListToString(name));
1812 /* must have CREATE privilege on namespace */
1813 aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
1814 if (aclresult != ACLCHECK_OK)
1815 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1816 get_namespace_name(namespaceOid));
1818 /* rename */
1819 namestrcpy(&(((Form_pg_opclass) GETSTRUCT(tup))->opcname), newname);
1820 simple_heap_update(rel, &tup->t_self, tup);
1821 CatalogUpdateIndexes(rel, tup);
1823 heap_close(rel, NoLock);
1824 heap_freetuple(tup);
1828 * Rename opfamily
1830 void
1831 RenameOpFamily(List *name, const char *access_method, const char *newname)
1833 Oid opfOid;
1834 Oid amOid;
1835 Oid namespaceOid;
1836 char *schemaname;
1837 char *opfname;
1838 HeapTuple tup;
1839 Relation rel;
1840 AclResult aclresult;
1842 amOid = GetSysCacheOid(AMNAME,
1843 CStringGetDatum(access_method),
1844 0, 0, 0);
1845 if (!OidIsValid(amOid))
1846 ereport(ERROR,
1847 (errcode(ERRCODE_UNDEFINED_OBJECT),
1848 errmsg("access method \"%s\" does not exist",
1849 access_method)));
1851 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
1854 * Look up the opfamily
1856 DeconstructQualifiedName(name, &schemaname, &opfname);
1858 if (schemaname)
1860 namespaceOid = LookupExplicitNamespace(schemaname);
1862 tup = SearchSysCacheCopy(OPFAMILYAMNAMENSP,
1863 ObjectIdGetDatum(amOid),
1864 PointerGetDatum(opfname),
1865 ObjectIdGetDatum(namespaceOid),
1867 if (!HeapTupleIsValid(tup))
1868 ereport(ERROR,
1869 (errcode(ERRCODE_UNDEFINED_OBJECT),
1870 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
1871 opfname, access_method)));
1873 opfOid = HeapTupleGetOid(tup);
1875 else
1877 opfOid = OpfamilynameGetOpfid(amOid, opfname);
1878 if (!OidIsValid(opfOid))
1879 ereport(ERROR,
1880 (errcode(ERRCODE_UNDEFINED_OBJECT),
1881 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
1882 opfname, access_method)));
1884 tup = SearchSysCacheCopy(OPFAMILYOID,
1885 ObjectIdGetDatum(opfOid),
1886 0, 0, 0);
1887 if (!HeapTupleIsValid(tup)) /* should not happen */
1888 elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
1890 namespaceOid = ((Form_pg_opfamily) GETSTRUCT(tup))->opfnamespace;
1893 /* make sure the new name doesn't exist */
1894 if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
1895 ObjectIdGetDatum(amOid),
1896 CStringGetDatum(newname),
1897 ObjectIdGetDatum(namespaceOid),
1900 ereport(ERROR,
1901 (errcode(ERRCODE_DUPLICATE_OBJECT),
1902 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1903 newname, access_method,
1904 get_namespace_name(namespaceOid))));
1907 /* must be owner */
1908 if (!pg_opfamily_ownercheck(opfOid, GetUserId()))
1909 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
1910 NameListToString(name));
1912 /* must have CREATE privilege on namespace */
1913 aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
1914 if (aclresult != ACLCHECK_OK)
1915 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1916 get_namespace_name(namespaceOid));
1918 /* rename */
1919 namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname);
1920 simple_heap_update(rel, &tup->t_self, tup);
1921 CatalogUpdateIndexes(rel, tup);
1923 heap_close(rel, NoLock);
1924 heap_freetuple(tup);
1928 * Change opclass owner by name
1930 void
1931 AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
1933 Oid amOid;
1934 Relation rel;
1935 HeapTuple tup;
1936 char *opcname;
1937 char *schemaname;
1939 amOid = GetSysCacheOid(AMNAME,
1940 CStringGetDatum(access_method),
1941 0, 0, 0);
1942 if (!OidIsValid(amOid))
1943 ereport(ERROR,
1944 (errcode(ERRCODE_UNDEFINED_OBJECT),
1945 errmsg("access method \"%s\" does not exist",
1946 access_method)));
1948 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
1951 * Look up the opclass
1953 DeconstructQualifiedName(name, &schemaname, &opcname);
1955 if (schemaname)
1957 Oid namespaceOid;
1959 namespaceOid = LookupExplicitNamespace(schemaname);
1961 tup = SearchSysCacheCopy(CLAAMNAMENSP,
1962 ObjectIdGetDatum(amOid),
1963 PointerGetDatum(opcname),
1964 ObjectIdGetDatum(namespaceOid),
1966 if (!HeapTupleIsValid(tup))
1967 ereport(ERROR,
1968 (errcode(ERRCODE_UNDEFINED_OBJECT),
1969 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1970 opcname, access_method)));
1972 else
1974 Oid opcOid;
1976 opcOid = OpclassnameGetOpcid(amOid, opcname);
1977 if (!OidIsValid(opcOid))
1978 ereport(ERROR,
1979 (errcode(ERRCODE_UNDEFINED_OBJECT),
1980 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1981 opcname, access_method)));
1983 tup = SearchSysCacheCopy(CLAOID,
1984 ObjectIdGetDatum(opcOid),
1985 0, 0, 0);
1986 if (!HeapTupleIsValid(tup)) /* should not happen */
1987 elog(ERROR, "cache lookup failed for opclass %u", opcOid);
1990 AlterOpClassOwner_internal(rel, tup, newOwnerId);
1992 heap_freetuple(tup);
1993 heap_close(rel, NoLock);
1997 * The first parameter is pg_opclass, opened and suitably locked. The second
1998 * parameter is a copy of the tuple from pg_opclass we want to modify.
2000 static void
2001 AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
2003 Oid namespaceOid;
2004 AclResult aclresult;
2005 Form_pg_opclass opcForm;
2007 Assert(tup->t_tableOid == OperatorClassRelationId);
2008 Assert(RelationGetRelid(rel) == OperatorClassRelationId);
2010 opcForm = (Form_pg_opclass) GETSTRUCT(tup);
2012 namespaceOid = opcForm->opcnamespace;
2015 * If the new owner is the same as the existing owner, consider the
2016 * command to have succeeded. This is for dump restoration purposes.
2018 if (opcForm->opcowner != newOwnerId)
2020 /* Superusers can always do it */
2021 if (!superuser())
2023 /* Otherwise, must be owner of the existing object */
2024 if (!pg_opclass_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2025 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
2026 NameStr(opcForm->opcname));
2028 /* Must be able to become new owner */
2029 check_is_member_of_role(GetUserId(), newOwnerId);
2031 /* New owner must have CREATE privilege on namespace */
2032 aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
2033 ACL_CREATE);
2034 if (aclresult != ACLCHECK_OK)
2035 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2036 get_namespace_name(namespaceOid));
2040 * Modify the owner --- okay to scribble on tup because it's a copy
2042 opcForm->opcowner = newOwnerId;
2044 simple_heap_update(rel, &tup->t_self, tup);
2046 CatalogUpdateIndexes(rel, tup);
2048 /* Update owner dependency reference */
2049 changeDependencyOnOwner(OperatorClassRelationId, HeapTupleGetOid(tup),
2050 newOwnerId);
2055 * Change opfamily owner by name
2057 void
2058 AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId)
2060 Oid amOid;
2061 Relation rel;
2062 HeapTuple tup;
2063 char *opfname;
2064 char *schemaname;
2066 amOid = GetSysCacheOid(AMNAME,
2067 CStringGetDatum(access_method),
2068 0, 0, 0);
2069 if (!OidIsValid(amOid))
2070 ereport(ERROR,
2071 (errcode(ERRCODE_UNDEFINED_OBJECT),
2072 errmsg("access method \"%s\" does not exist",
2073 access_method)));
2075 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
2078 * Look up the opfamily
2080 DeconstructQualifiedName(name, &schemaname, &opfname);
2082 if (schemaname)
2084 Oid namespaceOid;
2086 namespaceOid = LookupExplicitNamespace(schemaname);
2088 tup = SearchSysCacheCopy(OPFAMILYAMNAMENSP,
2089 ObjectIdGetDatum(amOid),
2090 PointerGetDatum(opfname),
2091 ObjectIdGetDatum(namespaceOid),
2093 if (!HeapTupleIsValid(tup))
2094 ereport(ERROR,
2095 (errcode(ERRCODE_UNDEFINED_OBJECT),
2096 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
2097 opfname, access_method)));
2099 else
2101 Oid opfOid;
2103 opfOid = OpfamilynameGetOpfid(amOid, opfname);
2104 if (!OidIsValid(opfOid))
2105 ereport(ERROR,
2106 (errcode(ERRCODE_UNDEFINED_OBJECT),
2107 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
2108 opfname, access_method)));
2110 tup = SearchSysCacheCopy(OPFAMILYOID,
2111 ObjectIdGetDatum(opfOid),
2112 0, 0, 0);
2113 if (!HeapTupleIsValid(tup)) /* should not happen */
2114 elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
2117 AlterOpFamilyOwner_internal(rel, tup, newOwnerId);
2119 heap_freetuple(tup);
2120 heap_close(rel, NoLock);
2124 * The first parameter is pg_opfamily, opened and suitably locked. The second
2125 * parameter is a copy of the tuple from pg_opfamily we want to modify.
2127 static void
2128 AlterOpFamilyOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
2130 Oid namespaceOid;
2131 AclResult aclresult;
2132 Form_pg_opfamily opfForm;
2134 Assert(tup->t_tableOid == OperatorFamilyRelationId);
2135 Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
2137 opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
2139 namespaceOid = opfForm->opfnamespace;
2142 * If the new owner is the same as the existing owner, consider the
2143 * command to have succeeded. This is for dump restoration purposes.
2145 if (opfForm->opfowner != newOwnerId)
2147 /* Superusers can always do it */
2148 if (!superuser())
2150 /* Otherwise, must be owner of the existing object */
2151 if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2152 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
2153 NameStr(opfForm->opfname));
2155 /* Must be able to become new owner */
2156 check_is_member_of_role(GetUserId(), newOwnerId);
2158 /* New owner must have CREATE privilege on namespace */
2159 aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
2160 ACL_CREATE);
2161 if (aclresult != ACLCHECK_OK)
2162 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2163 get_namespace_name(namespaceOid));
2167 * Modify the owner --- okay to scribble on tup because it's a copy
2169 opfForm->opfowner = newOwnerId;
2171 simple_heap_update(rel, &tup->t_self, tup);
2173 CatalogUpdateIndexes(rel, tup);
2175 /* Update owner dependency reference */
2176 changeDependencyOnOwner(OperatorFamilyRelationId, HeapTupleGetOid(tup),
2177 newOwnerId);