1 /*-------------------------------------------------------------------------
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
14 *-------------------------------------------------------------------------
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.
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 */
60 static void AlterOpFamilyAdd(List
*opfamilyname
, Oid amoid
, Oid opfamilyoid
,
61 int maxOpNumber
, int maxProcNumber
,
63 static void AlterOpFamilyDrop(List
*opfamilyname
, Oid amoid
, Oid opfamilyoid
,
64 int maxOpNumber
, int maxProcNumber
,
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
,
78 static void dropProcedures(List
*opfamilyname
, Oid amoid
, Oid opfamilyoid
,
80 static void AlterOpClassOwner_internal(Relation rel
, HeapTuple tuple
,
82 static void AlterOpFamilyOwner_internal(Relation rel
, HeapTuple tuple
,
88 * Look up an existing opfamily by name.
90 * Returns a syscache tuple reference, or NULL if not found.
93 OpFamilyCacheLookup(Oid amID
, List
*opfamilyname
)
98 /* deconstruct the name list */
99 DeconstructQualifiedName(opfamilyname
, &schemaname
, &opfname
);
103 /* Look in specific schema only */
106 namespaceId
= LookupExplicitNamespace(schemaname
);
107 return SearchSysCache(OPFAMILYAMNAMENSP
,
108 ObjectIdGetDatum(amID
),
109 PointerGetDatum(opfname
),
110 ObjectIdGetDatum(namespaceId
),
115 /* Unqualified opfamily name, so search the search path */
116 Oid opfID
= OpfamilynameGetOpfid(amID
, opfname
);
118 if (!OidIsValid(opfID
))
120 return SearchSysCache(OPFAMILYOID
,
121 ObjectIdGetDatum(opfID
),
128 * Look up an existing opclass by name.
130 * Returns a syscache tuple reference, or NULL if not found.
133 OpClassCacheLookup(Oid amID
, List
*opclassname
)
138 /* deconstruct the name list */
139 DeconstructQualifiedName(opclassname
, &schemaname
, &opcname
);
143 /* Look in specific schema only */
146 namespaceId
= LookupExplicitNamespace(schemaname
);
147 return SearchSysCache(CLAAMNAMENSP
,
148 ObjectIdGetDatum(amID
),
149 PointerGetDatum(opcname
),
150 ObjectIdGetDatum(namespaceId
),
155 /* Unqualified opclass name, so search the search path */
156 Oid opcID
= OpclassnameGetOpcid(amID
, opcname
);
158 if (!OidIsValid(opcID
))
160 return SearchSysCache(CLAOID
,
161 ObjectIdGetDatum(opcID
),
168 * Internal routine to make the catalog entry for a new operator family.
170 * Caller must have done permissions checks etc. already.
173 CreateOpFamily(char *amname
, char *opfname
, Oid namespaceoid
, Oid amoid
)
178 Datum values
[Natts_pg_opfamily
];
179 char nulls
[Natts_pg_opfamily
];
181 ObjectAddress myself
,
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
),
196 (errcode(ERRCODE_DUPLICATE_OBJECT
),
197 errmsg("operator family \"%s\" for access method \"%s\" already exists",
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
);
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
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
);
245 * Define a new index operator class.
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 */
266 Datum values
[Natts_pg_opclass
];
267 char nulls
[Natts_pg_opclass
];
270 ObjectAddress myself
,
273 /* Convert list of names to a name and namespace */
274 namespaceoid
= QualifiedNameGetCreationNamespace(stmt
->opclassname
,
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
),
287 if (!HeapTupleIsValid(tup
))
289 (errcode(ERRCODE_UNDEFINED_OBJECT
),
290 errmsg("access method \"%s\" does not exist",
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.
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
);
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
));
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
))
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
);
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
);
383 * Create it ... again no need for more permissions ...
385 opfamilyoid
= CreateOpFamily(stmt
->amname
, opcname
,
386 namespaceoid
, amoid
);
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
);
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
)
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
,
427 /* Default to binary op on input datatype */
428 operOid
= LookupOperName(NULL
, item
->name
,
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
));
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);
452 case OPCLASS_ITEM_FUNCTION
:
453 if (item
->number
<= 0 || item
->number
> maxProcNumber
)
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
,
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
));
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);
482 case OPCLASS_ITEM_STORAGETYPE
:
483 if (OidIsValid(storageoid
))
485 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
486 errmsg("storage type specified more than once")));
487 storageoid
= typenameTypeId(NULL
, item
->storedtype
, NULL
);
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
));
498 elog(ERROR
, "unrecognized item type: %d", item
->itemtype
);
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
;
513 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
514 errmsg("storage type cannot be different from data type for access method \"%s\"",
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
),
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.)
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
)
558 (errcode(ERRCODE_DUPLICATE_OBJECT
),
559 errmsg("could not make operator class \"%s\" be default for type %s",
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
);
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
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
);
647 * Define a new index operator family.
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 */
658 Datum values
[Natts_pg_opfamily
];
659 char nulls
[Natts_pg_opfamily
];
662 ObjectAddress myself
,
665 /* Convert list of names to a name and namespace */
666 namespaceoid
= QualifiedNameGetCreationNamespace(stmt
->opfamilyname
,
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
),
679 if (!HeapTupleIsValid(tup
))
681 (errcode(ERRCODE_UNDEFINED_OBJECT
),
682 errmsg("access method \"%s\" does not exist",
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.
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
),
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
);
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
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
);
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.
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 */
778 /* Get necessary info about access method */
779 tup
= SearchSysCache(AMNAME
,
780 CStringGetDatum(stmt
->amname
),
782 if (!HeapTupleIsValid(tup
))
784 (errcode(ERRCODE_UNDEFINED_OBJECT
),
785 errmsg("access method \"%s\" does not exist",
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
))
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.
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.
824 AlterOpFamilyDrop(stmt
->opfamilyname
, amoid
, opfamilyoid
,
825 maxOpNumber
, maxProcNumber
,
828 AlterOpFamilyAdd(stmt
->opfamilyname
, amoid
, opfamilyoid
,
829 maxOpNumber
, maxProcNumber
,
834 * ADD part of ALTER OP FAMILY
837 AlterOpFamilyAdd(List
*opfamilyname
, Oid amoid
, Oid opfamilyoid
,
838 int maxOpNumber
, int maxProcNumber
,
841 List
*operators
; /* OpFamilyMember list for operators */
842 List
*procedures
; /* OpFamilyMember list for support procs */
849 * Scan the "items" list to obtain additional info.
853 CreateOpClassItem
*item
= lfirst(l
);
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
)
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
,
880 (errcode(ERRCODE_SYNTAX_ERROR
),
881 errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
882 operOid
= InvalidOid
; /* keep compiler quiet */
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
));
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);
904 case OPCLASS_ITEM_FUNCTION
:
905 if (item
->number
<= 0 || item
->number
> maxProcNumber
)
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
,
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
));
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);
934 case OPCLASS_ITEM_STORAGETYPE
:
936 (errcode(ERRCODE_SYNTAX_ERROR
),
937 errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
940 elog(ERROR
, "unrecognized item type: %d", item
->itemtype
);
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
959 AlterOpFamilyDrop(List
*opfamilyname
, Oid amoid
, Oid opfamilyoid
,
960 int maxOpNumber
, int maxProcNumber
,
963 List
*operators
; /* OpFamilyMember list for operators */
964 List
*procedures
; /* OpFamilyMember list for support procs */
971 * Scan the "items" list to obtain additional info.
975 CreateOpClassItem
*item
= lfirst(l
);
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
)
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
);
992 member
= (OpFamilyMember
*) palloc0(sizeof(OpFamilyMember
));
993 member
->number
= item
->number
;
994 member
->lefttype
= lefttype
;
995 member
->righttype
= righttype
;
996 addFamilyMember(&operators
, member
, false);
998 case OPCLASS_ITEM_FUNCTION
:
999 if (item
->number
<= 0 || item
->number
> maxProcNumber
)
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
);
1007 member
= (OpFamilyMember
*) palloc0(sizeof(OpFamilyMember
));
1008 member
->number
= item
->number
;
1009 member
->lefttype
= lefttype
;
1010 member
->righttype
= righttype
;
1011 addFamilyMember(&procedures
, member
, true);
1013 case OPCLASS_ITEM_STORAGETYPE
:
1014 /* grammar prevents this from appearing */
1016 elog(ERROR
, "unrecognized item type: %d", item
->itemtype
);
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
1033 processTypesSpec(List
*args
, Oid
*lefttype
, Oid
*righttype
)
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
);
1048 *righttype
= *lefttype
;
1050 if (list_length(args
) > 2)
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.
1062 assignOperTypes(OpFamilyMember
*member
, Oid amoid
, Oid typeoid
)
1065 Form_pg_operator opform
;
1067 /* Fetch the operator definition */
1068 optup
= SearchSysCache(OPEROID
,
1069 ObjectIdGetDatum(member
->object
),
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')
1080 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1081 errmsg("index operators must be binary")));
1082 if (opform
->oprresult
!= BOOLOID
)
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.
1103 assignProcTypes(OpFamilyMember
*member
, Oid amoid
, Oid typeoid
)
1106 Form_pg_proc procform
;
1108 /* Fetch the procedure definition */
1109 proctup
= SearchSysCache(PROCOID
,
1110 ObjectIdGetDatum(member
->object
),
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)
1124 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1125 errmsg("btree procedures must have two arguments")));
1126 if (procform
->prorettype
!= INT4OID
)
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)
1143 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1144 errmsg("hash procedures must have one argument")));
1145 if (procform
->prorettype
!= INT4OID
)
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];
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
))
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.
1184 addFamilyMember(List
**list
, OpFamilyMember
*member
, bool isProc
)
1190 OpFamilyMember
*old
= (OpFamilyMember
*) lfirst(l
);
1192 if (old
->number
== member
->number
&&
1193 old
->lefttype
== member
->lefttype
&&
1194 old
->righttype
== member
->righttype
)
1198 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1199 errmsg("procedure number %d for (%s,%s) appears more than once",
1201 format_type_be(member
->lefttype
),
1202 format_type_be(member
->righttype
))));
1205 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION
),
1206 errmsg("operator number %d for (%s,%s) appears more than once",
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.
1223 storeOperators(List
*opfamilyname
, Oid amoid
,
1224 Oid opfamilyoid
, Oid opclassoid
,
1225 List
*operators
, bool isAdd
)
1228 Datum values
[Natts_pg_amop
];
1229 char nulls
[Natts_pg_amop
];
1232 ObjectAddress myself
,
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)
1247 SearchSysCacheExists(AMOPSTRATEGY
,
1248 ObjectIdGetDatum(opfamilyoid
),
1249 ObjectIdGetDatum(op
->lefttype
),
1250 ObjectIdGetDatum(op
->righttype
),
1251 Int16GetDatum(op
->number
)))
1253 (errcode(ERRCODE_DUPLICATE_OBJECT
),
1254 errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
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
);
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.
1323 storeProcedures(List
*opfamilyname
, Oid amoid
,
1324 Oid opfamilyoid
, Oid opclassoid
,
1325 List
*procedures
, bool isAdd
)
1328 Datum values
[Natts_pg_amproc
];
1329 char nulls
[Natts_pg_amproc
];
1332 ObjectAddress myself
,
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)
1347 SearchSysCacheExists(AMPROCNUM
,
1348 ObjectIdGetDatum(opfamilyoid
),
1349 ObjectIdGetDatum(proc
->lefttype
),
1350 ObjectIdGetDatum(proc
->righttype
),
1351 Int16GetDatum(proc
->number
)))
1353 (errcode(ERRCODE_DUPLICATE_OBJECT
),
1354 errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
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
);
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.
1422 dropOperators(List
*opfamilyname
, Oid amoid
, Oid opfamilyoid
,
1427 foreach(l
, operators
)
1429 OpFamilyMember
*op
= (OpFamilyMember
*) lfirst(l
);
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
))
1440 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1441 errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
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.
1462 dropProcedures(List
*opfamilyname
, Oid amoid
, Oid opfamilyoid
,
1467 foreach(l
, procedures
)
1469 OpFamilyMember
*op
= (OpFamilyMember
*) lfirst(l
);
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
))
1480 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1481 errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
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
);
1498 * Deletes an opclass.
1501 RemoveOpClass(RemoveOpClassStmt
*stmt
)
1506 ObjectAddress object
;
1509 * Get the access method's OID.
1511 amID
= GetSysCacheOid(AMNAME
,
1512 CStringGetDatum(stmt
->amname
),
1514 if (!OidIsValid(amID
))
1516 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1517 errmsg("access method \"%s\" does not exist",
1521 * Look up the opclass.
1523 tuple
= OpClassCacheLookup(amID
, stmt
->opclassname
);
1524 if (!HeapTupleIsValid(tuple
))
1526 if (!stmt
->missing_ok
)
1528 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1529 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1530 NameListToString(stmt
->opclassname
), stmt
->amname
)));
1533 (errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1534 NameListToString(stmt
->opclassname
), stmt
->amname
)));
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
,
1544 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_OPCLASS
,
1545 NameListToString(stmt
->opclassname
));
1547 ReleaseSysCache(tuple
);
1552 object
.classId
= OperatorClassRelationId
;
1553 object
.objectId
= opcID
;
1554 object
.objectSubId
= 0;
1556 performDeletion(&object
, stmt
->behavior
);
1561 * Deletes an opfamily.
1564 RemoveOpFamily(RemoveOpFamilyStmt
*stmt
)
1569 ObjectAddress object
;
1572 * Get the access method's OID.
1574 amID
= GetSysCacheOid(AMNAME
,
1575 CStringGetDatum(stmt
->amname
),
1577 if (!OidIsValid(amID
))
1579 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1580 errmsg("access method \"%s\" does not exist",
1584 * Look up the opfamily.
1586 tuple
= OpFamilyCacheLookup(amID
, stmt
->opfamilyname
);
1587 if (!HeapTupleIsValid(tuple
))
1589 if (!stmt
->missing_ok
)
1591 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1592 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
1593 NameListToString(stmt
->opfamilyname
), stmt
->amname
)));
1596 (errmsg("operator family \"%s\" does not exist for access method \"%s\"",
1597 NameListToString(stmt
->opfamilyname
), stmt
->amname
)));
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
,
1607 aclcheck_error(ACLCHECK_NOT_OWNER
, ACL_KIND_OPFAMILY
,
1608 NameListToString(stmt
->opfamilyname
));
1610 ReleaseSysCache(tuple
);
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.
1627 RemoveOpFamilyById(Oid opfamilyOid
)
1632 rel
= heap_open(OperatorFamilyRelationId
, RowExclusiveLock
);
1634 tup
= SearchSysCache(OPFAMILYOID
,
1635 ObjectIdGetDatum(opfamilyOid
),
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
);
1648 RemoveOpClassById(Oid opclassOid
)
1653 rel
= heap_open(OperatorClassRelationId
, RowExclusiveLock
);
1655 tup
= SearchSysCache(CLAOID
,
1656 ObjectIdGetDatum(opclassOid
),
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
);
1669 RemoveAmOpEntryById(Oid entryOid
)
1673 ScanKeyData skey
[1];
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
);
1698 RemoveAmProcEntryById(Oid entryOid
)
1702 ScanKeyData skey
[1];
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
);
1731 RenameOpClass(List
*name
, const char *access_method
, const char *newname
)
1740 AclResult aclresult
;
1742 amOid
= GetSysCacheOid(AMNAME
,
1743 CStringGetDatum(access_method
),
1745 if (!OidIsValid(amOid
))
1747 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1748 errmsg("access method \"%s\" does not exist",
1751 rel
= heap_open(OperatorClassRelationId
, RowExclusiveLock
);
1754 * Look up the opclass
1756 DeconstructQualifiedName(name
, &schemaname
, &opcname
);
1760 namespaceOid
= LookupExplicitNamespace(schemaname
);
1762 tup
= SearchSysCacheCopy(CLAAMNAMENSP
,
1763 ObjectIdGetDatum(amOid
),
1764 PointerGetDatum(opcname
),
1765 ObjectIdGetDatum(namespaceOid
),
1767 if (!HeapTupleIsValid(tup
))
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
);
1777 opcOid
= OpclassnameGetOpcid(amOid
, opcname
);
1778 if (!OidIsValid(opcOid
))
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
),
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
),
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
))));
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
));
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
);
1831 RenameOpFamily(List
*name
, const char *access_method
, const char *newname
)
1840 AclResult aclresult
;
1842 amOid
= GetSysCacheOid(AMNAME
,
1843 CStringGetDatum(access_method
),
1845 if (!OidIsValid(amOid
))
1847 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1848 errmsg("access method \"%s\" does not exist",
1851 rel
= heap_open(OperatorFamilyRelationId
, RowExclusiveLock
);
1854 * Look up the opfamily
1856 DeconstructQualifiedName(name
, &schemaname
, &opfname
);
1860 namespaceOid
= LookupExplicitNamespace(schemaname
);
1862 tup
= SearchSysCacheCopy(OPFAMILYAMNAMENSP
,
1863 ObjectIdGetDatum(amOid
),
1864 PointerGetDatum(opfname
),
1865 ObjectIdGetDatum(namespaceOid
),
1867 if (!HeapTupleIsValid(tup
))
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
);
1877 opfOid
= OpfamilynameGetOpfid(amOid
, opfname
);
1878 if (!OidIsValid(opfOid
))
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
),
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
),
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
))));
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
));
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
1931 AlterOpClassOwner(List
*name
, const char *access_method
, Oid newOwnerId
)
1939 amOid
= GetSysCacheOid(AMNAME
,
1940 CStringGetDatum(access_method
),
1942 if (!OidIsValid(amOid
))
1944 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1945 errmsg("access method \"%s\" does not exist",
1948 rel
= heap_open(OperatorClassRelationId
, RowExclusiveLock
);
1951 * Look up the opclass
1953 DeconstructQualifiedName(name
, &schemaname
, &opcname
);
1959 namespaceOid
= LookupExplicitNamespace(schemaname
);
1961 tup
= SearchSysCacheCopy(CLAAMNAMENSP
,
1962 ObjectIdGetDatum(amOid
),
1963 PointerGetDatum(opcname
),
1964 ObjectIdGetDatum(namespaceOid
),
1966 if (!HeapTupleIsValid(tup
))
1968 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1969 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
1970 opcname
, access_method
)));
1976 opcOid
= OpclassnameGetOpcid(amOid
, opcname
);
1977 if (!OidIsValid(opcOid
))
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
),
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.
2001 AlterOpClassOwner_internal(Relation rel
, HeapTuple tup
, Oid newOwnerId
)
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 */
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
,
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
),
2055 * Change opfamily owner by name
2058 AlterOpFamilyOwner(List
*name
, const char *access_method
, Oid newOwnerId
)
2066 amOid
= GetSysCacheOid(AMNAME
,
2067 CStringGetDatum(access_method
),
2069 if (!OidIsValid(amOid
))
2071 (errcode(ERRCODE_UNDEFINED_OBJECT
),
2072 errmsg("access method \"%s\" does not exist",
2075 rel
= heap_open(OperatorFamilyRelationId
, RowExclusiveLock
);
2078 * Look up the opfamily
2080 DeconstructQualifiedName(name
, &schemaname
, &opfname
);
2086 namespaceOid
= LookupExplicitNamespace(schemaname
);
2088 tup
= SearchSysCacheCopy(OPFAMILYAMNAMENSP
,
2089 ObjectIdGetDatum(amOid
),
2090 PointerGetDatum(opfname
),
2091 ObjectIdGetDatum(namespaceOid
),
2093 if (!HeapTupleIsValid(tup
))
2095 (errcode(ERRCODE_UNDEFINED_OBJECT
),
2096 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
2097 opfname
, access_method
)));
2103 opfOid
= OpfamilynameGetOpfid(amOid
, opfname
);
2104 if (!OidIsValid(opfOid
))
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
),
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.
2128 AlterOpFamilyOwner_internal(Relation rel
, HeapTuple tup
, Oid newOwnerId
)
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 */
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
,
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
),