1/*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_operator relation
6 * Portions Copyright (c) 1996-2025, 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 *-------------------------------------------------------------------------
42 Oid operatorNamespace,
48 Oid operatorNamespace,
53 Oid otherLeftTypeId,
Oid otherRightTypeId,
54 const char *operatorName,
Oid operatorNamespace,
55 Oid leftTypeId,
Oid rightTypeId);
59 * Check whether a proposed operator name is legal
61 * This had better match the behavior of parser/scan.l!
63 * We need this because the parser is not smart enough to check that
64 * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
65 * are operator names rather than some other lexical entity.
72 /* Can't be empty or too long */
76 /* Can't contain any invalid characters */
77 /* Test string here should match op_chars in scan.l */
78 if (strspn(
name,
"~!@#^&|`?+-*/%<>=") !=
len)
81 /* Can't contain slash-star or dash-dash (comment starts) */
82 if (strstr(
name,
"/*") || strstr(
name,
"--"))
86 * For SQL standard compatibility, '+' and '-' cannot be the last char of
87 * a multi-char operator unless the operator contains chars that are not
88 * in SQL operators. The idea is to lex '=-' as two operators, but not to
89 * forbid operator names like '?-' that could not be sequences of standard
98 for (ic =
len - 2; ic >= 0; ic--)
100 if (strchr(
"~!@#^&|`?%",
name[ic]))
104 return false;
/* nope, not valid */
107 /* != isn't valid either, because parser will convert it to <> */
108 if (strcmp(
name,
"!=") == 0)
118 * finds an operator given an exact specification (name, namespace,
119 * left and right type IDs).
121 * *defined is set true if defined (not a shell)
125 Oid operatorNamespace,
131 Oid operatorObjectId;
142 operatorObjectId = oprform->oid;
152 return operatorObjectId;
158 * looks up an operator given a possibly-qualified name and
159 * left and right type IDs.
161 * *defined is set true if defined (not a shell)
169 Oid operatorObjectId;
173 leftObjectId, rightObjectId,
184 return operatorObjectId;
190 * Make a "shell" entry for a not-yet-existing operator.
194 Oid operatorNamespace,
199 Oid operatorObjectId;
203 bool nulls[Natts_pg_operator];
208 * validate operator name
212 (
errcode(ERRCODE_INVALID_NAME),
213 errmsg(
"\"%s\" is not a valid operator name",
220 tupDesc = pg_operator_desc->
rd_att;
223 * initialize our *nulls and *values arrays
225 for (
i = 0;
i < Natts_pg_operator; ++
i)
232 * initialize values[] with the operator name and input data types. Note
233 * that oprcode is set to InvalidOid, indicating it's a shell.
236 Anum_pg_operator_oid);
255 * create a new operator tuple
260 * insert our "shell" operator tuple
264 /* Add dependencies for the entry */
269 /* Post creation hook for new shell operator */
273 * Make sure the tuple is visible for subsequent lookups/updates.
278 * close the operator relation and return the oid.
282 return operatorObjectId;
288 * "X" indicates an optional argument (i.e. one that can be NULL or 0)
289 * operatorName name for new operator
290 * operatorNamespace namespace for new operator
291 * leftTypeId X left type ID
292 * rightTypeId X right type ID
293 * procedureId procedure ID for operator
294 * commutatorName X commutator operator
295 * negatorName X negator operator
296 * restrictionId X restriction selectivity procedure ID
297 * joinId X join selectivity procedure ID
298 * canMerge merge join can be used with this operator
299 * canHash hash join can be used with this operator
301 * The caller should have validated properties and permissions for the
302 * objects passed as OID references. We must handle the commutator and
303 * negator operator references specially, however, since those need not
306 * This routine gets complicated because it allows the user to
307 * specify operators that do not exist. For example, if operator
308 * "op" is being defined, the negator operator "negop" and the
309 * commutator "commop" can also be defined without specifying
310 * any information other than their names. Since in order to
311 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
312 * operators must be placed in the fields of "op", a forward
313 * declaration is done on the commutator and negator operators.
314 * This is called creating a shell, and its main effect is to
315 * create a tuple in the PG_OPERATOR catalog with minimal
316 * information about the operator (just its name and types).
317 * Forward declaration is used only for this purpose, it is
318 * not available to the user as it is for type definition.
322 Oid operatorNamespace,
326 List *commutatorName,
336 bool nulls[Natts_pg_operator];
337 bool replaces[Natts_pg_operator];
339 Oid operatorObjectId;
340 bool operatorAlreadyDefined;
344 bool selfCommutator =
false;
354 (
errcode(ERRCODE_INVALID_NAME),
355 errmsg(
"\"%s\" is not a valid operator name",
363 commutatorName !=
NIL,
374 &operatorAlreadyDefined);
376 if (operatorAlreadyDefined)
378 (
errcode(ERRCODE_DUPLICATE_FUNCTION),
379 errmsg(
"operator %s already exists",
383 * At this point, if operatorObjectId is not InvalidOid then we are
384 * filling in a previously-created shell. Insist that the user own any
393 * Set up the other operators. If they do not currently exist, create
394 * shells in order to get ObjectId's.
399 /* commutator has reversed arg types */
401 rightTypeId, leftTypeId,
402 operatorName, operatorNamespace,
403 leftTypeId, rightTypeId);
405 /* Permission check: must own other operator */
412 * If self-linkage to the new operator is requested, we'll fix it
413 * below. (In case of self-linkage to an existing shell operator, we
414 * need do nothing special.)
417 selfCommutator =
true;
424 /* negator has same arg types */
426 leftTypeId, rightTypeId,
427 operatorName, operatorNamespace,
428 leftTypeId, rightTypeId);
430 /* Permission check: must own other operator */
437 * Prevent self negation, as it doesn't make sense. It's self
438 * negation if result is InvalidOid (negator would be the same
439 * operator but it doesn't exist yet) or operatorObjectId (we are
440 * replacing a shell that would need to be its own negator).
442 if (!
OidIsValid(negatorId) || negatorId == operatorObjectId)
444 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
445 errmsg(
"operator cannot be its own negator")));
451 * set up values in the operator tuple
454 for (
i = 0;
i < Natts_pg_operator; ++
i)
480 * If we are replacing an operator shell, update; else insert
482 if (operatorObjectId)
489 elog(
ERROR,
"cache lookup failed for operator %u",
492 replaces[Anum_pg_operator_oid - 1] =
false;
507 Anum_pg_operator_oid);
516 /* Add dependencies for the entry */
520 * If a commutator and/or negator link is provided, update the other
521 * operator(s) to point at this one, if they don't already have a link.
522 * This supports an alternative style of operator definition wherein the
523 * user first defines one operator without giving negator or commutator,
524 * then defines the other operator of the pair with the proper commutator
525 * or negator attribute. That style doesn't require creation of a shell,
526 * and it's the only style that worked right before Postgres version 6.5.
527 * This code also takes care of the situation where the new operator is
528 * its own commutator.
531 commutatorId = operatorObjectId;
534 OperatorUpd(operatorObjectId, commutatorId, negatorId,
false);
536 /* Post creation hook for new operator */
545 * OperatorValidateParams
547 * Check that an operator with argument types leftTypeId and rightTypeId,
548 * returning operResultType, can have the attributes that are set to true.
549 * Raise an error for any disallowed attribute.
551 * Note: in ALTER OPERATOR, we only bother to pass "true" for attributes
552 * the command is trying to set, not those that may already be set.
553 * This is OK as long as the attribute checks are independent.
561 bool hasRestrictionSelectivity,
562 bool hasJoinSelectivity,
568 /* If it's not a binary op, these things mustn't be set: */
571 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
572 errmsg(
"only binary operators can have commutators")));
573 if (hasJoinSelectivity)
575 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
576 errmsg(
"only binary operators can have join selectivity")));
579 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
580 errmsg(
"only binary operators can merge join")));
583 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
584 errmsg(
"only binary operators can hash")));
587 if (operResultType != BOOLOID)
589 /* If it's not a boolean op, these things mustn't be set: */
592 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
593 errmsg(
"only boolean operators can have negators")));
594 if (hasRestrictionSelectivity)
596 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
597 errmsg(
"only boolean operators can have restriction selectivity")));
598 if (hasJoinSelectivity)
600 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
601 errmsg(
"only boolean operators can have join selectivity")));
604 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
605 errmsg(
"only boolean operators can merge join")));
608 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
609 errmsg(
"only boolean operators can hash")));
614 * Try to lookup another operator (commutator, etc); return its OID
616 * If not found, check to see if it would be the same operator we are trying
617 * to define; if so, return InvalidOid. (Caller must decide whether
618 * that is sensible.) If it is not the same operator, create a shell
623 const char *operatorName,
Oid operatorNamespace,
624 Oid leftTypeId,
Oid rightTypeId)
639 /* other op already in catalogs */
646 if (strcmp(otherName, operatorName) == 0 &&
647 otherNamespace == operatorNamespace &&
648 otherLeftTypeId == leftTypeId &&
649 otherRightTypeId == rightTypeId)
651 /* self-linkage to new operator; caller must handle this */
655 /* not in catalogs, different from operator, so make shell */
673 * For a given operator, look up its negator and commutator operators.
674 * When isDelete is false, update their negator and commutator fields to
675 * point back to the given operator; when isDelete is true, update those
676 * fields to be InvalidOid.
678 * The !isDelete case solves a problem for users who need to insert two new
679 * operators that are the negator or commutator of each other, while the
680 * isDelete case is needed so as not to leave dangling OID links behind
681 * after dropping an operator.
690 * If we're making an operator into its own commutator, then we need a
691 * command-counter increment here, since we've just inserted the tuple
692 * we're about to update. But when we're dropping an operator, we can
693 * skip this because we're at the beginning of the command.
698 /* Open the relation. */
701 /* Get a writable copy of the commutator's tuple. */
707 /* Update the commutator's tuple if need be. */
711 bool update_commutator =
false;
714 * We can skip doing anything if the commutator's oprcom field is
715 * already what we want. While that's not expected in the isDelete
716 * case, it's perfectly possible when filling in a shell operator.
721 update_commutator =
true;
723 else if (!isDelete && t->oprcom != baseId)
726 * If commutator's oprcom field is already set to point to some
727 * third operator, it's an error. Changing its link would be
728 * unsafe, and letting the inconsistency stand would not be good
729 * either. This might be indicative of catalog corruption, so
730 * don't assume t->oprcom is necessarily a valid operator.
738 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
739 errmsg(
"commutator operator %s is already the commutator of operator %s",
740 NameStr(t->oprname), thirdop)));
743 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
744 errmsg(
"commutator operator %s is already the commutator of operator %u",
745 NameStr(t->oprname), t->oprcom)));
749 update_commutator =
true;
752 /* If any columns were found to need modification, update tuple. */
753 if (update_commutator)
758 * Do CCI to make the updated tuple visible. We must do this in
759 * case the commutator is also the negator. (Which would be a
760 * logic error on the operator definer's part, but that's not a
761 * good reason to fail here.) We would need a CCI anyway in the
762 * deletion case for a self-commutator with no negator.
769 * Similarly find and update the negator, if any.
779 bool update_negator =
false;
782 * We can skip doing anything if the negator's oprnegate field is
783 * already what we want. While that's not expected in the isDelete
784 * case, it's perfectly possible when filling in a shell operator.
789 update_negator =
true;
791 else if (!isDelete && t->oprnegate != baseId)
794 * If negator's oprnegate field is already set to point to some
795 * third operator, it's an error. Changing its link would be
796 * unsafe, and letting the inconsistency stand would not be good
797 * either. This might be indicative of catalog corruption, so
798 * don't assume t->oprnegate is necessarily a valid operator.
806 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
807 errmsg(
"negator operator %s is already the negator of operator %s",
808 NameStr(t->oprname), thirdop)));
811 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
812 errmsg(
"negator operator %s is already the negator of operator %u",
813 NameStr(t->oprname), t->oprnegate)));
816 t->oprnegate = baseId;
817 update_negator =
true;
820 /* If any columns were found to need modification, update tuple. */
826 * In the deletion case, do CCI to make the updated tuple visible.
827 * We must do this in case the operator is its own negator. (Which
828 * would be a logic error on the operator definer's part, but
829 * that's not a good reason to fail here.)
836 /* Close relation and release catalog lock. */
841 * Create dependencies for an operator (either a freshly inserted
842 * complete operator, a new shell operator, a just-updated shell,
843 * or an operator that's being modified by ALTER OPERATOR).
845 * makeExtensionDep should be true when making a new operator or
846 * replacing a shell, false for ALTER OPERATOR. Passing false
847 * will prevent any change in the operator's extension membership.
849 * NB: the OidIsValid tests in this routine are necessary, in case
850 * the given operator is a shell.
854 bool makeExtensionDep,
865 * If we are updating the operator, delete any existing entries, except
866 * for extension membership which should remain the same.
876 /* Dependency on namespace */
883 /* Dependency on left type */
890 /* Dependency on right type */
897 /* Dependency on result type */
905 * NOTE: we do not consider the operator to depend on the associated
906 * operators oprcom and oprnegate. We do not want to delete this operator
907 * if those go away, but only reset the link fields; which is not a
908 * function that the dependency logic can handle. (It's taken care of
909 * manually within RemoveOperatorById, instead.)
912 /* Dependency on implementation function */
919 /* Dependency on restriction selectivity function */
926 /* Dependency on join selectivity function */
936 /* Dependency on owner */
940 /* Dependency on extension */
941 if (makeExtensionDep)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
static Datum values[MAXATTR]
#define RegProcedureIsValid(p)
#define OidIsValid(objectId)
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
ObjectAddresses * new_object_addresses(void)
void free_object_addresses(ObjectAddresses *addrs)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
char * get_opname(Oid opno)
RegProcedure get_opcode(Oid opno)
char * get_namespace_name(Oid nspid)
Oid get_func_rettype(Oid funcid)
void namestrcpy(Name name, const char *str)
char * NameListToString(const List *names)
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
#define InvokeObjectPostCreateHook(classId, objectId, subId)
#define ObjectAddressSet(addr, class_id, object_id)
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
static Oid get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
static Oid OperatorShellMake(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
static Oid OperatorGet(const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined)
static bool validOperatorName(const char *name)
ObjectAddress OperatorCreate(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, Oid procedureId, List *commutatorName, List *negatorName, Oid restrictionId, Oid joinId, bool canMerge, bool canHash)
void OperatorValidateParams(Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
FormData_pg_operator * Form_pg_operator
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
static Datum PointerGetDatum(const void *X)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
static Datum NameGetDatum(const NameData *X)
static Datum CharGetDatum(char X)
#define RelationGetDescr(relation)
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache4(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
#define SearchSysCacheCopy1(cacheId, key1)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
void CommandCounterIncrement(void)