]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_operator.c
Fix handling of extension membership when filling in a shell operator.
[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-2011, 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/xact.h"
22 #include "catalog/dependency.h"
23 #include "catalog/indexing.h"
24 #include "catalog/namespace.h"
25 #include "catalog/objectaccess.h"
26 #include "catalog/pg_namespace.h"
27 #include "catalog/pg_operator.h"
28 #include "catalog/pg_proc.h"
29 #include "catalog/pg_type.h"
30 #include "miscadmin.h"
31 #include "parser/parse_oper.h"
32 #include "utils/acl.h"
33 #include "utils/builtins.h"
34 #include "utils/lsyscache.h"
35 #include "utils/rel.h"
36 #include "utils/syscache.h"
37
38
39 static Oid OperatorGet(const char *operatorName,
40                         Oid operatorNamespace,
41                         Oid leftObjectId,
42                         Oid rightObjectId,
43                         bool *defined);
44
45 static Oid OperatorLookup(List *operatorName,
46                            Oid leftObjectId,
47                            Oid rightObjectId,
48                            bool *defined);
49
50 static Oid OperatorShellMake(const char *operatorName,
51                                   Oid operatorNamespace,
52                                   Oid leftTypeId,
53                                   Oid rightTypeId);
54
55 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
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 static void makeOperatorDependencies(HeapTuple tuple);
64
65
66 /*
67  * Check whether a proposed operator name is legal
68  *
69  * This had better match the behavior of parser/scan.l!
70  *
71  * We need this because the parser is not smart enough to check that
72  * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
73  * are operator names rather than some other lexical entity.
74  */
75 static bool
76 validOperatorName(const char *name)
77 {
78         size_t          len = strlen(name);
79
80         /* Can't be empty or too long */
81         if (len == 0 || len >= NAMEDATALEN)
82                 return false;
83
84         /* Can't contain any invalid characters */
85         /* Test string here should match op_chars in scan.l */
86         if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
87                 return false;
88
89         /* Can't contain slash-star or dash-dash (comment starts) */
90         if (strstr(name, "/*") || strstr(name, "--"))
91                 return false;
92
93         /*
94          * For SQL92 compatibility, '+' and '-' cannot be the last char of a
95          * multi-char operator unless the operator contains chars that are not in
96          * SQL92 operators. The idea is to lex '=-' as two operators, but not to
97          * forbid operator names like '?-' that could not be sequences of SQL92
98          * operators.
99          */
100         if (len > 1 &&
101                 (name[len - 1] == '+' ||
102                  name[len - 1] == '-'))
103         {
104                 int                     ic;
105
106                 for (ic = len - 2; ic >= 0; ic--)
107                 {
108                         if (strchr("~!@#^&|`?%", name[ic]))
109                                 break;
110                 }
111                 if (ic < 0)
112                         return false;           /* nope, not valid */
113         }
114
115         /* != isn't valid either, because parser will convert it to <> */
116         if (strcmp(name, "!=") == 0)
117                 return false;
118
119         return true;
120 }
121
122
123 /*
124  * OperatorGet
125  *
126  *              finds an operator given an exact specification (name, namespace,
127  *              left and right type IDs).
128  *
129  *              *defined is set TRUE if defined (not a shell)
130  */
131 static Oid
132 OperatorGet(const char *operatorName,
133                         Oid operatorNamespace,
134                         Oid leftObjectId,
135                         Oid rightObjectId,
136                         bool *defined)
137 {
138         HeapTuple       tup;
139         Oid                     operatorObjectId;
140
141         tup = SearchSysCache4(OPERNAMENSP,
142                                                   PointerGetDatum(operatorName),
143                                                   ObjectIdGetDatum(leftObjectId),
144                                                   ObjectIdGetDatum(rightObjectId),
145                                                   ObjectIdGetDatum(operatorNamespace));
146         if (HeapTupleIsValid(tup))
147         {
148                 RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
149
150                 operatorObjectId = HeapTupleGetOid(tup);
151                 *defined = RegProcedureIsValid(oprcode);
152                 ReleaseSysCache(tup);
153         }
154         else
155         {
156                 operatorObjectId = InvalidOid;
157                 *defined = false;
158         }
159
160         return operatorObjectId;
161 }
162
163 /*
164  * OperatorLookup
165  *
166  *              looks up an operator given a possibly-qualified name and
167  *              left and right type IDs.
168  *
169  *              *defined is set TRUE if defined (not a shell)
170  */
171 static Oid
172 OperatorLookup(List *operatorName,
173                            Oid leftObjectId,
174                            Oid rightObjectId,
175                            bool *defined)
176 {
177         Oid                     operatorObjectId;
178         RegProcedure oprcode;
179
180         operatorObjectId = LookupOperName(NULL, operatorName,
181                                                                           leftObjectId, rightObjectId,
182                                                                           true, -1);
183         if (!OidIsValid(operatorObjectId))
184         {
185                 *defined = false;
186                 return InvalidOid;
187         }
188
189         oprcode = get_opcode(operatorObjectId);
190         *defined = RegProcedureIsValid(oprcode);
191
192         return operatorObjectId;
193 }
194
195
196 /*
197  * OperatorShellMake
198  *              Make a "shell" entry for a not-yet-existing operator.
199  */
200 static Oid
201 OperatorShellMake(const char *operatorName,
202                                   Oid operatorNamespace,
203                                   Oid leftTypeId,
204                                   Oid rightTypeId)
205 {
206         Relation        pg_operator_desc;
207         Oid                     operatorObjectId;
208         int                     i;
209         HeapTuple       tup;
210         Datum           values[Natts_pg_operator];
211         bool            nulls[Natts_pg_operator];
212         NameData        oname;
213         TupleDesc       tupDesc;
214
215         /*
216          * validate operator name
217          */
218         if (!validOperatorName(operatorName))
219                 ereport(ERROR,
220                                 (errcode(ERRCODE_INVALID_NAME),
221                                  errmsg("\"%s\" is not a valid operator name",
222                                                 operatorName)));
223
224         /*
225          * initialize our *nulls and *values arrays
226          */
227         for (i = 0; i < Natts_pg_operator; ++i)
228         {
229                 nulls[i] = false;
230                 values[i] = (Datum) NULL;               /* redundant, but safe */
231         }
232
233         /*
234          * initialize values[] with the operator name and input data types. Note
235          * that oprcode is set to InvalidOid, indicating it's a shell.
236          */
237         namestrcpy(&oname, operatorName);
238         values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
239         values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
240         values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
241         values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
242         values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
243         values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
244         values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
245         values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
246         values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
247         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
248         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
249         values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
250         values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
251         values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
252
253         /*
254          * open pg_operator
255          */
256         pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
257         tupDesc = pg_operator_desc->rd_att;
258
259         /*
260          * create a new operator tuple
261          */
262         tup = heap_form_tuple(tupDesc, values, nulls);
263
264         /*
265          * insert our "shell" operator tuple
266          */
267         operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
268
269         CatalogUpdateIndexes(pg_operator_desc, tup);
270
271         /* Add dependencies for the entry */
272         makeOperatorDependencies(tup);
273
274         heap_freetuple(tup);
275
276         /* Post creation hook for new shell operator */
277         InvokeObjectAccessHook(OAT_POST_CREATE,
278                                                    OperatorRelationId, operatorObjectId, 0);
279
280         /*
281          * Make sure the tuple is visible for subsequent lookups/updates.
282          */
283         CommandCounterIncrement();
284
285         /*
286          * close the operator relation and return the oid.
287          */
288         heap_close(pg_operator_desc, RowExclusiveLock);
289
290         return operatorObjectId;
291 }
292
293 /*
294  * OperatorCreate
295  *
296  * "X" indicates an optional argument (i.e. one that can be NULL or 0)
297  *              operatorName                    name for new operator
298  *              operatorNamespace               namespace for new operator
299  *              leftTypeId                              X left type ID
300  *              rightTypeId                             X right type ID
301  *              procedureId                             procedure ID for operator
302  *              commutatorName                  X commutator operator
303  *              negatorName                             X negator operator
304  *              restrictionId                   X restriction selectivity procedure ID
305  *              joinId                                  X join selectivity procedure ID
306  *              canMerge                                merge join can be used with this operator
307  *              canHash                                 hash join can be used with this operator
308  *
309  * The caller should have validated properties and permissions for the
310  * objects passed as OID references.  We must handle the commutator and
311  * negator operator references specially, however, since those need not
312  * exist beforehand.
313  *
314  * This routine gets complicated because it allows the user to
315  * specify operators that do not exist.  For example, if operator
316  * "op" is being defined, the negator operator "negop" and the
317  * commutator "commop" can also be defined without specifying
318  * any information other than their names.      Since in order to
319  * add "op" to the PG_OPERATOR catalog, all the Oid's for these
320  * operators must be placed in the fields of "op", a forward
321  * declaration is done on the commutator and negator operators.
322  * This is called creating a shell, and its main effect is to
323  * create a tuple in the PG_OPERATOR catalog with minimal
324  * information about the operator (just its name and types).
325  * Forward declaration is used only for this purpose, it is
326  * not available to the user as it is for type definition.
327  */
328 void
329 OperatorCreate(const char *operatorName,
330                            Oid operatorNamespace,
331                            Oid leftTypeId,
332                            Oid rightTypeId,
333                            Oid procedureId,
334                            List *commutatorName,
335                            List *negatorName,
336                            Oid restrictionId,
337                            Oid joinId,
338                            bool canMerge,
339                            bool canHash)
340 {
341         Relation        pg_operator_desc;
342         HeapTuple       tup;
343         bool            nulls[Natts_pg_operator];
344         bool            replaces[Natts_pg_operator];
345         Datum           values[Natts_pg_operator];
346         Oid                     operatorObjectId;
347         bool            operatorAlreadyDefined;
348         Oid                     operResultType;
349         Oid                     commutatorId,
350                                 negatorId;
351         bool            selfCommutator = false;
352         NameData        oname;
353         TupleDesc       tupDesc;
354         int                     i;
355
356         /*
357          * Sanity checks
358          */
359         if (!validOperatorName(operatorName))
360                 ereport(ERROR,
361                                 (errcode(ERRCODE_INVALID_NAME),
362                                  errmsg("\"%s\" is not a valid operator name",
363                                                 operatorName)));
364
365         if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
366         {
367                 /* If it's not a binary op, these things mustn't be set: */
368                 if (commutatorName)
369                         ereport(ERROR,
370                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
371                                          errmsg("only binary operators can have commutators")));
372                 if (OidIsValid(joinId))
373                         ereport(ERROR,
374                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
375                                  errmsg("only binary operators can have join selectivity")));
376                 if (canMerge)
377                         ereport(ERROR,
378                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
379                                          errmsg("only binary operators can merge join")));
380                 if (canHash)
381                         ereport(ERROR,
382                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
383                                          errmsg("only binary operators can hash")));
384         }
385
386         operResultType = get_func_rettype(procedureId);
387
388         if (operResultType != BOOLOID)
389         {
390                 /* If it's not a boolean op, these things mustn't be set: */
391                 if (negatorName)
392                         ereport(ERROR,
393                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
394                                          errmsg("only boolean operators can have negators")));
395                 if (OidIsValid(restrictionId))
396                         ereport(ERROR,
397                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
398                                          errmsg("only boolean operators can have restriction selectivity")));
399                 if (OidIsValid(joinId))
400                         ereport(ERROR,
401                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
402                                 errmsg("only boolean operators can have join selectivity")));
403                 if (canMerge)
404                         ereport(ERROR,
405                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
406                                          errmsg("only boolean operators can merge join")));
407                 if (canHash)
408                         ereport(ERROR,
409                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
410                                          errmsg("only boolean operators can hash")));
411         }
412
413         operatorObjectId = OperatorGet(operatorName,
414                                                                    operatorNamespace,
415                                                                    leftTypeId,
416                                                                    rightTypeId,
417                                                                    &operatorAlreadyDefined);
418
419         if (operatorAlreadyDefined)
420                 ereport(ERROR,
421                                 (errcode(ERRCODE_DUPLICATE_FUNCTION),
422                                  errmsg("operator %s already exists",
423                                                 operatorName)));
424
425         /*
426          * At this point, if operatorObjectId is not InvalidOid then we are
427          * filling in a previously-created shell.  Insist that the user own any
428          * such shell.
429          */
430         if (OidIsValid(operatorObjectId) &&
431                 !pg_oper_ownercheck(operatorObjectId, GetUserId()))
432                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
433                                            operatorName);
434
435         /*
436          * Set up the other operators.  If they do not currently exist, create
437          * shells in order to get ObjectId's.
438          */
439
440         if (commutatorName)
441         {
442                 /* commutator has reversed arg types */
443                 commutatorId = get_other_operator(commutatorName,
444                                                                                   rightTypeId, leftTypeId,
445                                                                                   operatorName, operatorNamespace,
446                                                                                   leftTypeId, rightTypeId,
447                                                                                   true);
448
449                 /* Permission check: must own other operator */
450                 if (OidIsValid(commutatorId) &&
451                         !pg_oper_ownercheck(commutatorId, GetUserId()))
452                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
453                                                    NameListToString(commutatorName));
454
455                 /*
456                  * self-linkage to this operator; will fix below. Note that only
457                  * self-linkage for commutation makes sense.
458                  */
459                 if (!OidIsValid(commutatorId))
460                         selfCommutator = true;
461         }
462         else
463                 commutatorId = InvalidOid;
464
465         if (negatorName)
466         {
467                 /* negator has same arg types */
468                 negatorId = get_other_operator(negatorName,
469                                                                            leftTypeId, rightTypeId,
470                                                                            operatorName, operatorNamespace,
471                                                                            leftTypeId, rightTypeId,
472                                                                            false);
473
474                 /* Permission check: must own other operator */
475                 if (OidIsValid(negatorId) &&
476                         !pg_oper_ownercheck(negatorId, GetUserId()))
477                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
478                                                    NameListToString(negatorName));
479         }
480         else
481                 negatorId = InvalidOid;
482
483         /*
484          * set up values in the operator tuple
485          */
486
487         for (i = 0; i < Natts_pg_operator; ++i)
488         {
489                 values[i] = (Datum) NULL;
490                 replaces[i] = true;
491                 nulls[i] = false;
492         }
493
494         namestrcpy(&oname, operatorName);
495         values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
496         values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
497         values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
498         values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
499         values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
500         values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
501         values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
502         values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
503         values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
504         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
505         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
506         values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
507         values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
508         values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
509
510         pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
511
512         /*
513          * If we are replacing an operator shell, update; else insert
514          */
515         if (operatorObjectId)
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                 tupDesc = pg_operator_desc->rd_att;
534                 tup = heap_form_tuple(tupDesc, values, nulls);
535
536                 operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
537         }
538
539         /* Must update the indexes in either case */
540         CatalogUpdateIndexes(pg_operator_desc, tup);
541
542         /* Add dependencies for the entry */
543         makeOperatorDependencies(tup);
544
545         /* Post creation hook for new operator */
546         InvokeObjectAccessHook(OAT_POST_CREATE,
547                                                    OperatorRelationId, operatorObjectId, 0);
548
549         heap_close(pg_operator_desc, RowExclusiveLock);
550
551         /*
552          * If a commutator and/or negator link is provided, update the other
553          * operator(s) to point at this one, if they don't already have a link.
554          * This supports an alternative style of operator definition wherein the
555          * user first defines one operator without giving negator or commutator,
556          * then defines the other operator of the pair with the proper commutator
557          * or negator attribute.  That style doesn't require creation of a shell,
558          * and it's the only style that worked right before Postgres version 6.5.
559          * This code also takes care of the situation where the new operator is
560          * its own commutator.
561          */
562         if (selfCommutator)
563                 commutatorId = operatorObjectId;
564
565         if (OidIsValid(commutatorId) || OidIsValid(negatorId))
566                 OperatorUpd(operatorObjectId, commutatorId, negatorId);
567 }
568
569 /*
570  * Try to lookup another operator (commutator, etc)
571  *
572  * If not found, check to see if it is exactly the operator we are trying
573  * to define; if so, return InvalidOid.  (Note that this case is only
574  * sensible for a commutator, so we error out otherwise.)  If it is not
575  * the same operator, create a shell operator.
576  */
577 static Oid
578 get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
579                                    const char *operatorName, Oid operatorNamespace,
580                                    Oid leftTypeId, Oid rightTypeId, bool isCommutator)
581 {
582         Oid                     other_oid;
583         bool            otherDefined;
584         char       *otherName;
585         Oid                     otherNamespace;
586         AclResult       aclresult;
587
588         other_oid = OperatorLookup(otherOp,
589                                                            otherLeftTypeId,
590                                                            otherRightTypeId,
591                                                            &otherDefined);
592
593         if (OidIsValid(other_oid))
594         {
595                 /* other op already in catalogs */
596                 return other_oid;
597         }
598
599         otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
600                                                                                                            &otherName);
601
602         if (strcmp(otherName, operatorName) == 0 &&
603                 otherNamespace == operatorNamespace &&
604                 otherLeftTypeId == leftTypeId &&
605                 otherRightTypeId == rightTypeId)
606         {
607                 /*
608                  * self-linkage to this operator; caller will fix later. Note that
609                  * only self-linkage for commutation makes sense.
610                  */
611                 if (!isCommutator)
612                         ereport(ERROR,
613                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
614                          errmsg("operator cannot be its own negator or sort operator")));
615                 return InvalidOid;
616         }
617
618         /* not in catalogs, different from operator, so make shell */
619
620         aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
621                                                                           ACL_CREATE);
622         if (aclresult != ACLCHECK_OK)
623                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
624                                            get_namespace_name(otherNamespace));
625
626         other_oid = OperatorShellMake(otherName,
627                                                                   otherNamespace,
628                                                                   otherLeftTypeId,
629                                                                   otherRightTypeId);
630         return other_oid;
631 }
632
633 /*
634  * OperatorUpd
635  *
636  *      For a given operator, look up its negator and commutator operators.
637  *      If they are defined, but their negator and commutator fields
638  *      (respectively) are empty, then use the new operator for neg or comm.
639  *      This solves a problem for users who need to insert two new operators
640  *      which are the negator or commutator of each other.
641  */
642 static void
643 OperatorUpd(Oid baseId, Oid commId, Oid negId)
644 {
645         int                     i;
646         Relation        pg_operator_desc;
647         HeapTuple       tup;
648         bool            nulls[Natts_pg_operator];
649         bool            replaces[Natts_pg_operator];
650         Datum           values[Natts_pg_operator];
651
652         for (i = 0; i < Natts_pg_operator; ++i)
653         {
654                 values[i] = (Datum) 0;
655                 replaces[i] = false;
656                 nulls[i] = false;
657         }
658
659         /*
660          * check and update the commutator & negator, if necessary
661          *
662          * We need a CommandCounterIncrement here in case of a self-commutator
663          * operator: we'll need to update the tuple that we just inserted.
664          */
665         CommandCounterIncrement();
666
667         pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
668
669         tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
670
671         /*
672          * if the commutator and negator are the same operator, do one update. XXX
673          * this is probably useless code --- I doubt it ever makes sense for
674          * commutator and negator to be the same thing...
675          */
676         if (commId == negId)
677         {
678                 if (HeapTupleIsValid(tup))
679                 {
680                         Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
681
682                         if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
683                         {
684                                 if (!OidIsValid(t->oprnegate))
685                                 {
686                                         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
687                                         replaces[Anum_pg_operator_oprnegate - 1] = true;
688                                 }
689
690                                 if (!OidIsValid(t->oprcom))
691                                 {
692                                         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
693                                         replaces[Anum_pg_operator_oprcom - 1] = true;
694                                 }
695
696                                 tup = heap_modify_tuple(tup,
697                                                                                 RelationGetDescr(pg_operator_desc),
698                                                                                 values,
699                                                                                 nulls,
700                                                                                 replaces);
701
702                                 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
703
704                                 CatalogUpdateIndexes(pg_operator_desc, tup);
705                         }
706                 }
707
708                 heap_close(pg_operator_desc, RowExclusiveLock);
709
710                 return;
711         }
712
713         /* if commutator and negator are different, do two updates */
714
715         if (HeapTupleIsValid(tup) &&
716                 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
717         {
718                 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
719                 replaces[Anum_pg_operator_oprcom - 1] = true;
720
721                 tup = heap_modify_tuple(tup,
722                                                                 RelationGetDescr(pg_operator_desc),
723                                                                 values,
724                                                                 nulls,
725                                                                 replaces);
726
727                 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
728
729                 CatalogUpdateIndexes(pg_operator_desc, tup);
730
731                 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
732                 replaces[Anum_pg_operator_oprcom - 1] = false;
733         }
734
735         /* check and update the negator, if necessary */
736
737         tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
738
739         if (HeapTupleIsValid(tup) &&
740                 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
741         {
742                 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
743                 replaces[Anum_pg_operator_oprnegate - 1] = true;
744
745                 tup = heap_modify_tuple(tup,
746                                                                 RelationGetDescr(pg_operator_desc),
747                                                                 values,
748                                                                 nulls,
749                                                                 replaces);
750
751                 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
752
753                 CatalogUpdateIndexes(pg_operator_desc, tup);
754         }
755
756         heap_close(pg_operator_desc, RowExclusiveLock);
757 }
758
759 /*
760  * Create dependencies for a new operator (either a freshly inserted
761  * complete operator, a new shell operator, or a just-updated shell).
762  *
763  * NB: the OidIsValid tests in this routine are necessary, in case
764  * the given operator is a shell.
765  */
766 static void
767 makeOperatorDependencies(HeapTuple tuple)
768 {
769         Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
770         ObjectAddress myself,
771                                 referenced;
772
773         myself.classId = OperatorRelationId;
774         myself.objectId = HeapTupleGetOid(tuple);
775         myself.objectSubId = 0;
776
777         /*
778          * In case we are updating a shell, delete any existing entries, except
779          * for extension membership which should remain the same.
780          */
781         deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
782         deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
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 }