1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_operator relation
6 * Portions Copyright (c) 1996-2011, 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/xact.h"
22 #include "catalog/dependency.h"
23 #include "catalog/indexing.h"
24 #include "catalog/namespace.h"
25 #include "catalog/objectaccess.h"
26 #include "catalog/pg_namespace.h"
27 #include "catalog/pg_operator.h"
28 #include "catalog/pg_proc.h"
29 #include "catalog/pg_type.h"
30 #include "miscadmin.h"
31 #include "parser/parse_oper.h"
32 #include "utils/acl.h"
33 #include "utils/builtins.h"
34 #include "utils/lsyscache.h"
35 #include "utils/rel.h"
36 #include "utils/syscache.h"
39 static Oid OperatorGet(const char *operatorName,
40 Oid operatorNamespace,
45 static Oid OperatorLookup(List *operatorName,
50 static Oid OperatorShellMake(const char *operatorName,
51 Oid operatorNamespace,
55 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
57 static Oid get_other_operator(List *otherOp,
58 Oid otherLeftTypeId, Oid otherRightTypeId,
59 const char *operatorName, Oid operatorNamespace,
60 Oid leftTypeId, Oid rightTypeId,
63 static void makeOperatorDependencies(HeapTuple tuple);
67 * Check whether a proposed operator name is legal
69 * This had better match the behavior of parser/scan.l!
71 * We need this because the parser is not smart enough to check that
72 * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
73 * are operator names rather than some other lexical entity.
76 validOperatorName(const char *name)
78 size_t len = strlen(name);
80 /* Can't be empty or too long */
81 if (len == 0 || len >= NAMEDATALEN)
84 /* Can't contain any invalid characters */
85 /* Test string here should match op_chars in scan.l */
86 if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
89 /* Can't contain slash-star or dash-dash (comment starts) */
90 if (strstr(name, "/*") || strstr(name, "--"))
94 * For SQL92 compatibility, '+' and '-' cannot be the last char of a
95 * multi-char operator unless the operator contains chars that are not in
96 * SQL92 operators. The idea is to lex '=-' as two operators, but not to
97 * forbid operator names like '?-' that could not be sequences of SQL92
101 (name[len - 1] == '+' ||
102 name[len - 1] == '-'))
106 for (ic = len - 2; ic >= 0; ic--)
108 if (strchr("~!@#^&|`?%", name[ic]))
112 return false; /* nope, not valid */
115 /* != isn't valid either, because parser will convert it to <> */
116 if (strcmp(name, "!=") == 0)
126 * finds an operator given an exact specification (name, namespace,
127 * left and right type IDs).
129 * *defined is set TRUE if defined (not a shell)
132 OperatorGet(const char *operatorName,
133 Oid operatorNamespace,
139 Oid operatorObjectId;
141 tup = SearchSysCache4(OPERNAMENSP,
142 PointerGetDatum(operatorName),
143 ObjectIdGetDatum(leftObjectId),
144 ObjectIdGetDatum(rightObjectId),
145 ObjectIdGetDatum(operatorNamespace));
146 if (HeapTupleIsValid(tup))
148 RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
150 operatorObjectId = HeapTupleGetOid(tup);
151 *defined = RegProcedureIsValid(oprcode);
152 ReleaseSysCache(tup);
156 operatorObjectId = InvalidOid;
160 return operatorObjectId;
166 * looks up an operator given a possibly-qualified name and
167 * left and right type IDs.
169 * *defined is set TRUE if defined (not a shell)
172 OperatorLookup(List *operatorName,
177 Oid operatorObjectId;
178 RegProcedure oprcode;
180 operatorObjectId = LookupOperName(NULL, operatorName,
181 leftObjectId, rightObjectId,
183 if (!OidIsValid(operatorObjectId))
189 oprcode = get_opcode(operatorObjectId);
190 *defined = RegProcedureIsValid(oprcode);
192 return operatorObjectId;
198 * Make a "shell" entry for a not-yet-existing operator.
201 OperatorShellMake(const char *operatorName,
202 Oid operatorNamespace,
206 Relation pg_operator_desc;
207 Oid operatorObjectId;
210 Datum values[Natts_pg_operator];
211 bool nulls[Natts_pg_operator];
216 * validate operator name
218 if (!validOperatorName(operatorName))
220 (errcode(ERRCODE_INVALID_NAME),
221 errmsg("\"%s\" is not a valid operator name",
225 * initialize our *nulls and *values arrays
227 for (i = 0; i < Natts_pg_operator; ++i)
230 values[i] = (Datum) NULL; /* redundant, but safe */
234 * initialize values[] with the operator name and input data types. Note
235 * that oprcode is set to InvalidOid, indicating it's a shell.
237 namestrcpy(&oname, operatorName);
238 values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
239 values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
240 values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
241 values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
242 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
243 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
244 values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
245 values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
246 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
247 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
248 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
249 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
250 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
251 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
256 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
257 tupDesc = pg_operator_desc->rd_att;
260 * create a new operator tuple
262 tup = heap_form_tuple(tupDesc, values, nulls);
265 * insert our "shell" operator tuple
267 operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
269 CatalogUpdateIndexes(pg_operator_desc, tup);
271 /* Add dependencies for the entry */
272 makeOperatorDependencies(tup);
276 /* Post creation hook for new shell operator */
277 InvokeObjectAccessHook(OAT_POST_CREATE,
278 OperatorRelationId, operatorObjectId, 0);
281 * Make sure the tuple is visible for subsequent lookups/updates.
283 CommandCounterIncrement();
286 * close the operator relation and return the oid.
288 heap_close(pg_operator_desc, RowExclusiveLock);
290 return operatorObjectId;
296 * "X" indicates an optional argument (i.e. one that can be NULL or 0)
297 * operatorName name for new operator
298 * operatorNamespace namespace for new operator
299 * leftTypeId X left type ID
300 * rightTypeId X right type ID
301 * procedureId procedure ID for operator
302 * commutatorName X commutator operator
303 * negatorName X negator operator
304 * restrictionId X restriction selectivity procedure ID
305 * joinId X join selectivity procedure ID
306 * canMerge merge join can be used with this operator
307 * canHash hash join can be used with this operator
309 * The caller should have validated properties and permissions for the
310 * objects passed as OID references. We must handle the commutator and
311 * negator operator references specially, however, since those need not
314 * This routine gets complicated because it allows the user to
315 * specify operators that do not exist. For example, if operator
316 * "op" is being defined, the negator operator "negop" and the
317 * commutator "commop" can also be defined without specifying
318 * any information other than their names. Since in order to
319 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
320 * operators must be placed in the fields of "op", a forward
321 * declaration is done on the commutator and negator operators.
322 * This is called creating a shell, and its main effect is to
323 * create a tuple in the PG_OPERATOR catalog with minimal
324 * information about the operator (just its name and types).
325 * Forward declaration is used only for this purpose, it is
326 * not available to the user as it is for type definition.
329 OperatorCreate(const char *operatorName,
330 Oid operatorNamespace,
334 List *commutatorName,
341 Relation pg_operator_desc;
343 bool nulls[Natts_pg_operator];
344 bool replaces[Natts_pg_operator];
345 Datum values[Natts_pg_operator];
346 Oid operatorObjectId;
347 bool operatorAlreadyDefined;
351 bool selfCommutator = false;
359 if (!validOperatorName(operatorName))
361 (errcode(ERRCODE_INVALID_NAME),
362 errmsg("\"%s\" is not a valid operator name",
365 if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
367 /* If it's not a binary op, these things mustn't be set: */
370 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
371 errmsg("only binary operators can have commutators")));
372 if (OidIsValid(joinId))
374 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
375 errmsg("only binary operators can have join selectivity")));
378 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
379 errmsg("only binary operators can merge join")));
382 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
383 errmsg("only binary operators can hash")));
386 operResultType = get_func_rettype(procedureId);
388 if (operResultType != BOOLOID)
390 /* If it's not a boolean op, these things mustn't be set: */
393 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
394 errmsg("only boolean operators can have negators")));
395 if (OidIsValid(restrictionId))
397 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
398 errmsg("only boolean operators can have restriction selectivity")));
399 if (OidIsValid(joinId))
401 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
402 errmsg("only boolean operators can have join selectivity")));
405 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
406 errmsg("only boolean operators can merge join")));
409 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
410 errmsg("only boolean operators can hash")));
413 operatorObjectId = OperatorGet(operatorName,
417 &operatorAlreadyDefined);
419 if (operatorAlreadyDefined)
421 (errcode(ERRCODE_DUPLICATE_FUNCTION),
422 errmsg("operator %s already exists",
426 * At this point, if operatorObjectId is not InvalidOid then we are
427 * filling in a previously-created shell. Insist that the user own any
430 if (OidIsValid(operatorObjectId) &&
431 !pg_oper_ownercheck(operatorObjectId, GetUserId()))
432 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
436 * Set up the other operators. If they do not currently exist, create
437 * shells in order to get ObjectId's.
442 /* commutator has reversed arg types */
443 commutatorId = get_other_operator(commutatorName,
444 rightTypeId, leftTypeId,
445 operatorName, operatorNamespace,
446 leftTypeId, rightTypeId,
449 /* Permission check: must own other operator */
450 if (OidIsValid(commutatorId) &&
451 !pg_oper_ownercheck(commutatorId, GetUserId()))
452 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
453 NameListToString(commutatorName));
456 * self-linkage to this operator; will fix below. Note that only
457 * self-linkage for commutation makes sense.
459 if (!OidIsValid(commutatorId))
460 selfCommutator = true;
463 commutatorId = InvalidOid;
467 /* negator has same arg types */
468 negatorId = get_other_operator(negatorName,
469 leftTypeId, rightTypeId,
470 operatorName, operatorNamespace,
471 leftTypeId, rightTypeId,
474 /* Permission check: must own other operator */
475 if (OidIsValid(negatorId) &&
476 !pg_oper_ownercheck(negatorId, GetUserId()))
477 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
478 NameListToString(negatorName));
481 negatorId = InvalidOid;
484 * set up values in the operator tuple
487 for (i = 0; i < Natts_pg_operator; ++i)
489 values[i] = (Datum) NULL;
494 namestrcpy(&oname, operatorName);
495 values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
496 values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
497 values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
498 values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
499 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
500 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
501 values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
502 values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
503 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
504 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
505 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
506 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
507 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
508 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
510 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
513 * If we are replacing an operator shell, update; else insert
515 if (operatorObjectId)
517 tup = SearchSysCacheCopy1(OPEROID,
518 ObjectIdGetDatum(operatorObjectId));
519 if (!HeapTupleIsValid(tup))
520 elog(ERROR, "cache lookup failed for operator %u",
523 tup = heap_modify_tuple(tup,
524 RelationGetDescr(pg_operator_desc),
529 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
533 tupDesc = pg_operator_desc->rd_att;
534 tup = heap_form_tuple(tupDesc, values, nulls);
536 operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
539 /* Must update the indexes in either case */
540 CatalogUpdateIndexes(pg_operator_desc, tup);
542 /* Add dependencies for the entry */
543 makeOperatorDependencies(tup);
545 /* Post creation hook for new operator */
546 InvokeObjectAccessHook(OAT_POST_CREATE,
547 OperatorRelationId, operatorObjectId, 0);
549 heap_close(pg_operator_desc, RowExclusiveLock);
552 * If a commutator and/or negator link is provided, update the other
553 * operator(s) to point at this one, if they don't already have a link.
554 * This supports an alternative style of operator definition wherein the
555 * user first defines one operator without giving negator or commutator,
556 * then defines the other operator of the pair with the proper commutator
557 * or negator attribute. That style doesn't require creation of a shell,
558 * and it's the only style that worked right before Postgres version 6.5.
559 * This code also takes care of the situation where the new operator is
560 * its own commutator.
563 commutatorId = operatorObjectId;
565 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
566 OperatorUpd(operatorObjectId, commutatorId, negatorId);
570 * Try to lookup another operator (commutator, etc)
572 * If not found, check to see if it is exactly the operator we are trying
573 * to define; if so, return InvalidOid. (Note that this case is only
574 * sensible for a commutator, so we error out otherwise.) If it is not
575 * the same operator, create a shell operator.
578 get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
579 const char *operatorName, Oid operatorNamespace,
580 Oid leftTypeId, Oid rightTypeId, bool isCommutator)
588 other_oid = OperatorLookup(otherOp,
593 if (OidIsValid(other_oid))
595 /* other op already in catalogs */
599 otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
602 if (strcmp(otherName, operatorName) == 0 &&
603 otherNamespace == operatorNamespace &&
604 otherLeftTypeId == leftTypeId &&
605 otherRightTypeId == rightTypeId)
608 * self-linkage to this operator; caller will fix later. Note that
609 * only self-linkage for commutation makes sense.
613 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
614 errmsg("operator cannot be its own negator or sort operator")));
618 /* not in catalogs, different from operator, so make shell */
620 aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
622 if (aclresult != ACLCHECK_OK)
623 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
624 get_namespace_name(otherNamespace));
626 other_oid = OperatorShellMake(otherName,
636 * For a given operator, look up its negator and commutator operators.
637 * If they are defined, but their negator and commutator fields
638 * (respectively) are empty, then use the new operator for neg or comm.
639 * This solves a problem for users who need to insert two new operators
640 * which are the negator or commutator of each other.
643 OperatorUpd(Oid baseId, Oid commId, Oid negId)
646 Relation pg_operator_desc;
648 bool nulls[Natts_pg_operator];
649 bool replaces[Natts_pg_operator];
650 Datum values[Natts_pg_operator];
652 for (i = 0; i < Natts_pg_operator; ++i)
654 values[i] = (Datum) 0;
660 * check and update the commutator & negator, if necessary
662 * We need a CommandCounterIncrement here in case of a self-commutator
663 * operator: we'll need to update the tuple that we just inserted.
665 CommandCounterIncrement();
667 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
669 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
672 * if the commutator and negator are the same operator, do one update. XXX
673 * this is probably useless code --- I doubt it ever makes sense for
674 * commutator and negator to be the same thing...
678 if (HeapTupleIsValid(tup))
680 Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
682 if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
684 if (!OidIsValid(t->oprnegate))
686 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
687 replaces[Anum_pg_operator_oprnegate - 1] = true;
690 if (!OidIsValid(t->oprcom))
692 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
693 replaces[Anum_pg_operator_oprcom - 1] = true;
696 tup = heap_modify_tuple(tup,
697 RelationGetDescr(pg_operator_desc),
702 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
704 CatalogUpdateIndexes(pg_operator_desc, tup);
708 heap_close(pg_operator_desc, RowExclusiveLock);
713 /* if commutator and negator are different, do two updates */
715 if (HeapTupleIsValid(tup) &&
716 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
718 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
719 replaces[Anum_pg_operator_oprcom - 1] = true;
721 tup = heap_modify_tuple(tup,
722 RelationGetDescr(pg_operator_desc),
727 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
729 CatalogUpdateIndexes(pg_operator_desc, tup);
731 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
732 replaces[Anum_pg_operator_oprcom - 1] = false;
735 /* check and update the negator, if necessary */
737 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
739 if (HeapTupleIsValid(tup) &&
740 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
742 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
743 replaces[Anum_pg_operator_oprnegate - 1] = true;
745 tup = heap_modify_tuple(tup,
746 RelationGetDescr(pg_operator_desc),
751 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
753 CatalogUpdateIndexes(pg_operator_desc, tup);
756 heap_close(pg_operator_desc, RowExclusiveLock);
760 * Create dependencies for a new operator (either a freshly inserted
761 * complete operator, a new shell operator, or a just-updated shell).
763 * NB: the OidIsValid tests in this routine are necessary, in case
764 * the given operator is a shell.
767 makeOperatorDependencies(HeapTuple tuple)
769 Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
770 ObjectAddress myself,
773 myself.classId = OperatorRelationId;
774 myself.objectId = HeapTupleGetOid(tuple);
775 myself.objectSubId = 0;
778 * In case we are updating a shell, delete any existing entries, except
779 * for extension membership which should remain the same.
781 deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
782 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);