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