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