1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_operator relation
6 * Portions Copyright (c) 1996-2024, 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/htup_details.h"
21 #include "access/table.h"
22 #include "access/xact.h"
23 #include "catalog/catalog.h"
24 #include "catalog/dependency.h"
25 #include "catalog/indexing.h"
26 #include "catalog/namespace.h"
27 #include "catalog/objectaccess.h"
28 #include "catalog/pg_namespace.h"
29 #include "catalog/pg_operator.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
OperatorShellMake(const char *operatorName
,
48 Oid operatorNamespace
,
52 static Oid
get_other_operator(List
*otherOp
,
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.
68 validOperatorName(const char *name
)
70 size_t len
= strlen(name
);
72 /* Can't be empty or too long */
73 if (len
== 0 || len
>= NAMEDATALEN
)
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
93 (name
[len
- 1] == '+' ||
94 name
[len
- 1] == '-'))
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)
124 OperatorGet(const char *operatorName
,
125 Oid operatorNamespace
,
131 Oid operatorObjectId
;
133 tup
= SearchSysCache4(OPERNAMENSP
,
134 PointerGetDatum(operatorName
),
135 ObjectIdGetDatum(leftObjectId
),
136 ObjectIdGetDatum(rightObjectId
),
137 ObjectIdGetDatum(operatorNamespace
));
138 if (HeapTupleIsValid(tup
))
140 Form_pg_operator oprform
= (Form_pg_operator
) GETSTRUCT(tup
);
142 operatorObjectId
= oprform
->oid
;
143 *defined
= RegProcedureIsValid(oprform
->oprcode
);
144 ReleaseSysCache(tup
);
148 operatorObjectId
= InvalidOid
;
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)
164 OperatorLookup(List
*operatorName
,
169 Oid operatorObjectId
;
170 RegProcedure oprcode
;
172 operatorObjectId
= LookupOperName(NULL
, operatorName
,
173 leftObjectId
, rightObjectId
,
175 if (!OidIsValid(operatorObjectId
))
181 oprcode
= get_opcode(operatorObjectId
);
182 *defined
= RegProcedureIsValid(oprcode
);
184 return operatorObjectId
;
190 * Make a "shell" entry for a not-yet-existing operator.
193 OperatorShellMake(const char *operatorName
,
194 Oid operatorNamespace
,
198 Relation pg_operator_desc
;
199 Oid operatorObjectId
;
202 Datum values
[Natts_pg_operator
];
203 bool nulls
[Natts_pg_operator
];
208 * validate operator name
210 if (!validOperatorName(operatorName
))
212 (errcode(ERRCODE_INVALID_NAME
),
213 errmsg("\"%s\" is not a valid operator name",
219 pg_operator_desc
= table_open(OperatorRelationId
, RowExclusiveLock
);
220 tupDesc
= pg_operator_desc
->rd_att
;
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 operatorObjectId
= GetNewOidWithIndex(pg_operator_desc
, OperatorOidIndexId
,
236 Anum_pg_operator_oid
);
237 values
[Anum_pg_operator_oid
- 1] = ObjectIdGetDatum(operatorObjectId
);
238 namestrcpy(&oname
, operatorName
);
239 values
[Anum_pg_operator_oprname
- 1] = NameGetDatum(&oname
);
240 values
[Anum_pg_operator_oprnamespace
- 1] = ObjectIdGetDatum(operatorNamespace
);
241 values
[Anum_pg_operator_oprowner
- 1] = ObjectIdGetDatum(GetUserId());
242 values
[Anum_pg_operator_oprkind
- 1] = CharGetDatum(leftTypeId
? 'b' : 'l');
243 values
[Anum_pg_operator_oprcanmerge
- 1] = BoolGetDatum(false);
244 values
[Anum_pg_operator_oprcanhash
- 1] = BoolGetDatum(false);
245 values
[Anum_pg_operator_oprleft
- 1] = ObjectIdGetDatum(leftTypeId
);
246 values
[Anum_pg_operator_oprright
- 1] = ObjectIdGetDatum(rightTypeId
);
247 values
[Anum_pg_operator_oprresult
- 1] = ObjectIdGetDatum(InvalidOid
);
248 values
[Anum_pg_operator_oprcom
- 1] = ObjectIdGetDatum(InvalidOid
);
249 values
[Anum_pg_operator_oprnegate
- 1] = ObjectIdGetDatum(InvalidOid
);
250 values
[Anum_pg_operator_oprcode
- 1] = ObjectIdGetDatum(InvalidOid
);
251 values
[Anum_pg_operator_oprrest
- 1] = ObjectIdGetDatum(InvalidOid
);
252 values
[Anum_pg_operator_oprjoin
- 1] = ObjectIdGetDatum(InvalidOid
);
255 * create a new operator tuple
257 tup
= heap_form_tuple(tupDesc
, values
, nulls
);
260 * insert our "shell" operator tuple
262 CatalogTupleInsert(pg_operator_desc
, tup
);
264 /* Add dependencies for the entry */
265 makeOperatorDependencies(tup
, true, false);
269 /* Post creation hook for new shell operator */
270 InvokeObjectPostCreateHook(OperatorRelationId
, operatorObjectId
, 0);
273 * Make sure the tuple is visible for subsequent lookups/updates.
275 CommandCounterIncrement();
278 * close the operator relation and return the oid.
280 table_close(pg_operator_desc
, RowExclusiveLock
);
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.
321 OperatorCreate(const char *operatorName
,
322 Oid operatorNamespace
,
326 List
*commutatorName
,
333 Relation pg_operator_desc
;
336 bool nulls
[Natts_pg_operator
];
337 bool replaces
[Natts_pg_operator
];
338 Datum values
[Natts_pg_operator
];
339 Oid operatorObjectId
;
340 bool operatorAlreadyDefined
;
344 bool selfCommutator
= false;
347 ObjectAddress address
;
352 if (!validOperatorName(operatorName
))
354 (errcode(ERRCODE_INVALID_NAME
),
355 errmsg("\"%s\" is not a valid operator name",
358 operResultType
= get_func_rettype(procedureId
);
360 OperatorValidateParams(leftTypeId
,
363 commutatorName
!= NIL
,
365 OidIsValid(restrictionId
),
370 operatorObjectId
= OperatorGet(operatorName
,
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
387 if (OidIsValid(operatorObjectId
) &&
388 !object_ownercheck(OperatorRelationId
, operatorObjectId
, GetUserId()))
389 aclcheck_error(ACLCHECK_NOT_OWNER
, OBJECT_OPERATOR
,
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 */
400 commutatorId
= get_other_operator(commutatorName
,
401 rightTypeId
, leftTypeId
,
402 operatorName
, operatorNamespace
,
403 leftTypeId
, rightTypeId
);
405 /* Permission check: must own other operator */
406 if (OidIsValid(commutatorId
) &&
407 !object_ownercheck(OperatorRelationId
, commutatorId
, GetUserId()))
408 aclcheck_error(ACLCHECK_NOT_OWNER
, OBJECT_OPERATOR
,
409 NameListToString(commutatorName
));
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.)
416 if (!OidIsValid(commutatorId
))
417 selfCommutator
= true;
420 commutatorId
= InvalidOid
;
424 /* negator has same arg types */
425 negatorId
= get_other_operator(negatorName
,
426 leftTypeId
, rightTypeId
,
427 operatorName
, operatorNamespace
,
428 leftTypeId
, rightTypeId
);
430 /* Permission check: must own other operator */
431 if (OidIsValid(negatorId
) &&
432 !object_ownercheck(OperatorRelationId
, negatorId
, GetUserId()))
433 aclcheck_error(ACLCHECK_NOT_OWNER
, OBJECT_OPERATOR
,
434 NameListToString(negatorName
));
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")));
448 negatorId
= InvalidOid
;
451 * set up values in the operator tuple
454 for (i
= 0; i
< Natts_pg_operator
; ++i
)
456 values
[i
] = (Datum
) NULL
;
461 namestrcpy(&oname
, operatorName
);
462 values
[Anum_pg_operator_oprname
- 1] = NameGetDatum(&oname
);
463 values
[Anum_pg_operator_oprnamespace
- 1] = ObjectIdGetDatum(operatorNamespace
);
464 values
[Anum_pg_operator_oprowner
- 1] = ObjectIdGetDatum(GetUserId());
465 values
[Anum_pg_operator_oprkind
- 1] = CharGetDatum(leftTypeId
? 'b' : 'l');
466 values
[Anum_pg_operator_oprcanmerge
- 1] = BoolGetDatum(canMerge
);
467 values
[Anum_pg_operator_oprcanhash
- 1] = BoolGetDatum(canHash
);
468 values
[Anum_pg_operator_oprleft
- 1] = ObjectIdGetDatum(leftTypeId
);
469 values
[Anum_pg_operator_oprright
- 1] = ObjectIdGetDatum(rightTypeId
);
470 values
[Anum_pg_operator_oprresult
- 1] = ObjectIdGetDatum(operResultType
);
471 values
[Anum_pg_operator_oprcom
- 1] = ObjectIdGetDatum(commutatorId
);
472 values
[Anum_pg_operator_oprnegate
- 1] = ObjectIdGetDatum(negatorId
);
473 values
[Anum_pg_operator_oprcode
- 1] = ObjectIdGetDatum(procedureId
);
474 values
[Anum_pg_operator_oprrest
- 1] = ObjectIdGetDatum(restrictionId
);
475 values
[Anum_pg_operator_oprjoin
- 1] = ObjectIdGetDatum(joinId
);
477 pg_operator_desc
= table_open(OperatorRelationId
, RowExclusiveLock
);
480 * If we are replacing an operator shell, update; else insert
482 if (operatorObjectId
)
486 tup
= SearchSysCacheCopy1(OPEROID
,
487 ObjectIdGetDatum(operatorObjectId
));
488 if (!HeapTupleIsValid(tup
))
489 elog(ERROR
, "cache lookup failed for operator %u",
492 replaces
[Anum_pg_operator_oid
- 1] = false;
493 tup
= heap_modify_tuple(tup
,
494 RelationGetDescr(pg_operator_desc
),
499 CatalogTupleUpdate(pg_operator_desc
, &tup
->t_self
, tup
);
505 operatorObjectId
= GetNewOidWithIndex(pg_operator_desc
,
507 Anum_pg_operator_oid
);
508 values
[Anum_pg_operator_oid
- 1] = ObjectIdGetDatum(operatorObjectId
);
510 tup
= heap_form_tuple(RelationGetDescr(pg_operator_desc
),
513 CatalogTupleInsert(pg_operator_desc
, tup
);
516 /* Add dependencies for the entry */
517 address
= makeOperatorDependencies(tup
, true, isUpdate
);
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
;
533 if (OidIsValid(commutatorId
) || OidIsValid(negatorId
))
534 OperatorUpd(operatorObjectId
, commutatorId
, negatorId
, false);
536 /* Post creation hook for new operator */
537 InvokeObjectPostCreateHook(OperatorRelationId
, operatorObjectId
, 0);
539 table_close(pg_operator_desc
, RowExclusiveLock
);
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.
556 OperatorValidateParams(Oid leftTypeId
,
561 bool hasRestrictionSelectivity
,
562 bool hasJoinSelectivity
,
566 if (!(OidIsValid(leftTypeId
) && OidIsValid(rightTypeId
)))
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
622 get_other_operator(List
*otherOp
, Oid otherLeftTypeId
, Oid otherRightTypeId
,
623 const char *operatorName
, Oid operatorNamespace
,
624 Oid leftTypeId
, Oid rightTypeId
)
632 other_oid
= OperatorLookup(otherOp
,
637 if (OidIsValid(other_oid
))
639 /* other op already in catalogs */
643 otherNamespace
= QualifiedNameGetCreationNamespace(otherOp
,
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 */
657 aclresult
= object_aclcheck(NamespaceRelationId
, otherNamespace
, GetUserId(),
659 if (aclresult
!= ACLCHECK_OK
)
660 aclcheck_error(aclresult
, OBJECT_SCHEMA
,
661 get_namespace_name(otherNamespace
));
663 other_oid
= OperatorShellMake(otherName
,
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.
684 OperatorUpd(Oid baseId
, Oid commId
, Oid negId
, bool isDelete
)
686 Relation pg_operator_desc
;
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.
696 CommandCounterIncrement();
698 /* Open the relation. */
699 pg_operator_desc
= table_open(OperatorRelationId
, RowExclusiveLock
);
701 /* Get a writable copy of the commutator's tuple. */
702 if (OidIsValid(commId
))
703 tup
= SearchSysCacheCopy1(OPEROID
, ObjectIdGetDatum(commId
));
707 /* Update the commutator's tuple if need be. */
708 if (HeapTupleIsValid(tup
))
710 Form_pg_operator t
= (Form_pg_operator
) GETSTRUCT(tup
);
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.
718 if (isDelete
&& OidIsValid(t
->oprcom
))
720 t
->oprcom
= InvalidOid
;
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.
732 if (OidIsValid(t
->oprcom
))
734 char *thirdop
= get_opname(t
->oprcom
);
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
)
755 CatalogTupleUpdate(pg_operator_desc
, &tup
->t_self
, tup
);
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.
764 CommandCounterIncrement();
769 * Similarly find and update the negator, if any.
771 if (OidIsValid(negId
))
772 tup
= SearchSysCacheCopy1(OPEROID
, ObjectIdGetDatum(negId
));
776 if (HeapTupleIsValid(tup
))
778 Form_pg_operator t
= (Form_pg_operator
) GETSTRUCT(tup
);
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.
786 if (isDelete
&& OidIsValid(t
->oprnegate
))
788 t
->oprnegate
= InvalidOid
;
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.
800 if (OidIsValid(t
->oprnegate
))
802 char *thirdop
= get_opname(t
->oprnegate
);
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. */
823 CatalogTupleUpdate(pg_operator_desc
, &tup
->t_self
, tup
);
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.)
832 CommandCounterIncrement();
836 /* Close relation and release catalog lock. */
837 table_close(pg_operator_desc
, RowExclusiveLock
);
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.
853 makeOperatorDependencies(HeapTuple tuple
,
854 bool makeExtensionDep
,
857 Form_pg_operator oper
= (Form_pg_operator
) GETSTRUCT(tuple
);
858 ObjectAddress myself
,
860 ObjectAddresses
*addrs
;
862 ObjectAddressSet(myself
, OperatorRelationId
, oper
->oid
);
865 * If we are updating the operator, delete any existing entries, except
866 * for extension membership which should remain the same.
870 deleteDependencyRecordsFor(myself
.classId
, myself
.objectId
, true);
871 deleteSharedDependencyRecordsFor(myself
.classId
, myself
.objectId
, 0);
874 addrs
= new_object_addresses();
876 /* Dependency on namespace */
877 if (OidIsValid(oper
->oprnamespace
))
879 ObjectAddressSet(referenced
, NamespaceRelationId
, oper
->oprnamespace
);
880 add_exact_object_address(&referenced
, addrs
);
883 /* Dependency on left type */
884 if (OidIsValid(oper
->oprleft
))
886 ObjectAddressSet(referenced
, TypeRelationId
, oper
->oprleft
);
887 add_exact_object_address(&referenced
, addrs
);
890 /* Dependency on right type */
891 if (OidIsValid(oper
->oprright
))
893 ObjectAddressSet(referenced
, TypeRelationId
, oper
->oprright
);
894 add_exact_object_address(&referenced
, addrs
);
897 /* Dependency on result type */
898 if (OidIsValid(oper
->oprresult
))
900 ObjectAddressSet(referenced
, TypeRelationId
, oper
->oprresult
);
901 add_exact_object_address(&referenced
, addrs
);
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 */
913 if (OidIsValid(oper
->oprcode
))
915 ObjectAddressSet(referenced
, ProcedureRelationId
, oper
->oprcode
);
916 add_exact_object_address(&referenced
, addrs
);
919 /* Dependency on restriction selectivity function */
920 if (OidIsValid(oper
->oprrest
))
922 ObjectAddressSet(referenced
, ProcedureRelationId
, oper
->oprrest
);
923 add_exact_object_address(&referenced
, addrs
);
926 /* Dependency on join selectivity function */
927 if (OidIsValid(oper
->oprjoin
))
929 ObjectAddressSet(referenced
, ProcedureRelationId
, oper
->oprjoin
);
930 add_exact_object_address(&referenced
, addrs
);
933 record_object_address_dependencies(&myself
, addrs
, DEPENDENCY_NORMAL
);
934 free_object_addresses(addrs
);
936 /* Dependency on owner */
937 recordDependencyOnOwner(OperatorRelationId
, oper
->oid
,
940 /* Dependency on extension */
941 if (makeExtensionDep
)
942 recordDependencyOnCurrentExtension(&myself
, isUpdate
);