]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_operator.c
Fix initialization of fake LSN for unlogged relations
[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-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
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                 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  */
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          * 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  */
326 ObjectAddress
327 OperatorCreate(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  */
584 static Oid
585 get_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  */
653 void
654 OperatorUpd(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  */
772 ObjectAddress
773 makeOperatorDependencies(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 }