Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / catalog / pg_operator.c
blob0ab20ff61879e8f6489a91a2e6d75f4fc6360693
1 /*-------------------------------------------------------------------------
3 * pg_operator.c
4 * routines to support manipulation of the pg_operator relation
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * $PostgreSQL$
13 * NOTES
14 * these routines moved here from commands/define.c and somewhat cleaned up.
16 *-------------------------------------------------------------------------
18 #include "postgres.h"
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/pg_namespace.h"
26 #include "catalog/pg_operator.h"
27 #include "catalog/pg_proc.h"
28 #include "catalog/pg_type.h"
29 #include "miscadmin.h"
30 #include "parser/parse_oper.h"
31 #include "utils/acl.h"
32 #include "utils/builtins.h"
33 #include "utils/lsyscache.h"
34 #include "utils/rel.h"
35 #include "utils/syscache.h"
38 static Oid OperatorGet(const char *operatorName,
39 Oid operatorNamespace,
40 Oid leftObjectId,
41 Oid rightObjectId,
42 bool *defined);
44 static Oid OperatorLookup(List *operatorName,
45 Oid leftObjectId,
46 Oid rightObjectId,
47 bool *defined);
49 static Oid OperatorShellMake(const char *operatorName,
50 Oid operatorNamespace,
51 Oid leftTypeId,
52 Oid rightTypeId);
54 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
56 static Oid get_other_operator(List *otherOp,
57 Oid otherLeftTypeId, Oid otherRightTypeId,
58 const char *operatorName, Oid operatorNamespace,
59 Oid leftTypeId, Oid rightTypeId,
60 bool isCommutator);
62 static void makeOperatorDependencies(HeapTuple tuple);
66 * Check whether a proposed operator name is legal
68 * This had better match the behavior of parser/scan.l!
70 * We need this because the parser is not smart enough to check that
71 * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
72 * are operator names rather than some other lexical entity.
74 static bool
75 validOperatorName(const char *name)
77 size_t len = strlen(name);
79 /* Can't be empty or too long */
80 if (len == 0 || len >= NAMEDATALEN)
81 return false;
83 /* Can't contain any invalid characters */
84 /* Test string here should match op_chars in scan.l */
85 if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
86 return false;
88 /* Can't contain slash-star or dash-dash (comment starts) */
89 if (strstr(name, "/*") || strstr(name, "--"))
90 return false;
93 * For SQL92 compatibility, '+' and '-' cannot be the last char of a
94 * multi-char operator unless the operator contains chars that are not in
95 * SQL92 operators. The idea is to lex '=-' as two operators, but not to
96 * forbid operator names like '?-' that could not be sequences of SQL92
97 * operators.
99 if (len > 1 &&
100 (name[len - 1] == '+' ||
101 name[len - 1] == '-'))
103 int ic;
105 for (ic = len - 2; ic >= 0; ic--)
107 if (strchr("~!@#^&|`?%", name[ic]))
108 break;
110 if (ic < 0)
111 return false; /* nope, not valid */
114 /* != isn't valid either, because parser will convert it to <> */
115 if (strcmp(name, "!=") == 0)
116 return false;
118 return true;
123 * OperatorGet
125 * finds an operator given an exact specification (name, namespace,
126 * left and right type IDs).
128 * *defined is set TRUE if defined (not a shell)
130 static Oid
131 OperatorGet(const char *operatorName,
132 Oid operatorNamespace,
133 Oid leftObjectId,
134 Oid rightObjectId,
135 bool *defined)
137 HeapTuple tup;
138 Oid operatorObjectId;
140 tup = SearchSysCache(OPERNAMENSP,
141 PointerGetDatum(operatorName),
142 ObjectIdGetDatum(leftObjectId),
143 ObjectIdGetDatum(rightObjectId),
144 ObjectIdGetDatum(operatorNamespace));
145 if (HeapTupleIsValid(tup))
147 RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
149 operatorObjectId = HeapTupleGetOid(tup);
150 *defined = RegProcedureIsValid(oprcode);
151 ReleaseSysCache(tup);
153 else
155 operatorObjectId = InvalidOid;
156 *defined = false;
159 return operatorObjectId;
163 * OperatorLookup
165 * looks up an operator given a possibly-qualified name and
166 * left and right type IDs.
168 * *defined is set TRUE if defined (not a shell)
170 static Oid
171 OperatorLookup(List *operatorName,
172 Oid leftObjectId,
173 Oid rightObjectId,
174 bool *defined)
176 Oid operatorObjectId;
177 RegProcedure oprcode;
179 operatorObjectId = LookupOperName(NULL, operatorName,
180 leftObjectId, rightObjectId,
181 true, -1);
182 if (!OidIsValid(operatorObjectId))
184 *defined = false;
185 return InvalidOid;
188 oprcode = get_opcode(operatorObjectId);
189 *defined = RegProcedureIsValid(oprcode);
191 return operatorObjectId;
196 * OperatorShellMake
197 * Make a "shell" entry for a not-yet-existing operator.
199 static Oid
200 OperatorShellMake(const char *operatorName,
201 Oid operatorNamespace,
202 Oid leftTypeId,
203 Oid rightTypeId)
205 Relation pg_operator_desc;
206 Oid operatorObjectId;
207 int i;
208 HeapTuple tup;
209 Datum values[Natts_pg_operator];
210 char nulls[Natts_pg_operator];
211 NameData oname;
212 TupleDesc tupDesc;
215 * validate operator name
217 if (!validOperatorName(operatorName))
218 ereport(ERROR,
219 (errcode(ERRCODE_INVALID_NAME),
220 errmsg("\"%s\" is not a valid operator name",
221 operatorName)));
224 * initialize our *nulls and *values arrays
226 for (i = 0; i < Natts_pg_operator; ++i)
228 nulls[i] = ' ';
229 values[i] = (Datum) NULL; /* redundant, but safe */
233 * initialize values[] with the operator name and input data types. Note
234 * that oprcode is set to InvalidOid, indicating it's a shell.
236 i = 0;
237 namestrcpy(&oname, operatorName);
238 values[i++] = NameGetDatum(&oname); /* oprname */
239 values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
240 values[i++] = ObjectIdGetDatum(GetUserId()); /* oprowner */
241 values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
242 values[i++] = BoolGetDatum(false); /* oprcanmerge */
243 values[i++] = BoolGetDatum(false); /* oprcanhash */
244 values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
245 values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
246 values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */
247 values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */
248 values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */
249 values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */
250 values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */
251 values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */
254 * open pg_operator
256 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
257 tupDesc = pg_operator_desc->rd_att;
260 * create a new operator tuple
262 tup = heap_formtuple(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);
274 heap_freetuple(tup);
277 * Make sure the tuple is visible for subsequent lookups/updates.
279 CommandCounterIncrement();
282 * close the operator relation and return the oid.
284 heap_close(pg_operator_desc, RowExclusiveLock);
286 return operatorObjectId;
290 * OperatorCreate
292 * "X" indicates an optional argument (i.e. one that can be NULL or 0)
293 * operatorName name for new operator
294 * operatorNamespace namespace for new operator
295 * leftTypeId X left type ID
296 * rightTypeId X right type ID
297 * procedureId procedure ID for operator
298 * commutatorName X commutator operator
299 * negatorName X negator operator
300 * restrictionId X restriction selectivity procedure ID
301 * joinId X join selectivity procedure ID
302 * canMerge merge join can be used with this operator
303 * canHash hash join can be used with this operator
305 * The caller should have validated properties and permissions for the
306 * objects passed as OID references. We must handle the commutator and
307 * negator operator references specially, however, since those need not
308 * exist beforehand.
310 * This routine gets complicated because it allows the user to
311 * specify operators that do not exist. For example, if operator
312 * "op" is being defined, the negator operator "negop" and the
313 * commutator "commop" can also be defined without specifying
314 * any information other than their names. Since in order to
315 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
316 * operators must be placed in the fields of "op", a forward
317 * declaration is done on the commutator and negator operators.
318 * This is called creating a shell, and its main effect is to
319 * create a tuple in the PG_OPERATOR catalog with minimal
320 * information about the operator (just its name and types).
321 * Forward declaration is used only for this purpose, it is
322 * not available to the user as it is for type definition.
324 void
325 OperatorCreate(const char *operatorName,
326 Oid operatorNamespace,
327 Oid leftTypeId,
328 Oid rightTypeId,
329 Oid procedureId,
330 List *commutatorName,
331 List *negatorName,
332 Oid restrictionId,
333 Oid joinId,
334 bool canMerge,
335 bool canHash)
337 Relation pg_operator_desc;
338 HeapTuple tup;
339 char nulls[Natts_pg_operator];
340 char replaces[Natts_pg_operator];
341 Datum values[Natts_pg_operator];
342 Oid operatorObjectId;
343 bool operatorAlreadyDefined;
344 Oid operResultType;
345 Oid commutatorId,
346 negatorId;
347 bool selfCommutator = false;
348 NameData oname;
349 TupleDesc tupDesc;
350 int i;
353 * Sanity checks
355 if (!validOperatorName(operatorName))
356 ereport(ERROR,
357 (errcode(ERRCODE_INVALID_NAME),
358 errmsg("\"%s\" is not a valid operator name",
359 operatorName)));
361 if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
363 /* If it's not a binary op, these things mustn't be set: */
364 if (commutatorName)
365 ereport(ERROR,
366 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
367 errmsg("only binary operators can have commutators")));
368 if (OidIsValid(joinId))
369 ereport(ERROR,
370 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
371 errmsg("only binary operators can have join selectivity")));
372 if (canMerge)
373 ereport(ERROR,
374 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
375 errmsg("only binary operators can merge join")));
376 if (canHash)
377 ereport(ERROR,
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: */
387 if (negatorName)
388 ereport(ERROR,
389 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
390 errmsg("only boolean operators can have negators")));
391 if (OidIsValid(restrictionId))
392 ereport(ERROR,
393 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
394 errmsg("only boolean operators can have restriction selectivity")));
395 if (OidIsValid(joinId))
396 ereport(ERROR,
397 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
398 errmsg("only boolean operators can have join selectivity")));
399 if (canMerge)
400 ereport(ERROR,
401 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
402 errmsg("only boolean operators can merge join")));
403 if (canHash)
404 ereport(ERROR,
405 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
406 errmsg("only boolean operators can hash")));
409 operatorObjectId = OperatorGet(operatorName,
410 operatorNamespace,
411 leftTypeId,
412 rightTypeId,
413 &operatorAlreadyDefined);
415 if (operatorAlreadyDefined)
416 ereport(ERROR,
417 (errcode(ERRCODE_DUPLICATE_FUNCTION),
418 errmsg("operator %s already exists",
419 operatorName)));
422 * At this point, if operatorObjectId is not InvalidOid then we are
423 * filling in a previously-created shell. Insist that the user own
424 * any such shell.
426 if (OidIsValid(operatorObjectId) &&
427 !pg_oper_ownercheck(operatorObjectId, GetUserId()))
428 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
429 operatorName);
432 * Set up the other operators. If they do not currently exist, create
433 * shells in order to get ObjectId's.
436 if (commutatorName)
438 /* commutator has reversed arg types */
439 commutatorId = get_other_operator(commutatorName,
440 rightTypeId, leftTypeId,
441 operatorName, operatorNamespace,
442 leftTypeId, rightTypeId,
443 true);
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;
458 else
459 commutatorId = InvalidOid;
461 if (negatorName)
463 /* negator has same arg types */
464 negatorId = get_other_operator(negatorName,
465 leftTypeId, rightTypeId,
466 operatorName, operatorNamespace,
467 leftTypeId, rightTypeId,
468 false);
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));
476 else
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;
486 replaces[i] = 'r';
487 nulls[i] = ' ';
490 i = 0;
491 namestrcpy(&oname, operatorName);
492 values[i++] = NameGetDatum(&oname); /* oprname */
493 values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
494 values[i++] = ObjectIdGetDatum(GetUserId()); /* oprowner */
495 values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
496 values[i++] = BoolGetDatum(canMerge); /* oprcanmerge */
497 values[i++] = BoolGetDatum(canHash); /* oprcanhash */
498 values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
499 values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
500 values[i++] = ObjectIdGetDatum(operResultType); /* oprresult */
501 values[i++] = ObjectIdGetDatum(commutatorId); /* oprcom */
502 values[i++] = ObjectIdGetDatum(negatorId); /* oprnegate */
503 values[i++] = ObjectIdGetDatum(procedureId); /* oprcode */
504 values[i++] = ObjectIdGetDatum(restrictionId); /* oprrest */
505 values[i++] = ObjectIdGetDatum(joinId); /* oprjoin */
507 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
510 * If we are replacing an operator shell, update; else insert
512 if (operatorObjectId)
514 tup = SearchSysCacheCopy(OPEROID,
515 ObjectIdGetDatum(operatorObjectId),
516 0, 0, 0);
517 if (!HeapTupleIsValid(tup))
518 elog(ERROR, "cache lookup failed for operator %u",
519 operatorObjectId);
521 tup = heap_modifytuple(tup,
522 RelationGetDescr(pg_operator_desc),
523 values,
524 nulls,
525 replaces);
527 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
529 else
531 tupDesc = pg_operator_desc->rd_att;
532 tup = heap_formtuple(tupDesc, values, nulls);
534 operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
537 /* Must update the indexes in either case */
538 CatalogUpdateIndexes(pg_operator_desc, tup);
540 /* Add dependencies for the entry */
541 makeOperatorDependencies(tup);
543 heap_close(pg_operator_desc, RowExclusiveLock);
546 * If a commutator and/or negator link is provided, update the other
547 * operator(s) to point at this one, if they don't already have a link.
548 * This supports an alternative style of operator definition wherein the
549 * user first defines one operator without giving negator or commutator,
550 * then defines the other operator of the pair with the proper commutator
551 * or negator attribute. That style doesn't require creation of a shell,
552 * and it's the only style that worked right before Postgres version 6.5.
553 * This code also takes care of the situation where the new operator is
554 * its own commutator.
556 if (selfCommutator)
557 commutatorId = operatorObjectId;
559 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
560 OperatorUpd(operatorObjectId, commutatorId, negatorId);
564 * Try to lookup another operator (commutator, etc)
566 * If not found, check to see if it is exactly the operator we are trying
567 * to define; if so, return InvalidOid. (Note that this case is only
568 * sensible for a commutator, so we error out otherwise.) If it is not
569 * the same operator, create a shell operator.
571 static Oid
572 get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
573 const char *operatorName, Oid operatorNamespace,
574 Oid leftTypeId, Oid rightTypeId, bool isCommutator)
576 Oid other_oid;
577 bool otherDefined;
578 char *otherName;
579 Oid otherNamespace;
580 AclResult aclresult;
582 other_oid = OperatorLookup(otherOp,
583 otherLeftTypeId,
584 otherRightTypeId,
585 &otherDefined);
587 if (OidIsValid(other_oid))
589 /* other op already in catalogs */
590 return other_oid;
593 otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
594 &otherName);
596 if (strcmp(otherName, operatorName) == 0 &&
597 otherNamespace == operatorNamespace &&
598 otherLeftTypeId == leftTypeId &&
599 otherRightTypeId == rightTypeId)
602 * self-linkage to this operator; caller will fix later. Note that
603 * only self-linkage for commutation makes sense.
605 if (!isCommutator)
606 ereport(ERROR,
607 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
608 errmsg("operator cannot be its own negator or sort operator")));
609 return InvalidOid;
612 /* not in catalogs, different from operator, so make shell */
614 aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
615 ACL_CREATE);
616 if (aclresult != ACLCHECK_OK)
617 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
618 get_namespace_name(otherNamespace));
620 other_oid = OperatorShellMake(otherName,
621 otherNamespace,
622 otherLeftTypeId,
623 otherRightTypeId);
624 return other_oid;
628 * OperatorUpd
630 * For a given operator, look up its negator and commutator operators.
631 * If they are defined, but their negator and commutator fields
632 * (respectively) are empty, then use the new operator for neg or comm.
633 * This solves a problem for users who need to insert two new operators
634 * which are the negator or commutator of each other.
636 static void
637 OperatorUpd(Oid baseId, Oid commId, Oid negId)
639 int i;
640 Relation pg_operator_desc;
641 HeapTuple tup;
642 char nulls[Natts_pg_operator];
643 char replaces[Natts_pg_operator];
644 Datum values[Natts_pg_operator];
646 for (i = 0; i < Natts_pg_operator; ++i)
648 values[i] = (Datum) 0;
649 replaces[i] = ' ';
650 nulls[i] = ' ';
654 * check and update the commutator & negator, if necessary
656 * We need a CommandCounterIncrement here in case of a self-commutator
657 * operator: we'll need to update the tuple that we just inserted.
659 CommandCounterIncrement();
661 pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
663 tup = SearchSysCacheCopy(OPEROID,
664 ObjectIdGetDatum(commId),
665 0, 0, 0);
668 * if the commutator and negator are the same operator, do one update. XXX
669 * this is probably useless code --- I doubt it ever makes sense for
670 * commutator and negator to be the same thing...
672 if (commId == negId)
674 if (HeapTupleIsValid(tup))
676 Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
678 if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
680 if (!OidIsValid(t->oprnegate))
682 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
683 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
686 if (!OidIsValid(t->oprcom))
688 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
689 replaces[Anum_pg_operator_oprcom - 1] = 'r';
692 tup = heap_modifytuple(tup,
693 RelationGetDescr(pg_operator_desc),
694 values,
695 nulls,
696 replaces);
698 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
700 CatalogUpdateIndexes(pg_operator_desc, tup);
704 heap_close(pg_operator_desc, RowExclusiveLock);
706 return;
709 /* if commutator and negator are different, do two updates */
711 if (HeapTupleIsValid(tup) &&
712 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
714 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
715 replaces[Anum_pg_operator_oprcom - 1] = 'r';
717 tup = heap_modifytuple(tup,
718 RelationGetDescr(pg_operator_desc),
719 values,
720 nulls,
721 replaces);
723 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
725 CatalogUpdateIndexes(pg_operator_desc, tup);
727 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
728 replaces[Anum_pg_operator_oprcom - 1] = ' ';
731 /* check and update the negator, if necessary */
733 tup = SearchSysCacheCopy(OPEROID,
734 ObjectIdGetDatum(negId),
735 0, 0, 0);
737 if (HeapTupleIsValid(tup) &&
738 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
740 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
741 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
743 tup = heap_modifytuple(tup,
744 RelationGetDescr(pg_operator_desc),
745 values,
746 nulls,
747 replaces);
749 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
751 CatalogUpdateIndexes(pg_operator_desc, tup);
754 heap_close(pg_operator_desc, RowExclusiveLock);
758 * Create dependencies for a new operator (either a freshly inserted
759 * complete operator, a new shell operator, or a just-updated shell).
761 * NB: the OidIsValid tests in this routine are necessary, in case
762 * the given operator is a shell.
764 static void
765 makeOperatorDependencies(HeapTuple tuple)
767 Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
768 ObjectAddress myself,
769 referenced;
771 myself.classId = OperatorRelationId;
772 myself.objectId = HeapTupleGetOid(tuple);
773 myself.objectSubId = 0;
775 /* In case we are updating a shell, delete any existing entries */
776 deleteDependencyRecordsFor(myself.classId, myself.objectId);
777 deleteSharedDependencyRecordsFor(myself.classId, myself.objectId);
779 /* Dependency on namespace */
780 if (OidIsValid(oper->oprnamespace))
782 referenced.classId = NamespaceRelationId;
783 referenced.objectId = oper->oprnamespace;
784 referenced.objectSubId = 0;
785 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
788 /* Dependency on left type */
789 if (OidIsValid(oper->oprleft))
791 referenced.classId = TypeRelationId;
792 referenced.objectId = oper->oprleft;
793 referenced.objectSubId = 0;
794 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
797 /* Dependency on right type */
798 if (OidIsValid(oper->oprright))
800 referenced.classId = TypeRelationId;
801 referenced.objectId = oper->oprright;
802 referenced.objectSubId = 0;
803 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
806 /* Dependency on result type */
807 if (OidIsValid(oper->oprresult))
809 referenced.classId = TypeRelationId;
810 referenced.objectId = oper->oprresult;
811 referenced.objectSubId = 0;
812 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
816 * NOTE: we do not consider the operator to depend on the associated
817 * operators oprcom and oprnegate. We would not want to delete this
818 * operator if those go away, but only reset the link fields; which is not
819 * a function that the dependency code can presently handle. (Something
820 * could perhaps be done with objectSubId though.) For now, it's okay to
821 * let those links dangle if a referenced operator is removed.
824 /* Dependency on implementation function */
825 if (OidIsValid(oper->oprcode))
827 referenced.classId = ProcedureRelationId;
828 referenced.objectId = oper->oprcode;
829 referenced.objectSubId = 0;
830 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
833 /* Dependency on restriction selectivity function */
834 if (OidIsValid(oper->oprrest))
836 referenced.classId = ProcedureRelationId;
837 referenced.objectId = oper->oprrest;
838 referenced.objectSubId = 0;
839 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
842 /* Dependency on join selectivity function */
843 if (OidIsValid(oper->oprjoin))
845 referenced.classId = ProcedureRelationId;
846 referenced.objectId = oper->oprjoin;
847 referenced.objectSubId = 0;
848 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
851 /* Dependency on owner */
852 recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
853 oper->oprowner);