1/*-------------------------------------------------------------------------
2 *
3 * pg_operator.c
4 * routines to support manipulation of the pg_operator relation
5 *
6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/catalog/pg_operator.c
12 *
13 * NOTES
14 * these routines moved here from commands/define.c and somewhat cleaned up.
15 *
16 *-------------------------------------------------------------------------
17 */
18#include "postgres.h"
19
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"
39
40
41static Oid OperatorGet(const char *operatorName,
42 Oid operatorNamespace,
43 Oid leftObjectId,
44 Oid rightObjectId,
45 bool *defined);
46
47static Oid OperatorLookup(List *operatorName,
48 Oid leftObjectId,
49 Oid rightObjectId,
50 bool *defined);
51
52static Oid OperatorShellMake(const char *operatorName,
53 Oid operatorNamespace,
54 Oid leftTypeId,
55 Oid rightTypeId);
56
57static Oid get_other_operator(List *otherOp,
58 Oid otherLeftTypeId, Oid otherRightTypeId,
59 const char *operatorName, Oid operatorNamespace,
60 Oid leftTypeId, Oid rightTypeId,
61 bool isCommutator);
62
63
64/*
65 * Check whether a proposed operator name is legal
66 *
67 * This had better match the behavior of parser/scan.l!
68 *
69 * We need this because the parser is not smart enough to check that
70 * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
71 * are operator names rather than some other lexical entity.
72 */
73static bool
74validOperatorName(const char *name)
75{
76 size_t len = strlen(name);
77
78 /* Can't be empty or too long */
79 if (len == 0 || len >= NAMEDATALEN)
80 return false;
81
82 /* Can't contain any invalid characters */
83 /* Test string here should match op_chars in scan.l */
84 if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
85 return false;
86
87 /* Can't contain slash-star or dash-dash (comment starts) */
88 if (strstr(name, "/*") || strstr(name, "--"))
89 return false;
90
91 /*
92 * For SQL standard compatibility, '+' and '-' cannot be the last char of
93 * a multi-char operator unless the operator contains chars that are not
94 * in SQL operators. The idea is to lex '=-' as two operators, but not to
95 * forbid operator names like '?-' that could not be sequences of standard
96 * SQL operators.
97 */
98 if (len > 1 &&
99 (name[len - 1] == '+' ||
100 name[len - 1] == '-'))
101 {
102 int ic;
103
104 for (ic = len - 2; ic >= 0; ic--)
105 {
106 if (strchr("~!@#^&|`?%", name[ic]))
107 break;
108 }
109 if (ic < 0)
110 return false; /* nope, not valid */
111 }
112
113 /* != isn't valid either, because parser will convert it to <> */
114 if (strcmp(name, "!=") == 0)
115 return false;
116
117 return true;
118}
119
120
121/*
122 * OperatorGet
123 *
124 * finds an operator given an exact specification (name, namespace,
125 * left and right type IDs).
126 *
127 * *defined is set true if defined (not a shell)
128 */
129static Oid
130OperatorGet(const char *operatorName,
131 Oid operatorNamespace,
132 Oid leftObjectId,
133 Oid rightObjectId,
134 bool *defined)
135{
136 HeapTuple tup;
137 Oid operatorObjectId;
138
139 tup = SearchSysCache4(OPERNAMENSP,
140 PointerGetDatum(operatorName),
141 ObjectIdGetDatum(leftObjectId),
142 ObjectIdGetDatum(rightObjectId),
143 ObjectIdGetDatum(operatorNamespace));
144 if (HeapTupleIsValid(tup))
145 {
146 Form_pg_operator oprform = (Form_pg_operator) GETSTRUCT(tup);
147
148 operatorObjectId = oprform->oid;
149 *defined = RegProcedureIsValid(oprform->oprcode);
150 ReleaseSysCache(tup);
151 }
152 else
153 {
154 operatorObjectId = InvalidOid;
155 *defined = false;
156 }
157
158 return operatorObjectId;
159}
160
161/*
162 * OperatorLookup
163 *
164 * looks up an operator given a possibly-qualified name and
165 * left and right type IDs.
166 *
167 * *defined is set true if defined (not a shell)
168 */
169static Oid
170OperatorLookup(List *operatorName,
171 Oid leftObjectId,
172 Oid rightObjectId,
173 bool *defined)
174{
175 Oid operatorObjectId;
176 RegProcedure oprcode;
177
178 operatorObjectId = LookupOperName(NULL, operatorName,
179 leftObjectId, rightObjectId,
180 true, -1);
181 if (!OidIsValid(operatorObjectId))
182 {
183 *defined = false;
184 return InvalidOid;
185 }
186
187 oprcode = get_opcode(operatorObjectId);
188 *defined = RegProcedureIsValid(oprcode);
189
190 return operatorObjectId;
191}
192
193
194/*
195 * OperatorShellMake
196 * Make a "shell" entry for a not-yet-existing operator.
197 */
198static Oid
199OperatorShellMake(const char *operatorName,
200 Oid operatorNamespace,
201 Oid leftTypeId,
202 Oid rightTypeId)
203{
204 Relation pg_operator_desc;
205 Oid operatorObjectId;
206 int i;
207 HeapTuple tup;
208 Datum values[Natts_pg_operator];
209 bool nulls[Natts_pg_operator];
210 NameData oname;
211 TupleDesc tupDesc;
212
213 /*
214 * validate operator name
215 */
216 if (!validOperatorName(operatorName))
217 ereport(ERROR,
218 (errcode(ERRCODE_INVALID_NAME),
219 errmsg("\"%s\" is not a valid operator name",
220 operatorName)));
221
222 /*
223 * open pg_operator
224 */
225 pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
226 tupDesc = pg_operator_desc->rd_att;
227
228 /*
229 * initialize our *nulls and *values arrays
230 */
231 for (i = 0; i < Natts_pg_operator; ++i)
232 {
233 nulls[i] = false;
234 values[i] = (Datum) NULL; /* redundant, but safe */
235 }
236
237 /*
238 * initialize values[] with the operator name and input data types. Note
239 * that oprcode is set to InvalidOid, indicating it's a shell.
240 */
241 operatorObjectId = GetNewOidWithIndex(pg_operator_desc, OperatorOidIndexId,
242 Anum_pg_operator_oid);
243 values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
244 namestrcpy(&oname, operatorName);
245 values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
246 values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
247 values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
248 values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
249 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
250 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
251 values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
252 values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
253 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
254 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
255 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
256 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
257 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
258 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
259
260 /*
261 * create a new operator tuple
262 */
263 tup = heap_form_tuple(tupDesc, values, nulls);
264
265 /*
266 * insert our "shell" operator tuple
267 */
268 CatalogTupleInsert(pg_operator_desc, tup);
269
270 /* Add dependencies for the entry */
271 makeOperatorDependencies(tup, false);
272
273 heap_freetuple(tup);
274
275 /* Post creation hook for new shell operator */
276 InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
277
278 /*
279 * Make sure the tuple is visible for subsequent lookups/updates.
280 */
281 CommandCounterIncrement();
282
283 /*
284 * close the operator relation and return the oid.
285 */
286 table_close(pg_operator_desc, RowExclusiveLock);
287
288 return operatorObjectId;
289}
290
291/*
292 * OperatorCreate
293 *
294 * "X" indicates an optional argument (i.e. one that can be NULL or 0)
295 * operatorName name for new operator
296 * operatorNamespace namespace for new operator
297 * leftTypeId X left type ID
298 * rightTypeId X right type ID
299 * procedureId procedure ID for operator
300 * commutatorName X commutator operator
301 * negatorName X negator operator
302 * restrictionId X restriction selectivity procedure ID
303 * joinId X join selectivity procedure ID
304 * canMerge merge join can be used with this operator
305 * canHash hash join can be used with this operator
306 *
307 * The caller should have validated properties and permissions for the
308 * objects passed as OID references. We must handle the commutator and
309 * negator operator references specially, however, since those need not
310 * exist beforehand.
311 *
312 * This routine gets complicated because it allows the user to
313 * specify operators that do not exist. For example, if operator
314 * "op" is being defined, the negator operator "negop" and the
315 * commutator "commop" can also be defined without specifying
316 * any information other than their names. Since in order to
317 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
318 * operators must be placed in the fields of "op", a forward
319 * declaration is done on the commutator and negator operators.
320 * This is called creating a shell, and its main effect is to
321 * create a tuple in the PG_OPERATOR catalog with minimal
322 * information about the operator (just its name and types).
323 * Forward declaration is used only for this purpose, it is
324 * not available to the user as it is for type definition.
325 */
326ObjectAddress
327OperatorCreate(const char *operatorName,
328 Oid operatorNamespace,
329 Oid leftTypeId,
330 Oid rightTypeId,
331 Oid procedureId,
332 List *commutatorName,
333 List *negatorName,
334 Oid restrictionId,
335 Oid joinId,
336 bool canMerge,
337 bool canHash)
338{
339 Relation pg_operator_desc;
340 HeapTuple tup;
341 bool isUpdate;
342 bool nulls[Natts_pg_operator];
343 bool replaces[Natts_pg_operator];
344 Datum values[Natts_pg_operator];
345 Oid operatorObjectId;
346 bool operatorAlreadyDefined;
347 Oid operResultType;
348 Oid commutatorId,
349 negatorId;
350 bool selfCommutator = false;
351 NameData oname;
352 int i;
353 ObjectAddress address;
354
355 /*
356 * Sanity checks
357 */
358 if (!validOperatorName(operatorName))
359 ereport(ERROR,
360 (errcode(ERRCODE_INVALID_NAME),
361 errmsg("\"%s\" is not a valid operator name",
362 operatorName)));
363
364 if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
365 {
366 /* If it's not a binary op, these things mustn't be set: */
367 if (commutatorName)
368 ereport(ERROR,
369 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
370 errmsg("only binary operators can have commutators")));
371 if (OidIsValid(joinId))
372 ereport(ERROR,
373 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
374 errmsg("only binary operators can have join selectivity")));
375 if (canMerge)
376 ereport(ERROR,
377 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
378 errmsg("only binary operators can merge join")));
379 if (canHash)
380 ereport(ERROR,
381 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
382 errmsg("only binary operators can hash")));
383 }
384
385 operResultType = get_func_rettype(procedureId);
386
387 if (operResultType != BOOLOID)
388 {
389 /* If it's not a boolean op, these things mustn't be set: */
390 if (negatorName)
391 ereport(ERROR,
392 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
393 errmsg("only boolean operators can have negators")));
394 if (OidIsValid(restrictionId))
395 ereport(ERROR,
396 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
397 errmsg("only boolean operators can have restriction selectivity")));
398 if (OidIsValid(joinId))
399 ereport(ERROR,
400 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
401 errmsg("only boolean operators can have join selectivity")));
402 if (canMerge)
403 ereport(ERROR,
404 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
405 errmsg("only boolean operators can merge join")));
406 if (canHash)
407 ereport(ERROR,
408 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
409 errmsg("only boolean operators can hash")));
410 }
411
412 operatorObjectId = OperatorGet(operatorName,
413 operatorNamespace,
414 leftTypeId,
415 rightTypeId,
416 &operatorAlreadyDefined);
417
418 if (operatorAlreadyDefined)
419 ereport(ERROR,
420 (errcode(ERRCODE_DUPLICATE_FUNCTION),
421 errmsg("operator %s already exists",
422 operatorName)));
423
424 /*
425 * At this point, if operatorObjectId is not InvalidOid then we are
426 * filling in a previously-created shell. Insist that the user own any
427 * such shell.
428 */
429 if (OidIsValid(operatorObjectId) &&
430 !pg_oper_ownercheck(operatorObjectId, GetUserId()))
431 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
432 operatorName);
433
434 /*
435 * Set up the other operators. If they do not currently exist, create
436 * shells in order to get ObjectId's.
437 */
438
439 if (commutatorName)
440 {
441 /* commutator has reversed arg types */
442 commutatorId = get_other_operator(commutatorName,
443 rightTypeId, leftTypeId,
444 operatorName, operatorNamespace,
445 leftTypeId, rightTypeId,
446 true);
447
448 /* Permission check: must own other operator */
449 if (OidIsValid(commutatorId) &&
450 !pg_oper_ownercheck(commutatorId, GetUserId()))
451 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
452 NameListToString(commutatorName));
453
454 /*
455 * self-linkage to this operator; will fix below. Note that only
456 * self-linkage for commutation makes sense.
457 */
458 if (!OidIsValid(commutatorId))
459 selfCommutator = true;
460 }
461 else
462 commutatorId = InvalidOid;
463
464 if (negatorName)
465 {
466 /* negator has same arg types */
467 negatorId = get_other_operator(negatorName,
468 leftTypeId, rightTypeId,
469 operatorName, operatorNamespace,
470 leftTypeId, rightTypeId,
471 false);
472
473 /* Permission check: must own other operator */
474 if (OidIsValid(negatorId) &&
475 !pg_oper_ownercheck(negatorId, GetUserId()))
476 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
477 NameListToString(negatorName));
478 }
479 else
480 negatorId = InvalidOid;
481
482 /*
483 * set up values in the operator tuple
484 */
485
486 for (i = 0; i < Natts_pg_operator; ++i)
487 {
488 values[i] = (Datum) NULL;
489 replaces[i] = true;
490 nulls[i] = false;
491 }
492
493 namestrcpy(&oname, operatorName);
494 values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
495 values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
496 values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
497 values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
498 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
499 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
500 values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
501 values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
502 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
503 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
504 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
505 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
506 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
507 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
508
509 pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
510
511 /*
512 * If we are replacing an operator shell, update; else insert
513 */
514 if (operatorObjectId)
515 {
516 isUpdate = true;
517
518 tup = SearchSysCacheCopy1(OPEROID,
519 ObjectIdGetDatum(operatorObjectId));
520 if (!HeapTupleIsValid(tup))
521 elog(ERROR, "cache lookup failed for operator %u",
522 operatorObjectId);
523
524 replaces[Anum_pg_operator_oid - 1] = false;
525 tup = heap_modify_tuple(tup,
526 RelationGetDescr(pg_operator_desc),
527 values,
528 nulls,
529 replaces);
530
531 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
532 }
533 else
534 {
535 isUpdate = false;
536
537 operatorObjectId = GetNewOidWithIndex(pg_operator_desc,
538 OperatorOidIndexId,
539 Anum_pg_operator_oid);
540 values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
541
542 tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
543 values, nulls);
544
545 CatalogTupleInsert(pg_operator_desc, tup);
546 }
547
548 /* Add dependencies for the entry */
549 address = makeOperatorDependencies(tup, isUpdate);
550
551 /* Post creation hook for new operator */
552 InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
553
554 table_close(pg_operator_desc, RowExclusiveLock);
555
556 /*
557 * If a commutator and/or negator link is provided, update the other
558 * operator(s) to point at this one, if they don't already have a link.
559 * This supports an alternative style of operator definition wherein the
560 * user first defines one operator without giving negator or commutator,
561 * then defines the other operator of the pair with the proper commutator
562 * or negator attribute. That style doesn't require creation of a shell,
563 * and it's the only style that worked right before Postgres version 6.5.
564 * This code also takes care of the situation where the new operator is
565 * its own commutator.
566 */
567 if (selfCommutator)
568 commutatorId = operatorObjectId;
569
570 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
571 OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
572
573 return address;
574}
575
576/*
577 * Try to lookup another operator (commutator, etc)
578 *
579 * If not found, check to see if it is exactly the operator we are trying
580 * to define; if so, return InvalidOid. (Note that this case is only
581 * sensible for a commutator, so we error out otherwise.) If it is not
582 * the same operator, create a shell operator.
583 */
584static Oid
585get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
586 const char *operatorName, Oid operatorNamespace,
587 Oid leftTypeId, Oid rightTypeId, bool isCommutator)
588{
589 Oid other_oid;
590 bool otherDefined;
591 char *otherName;
592 Oid otherNamespace;
593 AclResult aclresult;
594
595 other_oid = OperatorLookup(otherOp,
596 otherLeftTypeId,
597 otherRightTypeId,
598 &otherDefined);
599
600 if (OidIsValid(other_oid))
601 {
602 /* other op already in catalogs */
603 return other_oid;
604 }
605
606 otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
607 &otherName);
608
609 if (strcmp(otherName, operatorName) == 0 &&
610 otherNamespace == operatorNamespace &&
611 otherLeftTypeId == leftTypeId &&
612 otherRightTypeId == rightTypeId)
613 {
614 /*
615 * self-linkage to this operator; caller will fix later. Note that
616 * only self-linkage for commutation makes sense.
617 */
618 if (!isCommutator)
619 ereport(ERROR,
620 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
621 errmsg("operator cannot be its own negator or sort operator")));
622 return InvalidOid;
623 }
624
625 /* not in catalogs, different from operator, so make shell */
626
627 aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
628 ACL_CREATE);
629 if (aclresult != ACLCHECK_OK)
630 aclcheck_error(aclresult, OBJECT_SCHEMA,
631 get_namespace_name(otherNamespace));
632
633 other_oid = OperatorShellMake(otherName,
634 otherNamespace,
635 otherLeftTypeId,
636 otherRightTypeId);
637 return other_oid;
638}
639
640/*
641 * OperatorUpd
642 *
643 * For a given operator, look up its negator and commutator operators.
644 * When isDelete is false, update their negator and commutator fields to
645 * point back to the given operator; when isDelete is true, update those
646 * fields to no longer point back to the given operator.
647 *
648 * The !isDelete case solves a problem for users who need to insert two new
649 * operators that are the negator or commutator of each other, while the
650 * isDelete case is needed so as not to leave dangling OID links behind
651 * after dropping an operator.
652 */
653void
654OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
655{
656 Relation pg_operator_desc;
657 HeapTuple tup;
658
659 /*
660 * If we're making an operator into its own commutator, then we need a
661 * command-counter increment here, since we've just inserted the tuple
662 * we're about to update. But when we're dropping an operator, we can
663 * skip this because we're at the beginning of the command.
664 */
665 if (!isDelete)
666 CommandCounterIncrement();
667
668 /* Open the relation. */
669 pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
670
671 /* Get a writable copy of the commutator's tuple. */
672 if (OidIsValid(commId))
673 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
674 else
675 tup = NULL;
676
677 /* Update the commutator's tuple if need be. */
678 if (HeapTupleIsValid(tup))
679 {
680 Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
681 bool update_commutator = false;
682
683 /*
684 * Out of due caution, we only change the commutator's oprcom field if
685 * it has the exact value we expected: InvalidOid when creating an
686 * operator, or baseId when dropping one.
687 */
688 if (isDelete && t->oprcom == baseId)
689 {
690 t->oprcom = InvalidOid;
691 update_commutator = true;
692 }
693 else if (!isDelete && !OidIsValid(t->oprcom))
694 {
695 t->oprcom = baseId;
696 update_commutator = true;
697 }
698
699 /* If any columns were found to need modification, update tuple. */
700 if (update_commutator)
701 {
702 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
703
704 /*
705 * Do CCI to make the updated tuple visible. We must do this in
706 * case the commutator is also the negator. (Which would be a
707 * logic error on the operator definer's part, but that's not a
708 * good reason to fail here.) We would need a CCI anyway in the
709 * deletion case for a self-commutator with no negator.
710 */
711 CommandCounterIncrement();
712 }
713 }
714
715 /*
716 * Similarly find and update the negator, if any.
717 */
718 if (OidIsValid(negId))
719 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
720 else
721 tup = NULL;
722
723 if (HeapTupleIsValid(tup))
724 {
725 Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
726 bool update_negator = false;
727
728 /*
729 * Out of due caution, we only change the negator's oprnegate field if
730 * it has the exact value we expected: InvalidOid when creating an
731 * operator, or baseId when dropping one.
732 */
733 if (isDelete && t->oprnegate == baseId)
734 {
735 t->oprnegate = InvalidOid;
736 update_negator = true;
737 }
738 else if (!isDelete && !OidIsValid(t->oprnegate))
739 {
740 t->oprnegate = baseId;
741 update_negator = true;
742 }
743
744 /* If any columns were found to need modification, update tuple. */
745 if (update_negator)
746 {
747 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
748
749 /*
750 * In the deletion case, do CCI to make the updated tuple visible.
751 * We must do this in case the operator is its own negator. (Which
752 * would be a logic error on the operator definer's part, but
753 * that's not a good reason to fail here.)
754 */
755 if (isDelete)
756 CommandCounterIncrement();
757 }
758 }
759
760 /* Close relation and release catalog lock. */
761 table_close(pg_operator_desc, RowExclusiveLock);
762}
763
764/*
765 * Create dependencies for an operator (either a freshly inserted
766 * complete operator, a new shell operator, a just-updated shell,
767 * or an operator that's being modified by ALTER OPERATOR).
768 *
769 * NB: the OidIsValid tests in this routine are necessary, in case
770 * the given operator is a shell.
771 */
772ObjectAddress
773makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
774{
775 Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
776 ObjectAddress myself,
777 referenced;
778
779 myself.classId = OperatorRelationId;
780 myself.objectId = oper->oid;
781 myself.objectSubId = 0;
782
783 /*
784 * If we are updating the operator, delete any existing entries, except
785 * for extension membership which should remain the same.
786 */
787 if (isUpdate)
788 {
789 deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
790 deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
791 }
792
793 /* Dependency on namespace */
794 if (OidIsValid(oper->oprnamespace))
795 {
796 referenced.classId = NamespaceRelationId;
797 referenced.objectId = oper->oprnamespace;
798 referenced.objectSubId = 0;
799 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
800 }
801
802 /* Dependency on left type */
803 if (OidIsValid(oper->oprleft))
804 {
805 referenced.classId = TypeRelationId;
806 referenced.objectId = oper->oprleft;
807 referenced.objectSubId = 0;
808 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
809 }
810
811 /* Dependency on right type */
812 if (OidIsValid(oper->oprright))
813 {
814 referenced.classId = TypeRelationId;
815 referenced.objectId = oper->oprright;
816 referenced.objectSubId = 0;
817 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
818 }
819
820 /* Dependency on result type */
821 if (OidIsValid(oper->oprresult))
822 {
823 referenced.classId = TypeRelationId;
824 referenced.objectId = oper->oprresult;
825 referenced.objectSubId = 0;
826 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
827 }
828
829 /*
830 * NOTE: we do not consider the operator to depend on the associated
831 * operators oprcom and oprnegate. We would not want to delete this
832 * operator if those go away, but only reset the link fields; which is not
833 * a function that the dependency code can presently handle. (Something
834 * could perhaps be done with objectSubId though.) For now, it's okay to
835 * let those links dangle if a referenced operator is removed.
836 */
837
838 /* Dependency on implementation function */
839 if (OidIsValid(oper->oprcode))
840 {
841 referenced.classId = ProcedureRelationId;
842 referenced.objectId = oper->oprcode;
843 referenced.objectSubId = 0;
844 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
845 }
846
847 /* Dependency on restriction selectivity function */
848 if (OidIsValid(oper->oprrest))
849 {
850 referenced.classId = ProcedureRelationId;
851 referenced.objectId = oper->oprrest;
852 referenced.objectSubId = 0;
853 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
854 }
855
856 /* Dependency on join selectivity function */
857 if (OidIsValid(oper->oprjoin))
858 {
859 referenced.classId = ProcedureRelationId;
860 referenced.objectId = oper->oprjoin;
861 referenced.objectSubId = 0;
862 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
863 }
864
865 /* Dependency on owner */
866 recordDependencyOnOwner(OperatorRelationId, oper->oid,
867 oper->oprowner);
868
869 /* Dependency on extension */
870 recordDependencyOnCurrentExtension(&myself, true);
871
872 return myself;
873}
874