1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_operator relation
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/pg_operator.c
14 * these routines moved here from commands/define.c and somewhat cleaned up.
16 *-------------------------------------------------------------------------
20 #include "access/heapam.h"
21 #include "access/htup_details.h"
22 #include "access/xact.h"
23 #include "catalog/dependency.h"
24 #include "catalog/indexing.h"
25 #include "catalog/namespace.h"
26 #include "catalog/objectaccess.h"
27 #include "catalog/pg_namespace.h"
28 #include "catalog/pg_operator.h"
29 #include "catalog/pg_operator_fn.h"
30 #include "catalog/pg_proc.h"
31 #include "catalog/pg_type.h"
32 #include "miscadmin.h"
33 #include "parser/parse_oper.h"
34 #include "utils/acl.h"
35 #include "utils/builtins.h"
36 #include "utils/lsyscache.h"
37 #include "utils/rel.h"
38 #include "utils/syscache.h"
41 static Oid OperatorGet(const char *operatorName,
42 Oid operatorNamespace,
47 static Oid OperatorLookup(List *operatorName,
52 static Oid OperatorShellMake(const char *operatorName,
53 Oid operatorNamespace,
57 static Oid get_other_operator(List *otherOp,
58 Oid otherLeftTypeId, Oid otherRightTypeId,
59 const char *operatorName, Oid operatorNamespace,
60 Oid leftTypeId, Oid rightTypeId,
65 * Check whether a proposed operator name is legal
67 * This had better match the behavior of parser/scan.l!
69 * We need this because the parser is not smart enough to check that
70 * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
71 * are operator names rather than some other lexical entity.
74 validOperatorName(const char *name)
76 size_t len = strlen(name);
78 /* Can't be empty or too long */
79 if (len == 0 || len >= NAMEDATALEN)
82 /* Can't contain any invalid characters */
83 /* Test string here should match op_chars in scan.l */
84 if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
87 /* Can't contain slash-star or dash-dash (comment starts) */
88 if (strstr(name, "/*") || strstr(name, "--"))
92 * For SQL standard compatibility, '+' and '-' cannot be the last char of
93 * a multi-char operator unless the operator contains chars that are not
94 * in SQL operators. The idea is to lex '=-' as two operators, but not to
95 * forbid operator names like '?-' that could not be sequences of standard
99 (name[len - 1] == '+' ||
100 name[len - 1] == '-'))
104 for (ic = len - 2; ic >= 0; ic--)
106 if (strchr("~!@#^&|`?%", name[ic]))
110 return false; /* nope, not valid */
113 /* != isn't valid either, because parser will convert it to <> */
114 if (strcmp(name, "!=") == 0)
124 * finds an operator given an exact specification (name, namespace,
125 * left and right type IDs).
127 * *defined is set true if defined (not a shell)
130 OperatorGet(const char *operatorName,
131 Oid operatorNamespace,
137 Oid operatorObjectId;
139 tup = SearchSysCache4(OPERNAMENSP,
140 PointerGetDatum(operatorName),
141 ObjectIdGetDatum(leftObjectId),
142 ObjectIdGetDatum(rightObjectId),
143 ObjectIdGetDatum(operatorNamespace));
144 if (HeapTupleIsValid(tup))
146 RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
148 operatorObjectId = HeapTupleGetOid(tup);
149 *defined = RegProcedureIsValid(oprcode);
150 ReleaseSysCache(tup);
154 operatorObjectId = InvalidOid;
158 return operatorObjectId;
164 * looks up an operator given a possibly-qualified name and
165 * left and right type IDs.
167 * *defined is set true if defined (not a shell)
170 OperatorLookup(List *operatorName,
175 Oid operatorObjectId;
176 RegProcedure oprcode;
178 operatorObjectId = LookupOperName(NULL, operatorName,
179 leftObjectId, rightObjectId,
181 if (!OidIsValid(operatorObjectId))
187 oprcode = get_opcode(operatorObjectId);
188 *defined = RegProcedureIsValid(oprcode);
190 return operatorObjectId;
196 * Make a "shell" entry for a not-yet-existing operator.
199 OperatorShellMake(const char *operatorName,
200 Oid operatorNamespace,
204 Relation pg_operator_desc;
205 Oid operatorObjectId;
208 Datum values[Natts_pg_operator];
209 bool nulls[Natts_pg_operator];
214 * validate operator name
216 if (!validOperatorName(operatorName))
218 (errcode(ERRCODE_INVALID_NAME),
219 errmsg("\"%s\" is not a valid operator name",
223 * initialize our *nulls and *values arrays
225 for (i = 0; i < Natts_pg_operator; ++i)
228 values[i] = (Datum) NULL; /* redundant, but safe */
232 * initialize values[] with the operator name and input data types. Note
233 * that oprcode is set to InvalidOid, indicating it's a shell.
235 namestrcpy(&oname, operatorName);
236 values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
237 values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
238 values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
239 values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
240 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
241 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
242 values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
243 values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
244 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
245 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
246 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
247 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
248 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
249 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
254 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
255 tupDesc = pg_operator_desc->rd_att;
258 * create a new operator tuple
260 tup = heap_form_tuple(tupDesc, values, nulls);
263 * insert our "shell" operator tuple
265 operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
267 /* Add dependencies for the entry */
268 makeOperatorDependencies(tup, false);
272 /* Post creation hook for new shell operator */
273 InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
276 * Make sure the tuple is visible for subsequent lookups/updates.
278 CommandCounterIncrement();
281 * close the operator relation and return the oid.
283 heap_close(pg_operator_desc, RowExclusiveLock);
285 return operatorObjectId;
291 * "X" indicates an optional argument (i.e. one that can be NULL or 0)
292 * operatorName name for new operator
293 * operatorNamespace namespace for new operator
294 * leftTypeId X left type ID
295 * rightTypeId X right type ID
296 * procedureId procedure ID for operator
297 * commutatorName X commutator operator
298 * negatorName X negator operator
299 * restrictionId X restriction selectivity procedure ID
300 * joinId X join selectivity procedure ID
301 * canMerge merge join can be used with this operator
302 * canHash hash join can be used with this operator
304 * The caller should have validated properties and permissions for the
305 * objects passed as OID references. We must handle the commutator and
306 * negator operator references specially, however, since those need not
309 * This routine gets complicated because it allows the user to
310 * specify operators that do not exist. For example, if operator
311 * "op" is being defined, the negator operator "negop" and the
312 * commutator "commop" can also be defined without specifying
313 * any information other than their names. Since in order to
314 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
315 * operators must be placed in the fields of "op", a forward
316 * declaration is done on the commutator and negator operators.
317 * This is called creating a shell, and its main effect is to
318 * create a tuple in the PG_OPERATOR catalog with minimal
319 * information about the operator (just its name and types).
320 * Forward declaration is used only for this purpose, it is
321 * not available to the user as it is for type definition.
324 OperatorCreate(const char *operatorName,
325 Oid operatorNamespace,
329 List *commutatorName,
336 Relation pg_operator_desc;
339 bool nulls[Natts_pg_operator];
340 bool replaces[Natts_pg_operator];
341 Datum values[Natts_pg_operator];
342 Oid operatorObjectId;
343 bool operatorAlreadyDefined;
347 bool selfCommutator = false;
350 ObjectAddress address;
355 if (!validOperatorName(operatorName))
357 (errcode(ERRCODE_INVALID_NAME),
358 errmsg("\"%s\" is not a valid operator name",
361 if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
363 /* If it's not a binary op, these things mustn't be set: */
366 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
367 errmsg("only binary operators can have commutators")));
368 if (OidIsValid(joinId))
370 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
371 errmsg("only binary operators can have join selectivity")));
374 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
375 errmsg("only binary operators can merge join")));
378 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
379 errmsg("only binary operators can hash")));
382 operResultType = get_func_rettype(procedureId);
384 if (operResultType != BOOLOID)
386 /* If it's not a boolean op, these things mustn't be set: */
389 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
390 errmsg("only boolean operators can have negators")));
391 if (OidIsValid(restrictionId))
393 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
394 errmsg("only boolean operators can have restriction selectivity")));
395 if (OidIsValid(joinId))
397 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
398 errmsg("only boolean operators can have join selectivity")));
401 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
402 errmsg("only boolean operators can merge join")));
405 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
406 errmsg("only boolean operators can hash")));
409 operatorObjectId = OperatorGet(operatorName,
413 &operatorAlreadyDefined);
415 if (operatorAlreadyDefined)
417 (errcode(ERRCODE_DUPLICATE_FUNCTION),
418 errmsg("operator %s already exists",
422 * At this point, if operatorObjectId is not InvalidOid then we are
423 * filling in a previously-created shell. Insist that the user own any
426 if (OidIsValid(operatorObjectId) &&
427 !pg_oper_ownercheck(operatorObjectId, GetUserId()))
428 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
432 * Set up the other operators. If they do not currently exist, create
433 * shells in order to get ObjectId's.
438 /* commutator has reversed arg types */
439 commutatorId = get_other_operator(commutatorName,
440 rightTypeId, leftTypeId,
441 operatorName, operatorNamespace,
442 leftTypeId, rightTypeId,
445 /* Permission check: must own other operator */
446 if (OidIsValid(commutatorId) &&
447 !pg_oper_ownercheck(commutatorId, GetUserId()))
448 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
449 NameListToString(commutatorName));
452 * self-linkage to this operator; will fix below. Note that only
453 * self-linkage for commutation makes sense.
455 if (!OidIsValid(commutatorId))
456 selfCommutator = true;
459 commutatorId = InvalidOid;
463 /* negator has same arg types */
464 negatorId = get_other_operator(negatorName,
465 leftTypeId, rightTypeId,
466 operatorName, operatorNamespace,
467 leftTypeId, rightTypeId,
470 /* Permission check: must own other operator */
471 if (OidIsValid(negatorId) &&
472 !pg_oper_ownercheck(negatorId, GetUserId()))
473 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
474 NameListToString(negatorName));
477 negatorId = InvalidOid;
480 * set up values in the operator tuple
483 for (i = 0; i < Natts_pg_operator; ++i)
485 values[i] = (Datum) NULL;
490 namestrcpy(&oname, operatorName);
491 values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
492 values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
493 values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
494 values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
495 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
496 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
497 values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
498 values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
499 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
500 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
501 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
502 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
503 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
504 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
506 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
509 * If we are replacing an operator shell, update; else insert
511 if (operatorObjectId)
515 tup = SearchSysCacheCopy1(OPEROID,
516 ObjectIdGetDatum(operatorObjectId));
517 if (!HeapTupleIsValid(tup))
518 elog(ERROR, "cache lookup failed for operator %u",
521 tup = heap_modify_tuple(tup,
522 RelationGetDescr(pg_operator_desc),
527 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
533 tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
536 operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
539 /* Add dependencies for the entry */
540 address = makeOperatorDependencies(tup, isUpdate);
542 /* Post creation hook for new operator */
543 InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
545 heap_close(pg_operator_desc, RowExclusiveLock);
548 * If a commutator and/or negator link is provided, update the other
549 * operator(s) to point at this one, if they don't already have a link.
550 * This supports an alternative style of operator definition wherein the
551 * user first defines one operator without giving negator or commutator,
552 * then defines the other operator of the pair with the proper commutator
553 * or negator attribute. That style doesn't require creation of a shell,
554 * and it's the only style that worked right before Postgres version 6.5.
555 * This code also takes care of the situation where the new operator is
556 * its own commutator.
559 commutatorId = operatorObjectId;
561 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
562 OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
568 * Try to lookup another operator (commutator, etc)
570 * If not found, check to see if it is exactly the operator we are trying
571 * to define; if so, return InvalidOid. (Note that this case is only
572 * sensible for a commutator, so we error out otherwise.) If it is not
573 * the same operator, create a shell operator.
576 get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
577 const char *operatorName, Oid operatorNamespace,
578 Oid leftTypeId, Oid rightTypeId, bool isCommutator)
586 other_oid = OperatorLookup(otherOp,
591 if (OidIsValid(other_oid))
593 /* other op already in catalogs */
597 otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
600 if (strcmp(otherName, operatorName) == 0 &&
601 otherNamespace == operatorNamespace &&
602 otherLeftTypeId == leftTypeId &&
603 otherRightTypeId == rightTypeId)
606 * self-linkage to this operator; caller will fix later. Note that
607 * only self-linkage for commutation makes sense.
611 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
612 errmsg("operator cannot be its own negator or sort operator")));
616 /* not in catalogs, different from operator, so make shell */
618 aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
620 if (aclresult != ACLCHECK_OK)
621 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
622 get_namespace_name(otherNamespace));
624 other_oid = OperatorShellMake(otherName,
634 * For a given operator, look up its negator and commutator operators.
635 * When isDelete is false, update their negator and commutator fields to
636 * point back to the given operator; when isDelete is true, update those
637 * fields to no longer point back to the given operator.
639 * The !isDelete case solves a problem for users who need to insert two new
640 * operators that are the negator or commutator of each other, while the
641 * isDelete case is needed so as not to leave dangling OID links behind
642 * after dropping an operator.
645 OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
647 Relation pg_operator_desc;
651 * If we're making an operator into its own commutator, then we need a
652 * command-counter increment here, since we've just inserted the tuple
653 * we're about to update. But when we're dropping an operator, we can
654 * skip this because we're at the beginning of the command.
657 CommandCounterIncrement();
659 /* Open the relation. */
660 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
662 /* Get a writable copy of the commutator's tuple. */
663 if (OidIsValid(commId))
664 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
668 /* Update the commutator's tuple if need be. */
669 if (HeapTupleIsValid(tup))
671 Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
672 bool update_commutator = false;
675 * Out of due caution, we only change the commutator's oprcom field if
676 * it has the exact value we expected: InvalidOid when creating an
677 * operator, or baseId when dropping one.
679 if (isDelete && t->oprcom == baseId)
681 t->oprcom = InvalidOid;
682 update_commutator = true;
684 else if (!isDelete && !OidIsValid(t->oprcom))
687 update_commutator = true;
690 /* If any columns were found to need modification, update tuple. */
691 if (update_commutator)
693 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
696 * Do CCI to make the updated tuple visible. We must do this in
697 * case the commutator is also the negator. (Which would be a
698 * logic error on the operator definer's part, but that's not a
699 * good reason to fail here.) We would need a CCI anyway in the
700 * deletion case for a self-commutator with no negator.
702 CommandCounterIncrement();
707 * Similarly find and update the negator, if any.
709 if (OidIsValid(negId))
710 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
714 if (HeapTupleIsValid(tup))
716 Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
717 bool update_negator = false;
720 * Out of due caution, we only change the negator's oprnegate field if
721 * it has the exact value we expected: InvalidOid when creating an
722 * operator, or baseId when dropping one.
724 if (isDelete && t->oprnegate == baseId)
726 t->oprnegate = InvalidOid;
727 update_negator = true;
729 else if (!isDelete && !OidIsValid(t->oprnegate))
731 t->oprnegate = baseId;
732 update_negator = true;
735 /* If any columns were found to need modification, update tuple. */
738 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
741 * In the deletion case, do CCI to make the updated tuple visible.
742 * We must do this in case the operator is its own negator. (Which
743 * would be a logic error on the operator definer's part, but
744 * that's not a good reason to fail here.)
747 CommandCounterIncrement();
751 /* Close relation and release catalog lock. */
752 heap_close(pg_operator_desc, RowExclusiveLock);
756 * Create dependencies for an operator (either a freshly inserted
757 * complete operator, a new shell operator, a just-updated shell,
758 * or an operator that's being modified by ALTER OPERATOR).
760 * NB: the OidIsValid tests in this routine are necessary, in case
761 * the given operator is a shell.
764 makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
766 Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
767 ObjectAddress myself,
770 myself.classId = OperatorRelationId;
771 myself.objectId = HeapTupleGetOid(tuple);
772 myself.objectSubId = 0;
775 * If we are updating the operator, delete any existing entries, except
776 * for extension membership which should remain the same.
780 deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
781 deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
784 /* Dependency on namespace */
785 if (OidIsValid(oper->oprnamespace))
787 referenced.classId = NamespaceRelationId;
788 referenced.objectId = oper->oprnamespace;
789 referenced.objectSubId = 0;
790 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
793 /* Dependency on left type */
794 if (OidIsValid(oper->oprleft))
796 referenced.classId = TypeRelationId;
797 referenced.objectId = oper->oprleft;
798 referenced.objectSubId = 0;
799 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
802 /* Dependency on right type */
803 if (OidIsValid(oper->oprright))
805 referenced.classId = TypeRelationId;
806 referenced.objectId = oper->oprright;
807 referenced.objectSubId = 0;
808 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
811 /* Dependency on result type */
812 if (OidIsValid(oper->oprresult))
814 referenced.classId = TypeRelationId;
815 referenced.objectId = oper->oprresult;
816 referenced.objectSubId = 0;
817 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
821 * NOTE: we do not consider the operator to depend on the associated
822 * operators oprcom and oprnegate. We would not want to delete this
823 * operator if those go away, but only reset the link fields; which is not
824 * a function that the dependency code can presently handle. (Something
825 * could perhaps be done with objectSubId though.) For now, it's okay to
826 * let those links dangle if a referenced operator is removed.
829 /* Dependency on implementation function */
830 if (OidIsValid(oper->oprcode))
832 referenced.classId = ProcedureRelationId;
833 referenced.objectId = oper->oprcode;
834 referenced.objectSubId = 0;
835 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
838 /* Dependency on restriction selectivity function */
839 if (OidIsValid(oper->oprrest))
841 referenced.classId = ProcedureRelationId;
842 referenced.objectId = oper->oprrest;
843 referenced.objectSubId = 0;
844 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
847 /* Dependency on join selectivity function */
848 if (OidIsValid(oper->oprjoin))
850 referenced.classId = ProcedureRelationId;
851 referenced.objectId = oper->oprjoin;
852 referenced.objectSubId = 0;
853 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
856 /* Dependency on owner */
857 recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
860 /* Dependency on extension */
861 recordDependencyOnCurrentExtension(&myself, true);