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