]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_operator.c
message refinements
[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-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.61 2001/08/10 15:49:39 petere Exp $
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 "catalog/catname.h"
22 #include "catalog/indexing.h"
23 #include "catalog/pg_operator.h"
24 #include "catalog/pg_proc.h"
25 #include "catalog/pg_type.h"
26 #include "miscadmin.h"
27 #include "parser/parse_func.h"
28 #include "utils/builtins.h"
29 #include "utils/fmgroids.h"
30 #include "utils/syscache.h"
31
32
33 static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
34                                                         const char *operatorName,
35                                                         Oid leftObjectId,
36                                                         Oid rightObjectId,
37                                                         bool *defined);
38
39 static Oid OperatorGet(char *operatorName,
40                         char *leftTypeName,
41                         char *rightTypeName,
42                         bool *defined);
43
44 static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
45                                                                   char *operatorName,
46                                                                   Oid leftObjectId,
47                                                                   Oid rightObjectId);
48
49 static Oid OperatorShellMake(char *operatorName,
50                                   char *leftTypeName,
51                                   char *rightTypeName);
52
53 static void OperatorDef(char *operatorName,
54                         char *leftTypeName,
55                         char *rightTypeName,
56                         char *procedureName,
57                         uint16 precedence,
58                         bool isLeftAssociative,
59                         char *commutatorName,
60                         char *negatorName,
61                         char *restrictionName,
62                         char *oinName,
63                         bool canHash,
64                         char *leftSortName,
65                         char *rightSortName);
66
67 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
68
69 /* ----------------------------------------------------------------
70  *              OperatorGetWithOpenRelation
71  *
72  *              performs a scan on pg_operator for an operator tuple
73  *              with given name and left/right type oids.
74  *
75  *        pg_operator_desc      -- reldesc for pg_operator
76  *        operatorName          -- name of operator to fetch
77  *        leftObjectId          -- left data type oid of operator to fetch
78  *        rightObjectId         -- right data type oid of operator to fetch
79  *        defined                       -- set TRUE if defined (not a shell)
80  * ----------------------------------------------------------------
81  */
82 static Oid
83 OperatorGetWithOpenRelation(Relation pg_operator_desc,
84                                                         const char *operatorName,
85                                                         Oid leftObjectId,
86                                                         Oid rightObjectId,
87                                                         bool *defined)
88 {
89         HeapScanDesc pg_operator_scan;
90         Oid                     operatorObjectId;
91         HeapTuple       tup;
92         ScanKeyData     opKey[3];
93
94         /*
95          * form scan key
96          */
97         ScanKeyEntryInitialize(&opKey[0], 0x0,
98                                                    Anum_pg_operator_oprname,
99                                                    F_NAMEEQ,
100                                                    PointerGetDatum(operatorName));
101         ScanKeyEntryInitialize(&opKey[1], 0x0,
102                                                    Anum_pg_operator_oprleft,
103                                                    F_OIDEQ,
104                                                    ObjectIdGetDatum(leftObjectId));
105         ScanKeyEntryInitialize(&opKey[2], 0x0,
106                                                    Anum_pg_operator_oprright,
107                                                    F_OIDEQ,
108                                                    ObjectIdGetDatum(rightObjectId));
109
110         /*
111          * begin the scan
112          */
113         pg_operator_scan = heap_beginscan(pg_operator_desc,
114                                                                           0,
115                                                                           SnapshotSelf,         /* no cache? */
116                                                                           3,
117                                                                           opKey);
118
119         /*
120          * fetch the operator tuple, if it exists, and determine the proper
121          * return oid value.
122          */
123         tup = heap_getnext(pg_operator_scan, 0);
124
125         if (HeapTupleIsValid(tup))
126         {
127                 regproc         oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
128
129                 operatorObjectId = tup->t_data->t_oid;
130                 *defined = RegProcedureIsValid(oprcode);
131         }
132         else
133         {
134                 operatorObjectId = InvalidOid;
135                 *defined = false;
136         }
137
138         /*
139          * close the scan and return the oid.
140          */
141         heap_endscan(pg_operator_scan);
142
143         return operatorObjectId;
144 }
145
146 /* ----------------------------------------------------------------
147  *              OperatorGet
148  *
149  *              finds the operator associated with the specified name
150  *              and left and right type names.
151  * ----------------------------------------------------------------
152  */
153 static Oid
154 OperatorGet(char *operatorName,
155                         char *leftTypeName,
156                         char *rightTypeName,
157                         bool *defined)
158 {
159         Relation        pg_operator_desc;
160
161         Oid                     operatorObjectId;
162         Oid                     leftObjectId = InvalidOid;
163         Oid                     rightObjectId = InvalidOid;
164         bool            leftDefined = false;
165         bool            rightDefined = false;
166
167         /*
168          * look up the operator data types.
169          *
170          * Note: types must be defined before operators
171          */
172         if (leftTypeName)
173         {
174                 leftObjectId = TypeGet(leftTypeName, &leftDefined);
175
176                 if (!OidIsValid(leftObjectId) || !leftDefined)
177                         elog(ERROR, "left type \"%s\" of operator %s does not exist",
178                                  leftTypeName, operatorName);
179         }
180
181         if (rightTypeName)
182         {
183                 rightObjectId = TypeGet(rightTypeName, &rightDefined);
184
185                 if (!OidIsValid(rightObjectId) || !rightDefined)
186                         elog(ERROR, "right type \"%s\" of operator %s does not exist",
187                                  rightTypeName, operatorName);
188         }
189
190         if (!((OidIsValid(leftObjectId) && leftDefined) ||
191                   (OidIsValid(rightObjectId) && rightDefined)))
192                 elog(ERROR, "operator %s must have at least one operand type", operatorName);
193
194         /*
195          * open the pg_operator relation
196          */
197         pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
198
199         /*
200          * get the oid for the operator with the appropriate name and
201          * left/right types.
202          */
203         operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
204                                                                                                    operatorName,
205                                                                                                    leftObjectId,
206                                                                                                    rightObjectId,
207                                                                                                    defined);
208
209         /*
210          * close the relation and return the operator oid.
211          */
212         heap_close(pg_operator_desc, AccessShareLock);
213
214         return operatorObjectId;
215 }
216
217 /* ----------------------------------------------------------------
218  *              OperatorShellMakeWithOpenRelation
219  *
220  * ----------------------------------------------------------------
221  */
222 static Oid
223 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
224                                                                   char *operatorName,
225                                                                   Oid leftObjectId,
226                                                                   Oid rightObjectId)
227 {
228         int                     i;
229         HeapTuple       tup;
230         Datum           values[Natts_pg_operator];
231         char            nulls[Natts_pg_operator];
232         Oid                     operatorObjectId;
233         NameData        oname;
234         TupleDesc       tupDesc;
235
236         /*
237          * initialize our *nulls and *values arrays
238          */
239         for (i = 0; i < Natts_pg_operator; ++i)
240         {
241                 nulls[i] = ' ';
242                 values[i] = (Datum) NULL;               /* redundant, but safe */
243         }
244
245         /*
246          * initialize *values with the operator name and input data types.
247          * Note that oprcode is set to InvalidOid, indicating it's a shell.
248          */
249         i = 0;
250         namestrcpy(&oname, operatorName);
251         values[i++] = NameGetDatum(&oname);
252         values[i++] = Int32GetDatum(GetUserId());
253         values[i++] = UInt16GetDatum(0);
254         values[i++] = CharGetDatum('b');        /* assume it's binary */
255         values[i++] = BoolGetDatum(false);
256         values[i++] = BoolGetDatum(false);
257         values[i++] = ObjectIdGetDatum(leftObjectId);           /* <-- left oid */
258         values[i++] = ObjectIdGetDatum(rightObjectId);          /* <-- right oid */
259         values[i++] = ObjectIdGetDatum(InvalidOid);
260         values[i++] = ObjectIdGetDatum(InvalidOid);
261         values[i++] = ObjectIdGetDatum(InvalidOid);
262         values[i++] = ObjectIdGetDatum(InvalidOid);
263         values[i++] = ObjectIdGetDatum(InvalidOid);
264         values[i++] = ObjectIdGetDatum(InvalidOid);
265         values[i++] = ObjectIdGetDatum(InvalidOid);
266         values[i++] = ObjectIdGetDatum(InvalidOid);
267
268         /*
269          * create a new operator tuple
270          */
271         tupDesc = pg_operator_desc->rd_att;
272
273         tup = heap_formtuple(tupDesc,
274                                                  values,
275                                                  nulls);
276
277         /*
278          * insert our "shell" operator tuple and close the relation
279          */
280         heap_insert(pg_operator_desc, tup);
281         operatorObjectId = tup->t_data->t_oid;
282
283         if (RelationGetForm(pg_operator_desc)->relhasindex)
284         {
285                 Relation        idescs[Num_pg_operator_indices];
286
287                 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
288                 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
289                 CatalogCloseIndices(Num_pg_operator_indices, idescs);
290         }
291
292         /*
293          * free the tuple and return the operator oid
294          */
295         heap_freetuple(tup);
296
297         return operatorObjectId;
298 }
299
300 /* ----------------------------------------------------------------
301  *              OperatorShellMake
302  *
303  *              Specify operator name and left and right type names,
304  *              fill an operator struct with this info and NULL's,
305  *              call heap_insert and return the Oid
306  *              to the caller.
307  * ----------------------------------------------------------------
308  */
309 static Oid
310 OperatorShellMake(char *operatorName,
311                                   char *leftTypeName,
312                                   char *rightTypeName)
313 {
314         Relation        pg_operator_desc;
315         Oid                     operatorObjectId;
316
317         Oid                     leftObjectId = InvalidOid;
318         Oid                     rightObjectId = InvalidOid;
319         bool            leftDefined = false;
320         bool            rightDefined = false;
321
322         /*
323          * get the left and right type oid's for this operator
324          */
325         if (leftTypeName)
326                 leftObjectId = TypeGet(leftTypeName, &leftDefined);
327
328         if (rightTypeName)
329                 rightObjectId = TypeGet(rightTypeName, &rightDefined);
330
331         if (!((OidIsValid(leftObjectId) && leftDefined) ||
332                   (OidIsValid(rightObjectId) && rightDefined)))
333                 elog(ERROR, "OperatorShellMake: the operand types are not valid");
334
335         /*
336          * open pg_operator
337          */
338         pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
339
340         /*
341          * add a "shell" operator tuple to the operator relation and recover
342          * the shell tuple's oid.
343          */
344         operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
345                                                                                                                  operatorName,
346                                                                                                                  leftObjectId,
347                                                                                                                  rightObjectId);
348
349         /*
350          * close the operator relation and return the oid.
351          */
352         heap_close(pg_operator_desc, RowExclusiveLock);
353
354         return operatorObjectId;
355 }
356
357 /* --------------------------------
358  * OperatorDef
359  *
360  * This routine gets complicated because it allows the user to
361  * specify operators that do not exist.  For example, if operator
362  * "op" is being defined, the negator operator "negop" and the
363  * commutator "commop" can also be defined without specifying
364  * any information other than their names.      Since in order to
365  * add "op" to the PG_OPERATOR catalog, all the Oid's for these
366  * operators must be placed in the fields of "op", a forward
367  * declaration is done on the commutator and negator operators.
368  * This is called creating a shell, and its main effect is to
369  * create a tuple in the PG_OPERATOR catalog with minimal
370  * information about the operator (just its name and types).
371  * Forward declaration is used only for this purpose, it is
372  * not available to the user as it is for type definition.
373  *
374  * Algorithm:
375  *
376  * check if operator already defined
377  *        if so, but oprcode is null, save the Oid -- we are filling in a shell
378  *        otherwise error
379  * get the attribute types from relation descriptor for pg_operator
380  * assign values to the fields of the operator:
381  *       operatorName
382  *       owner id (simply the user id of the caller)
383  *       precedence
384  *       operator "kind" either "b" for binary or "l" for left unary
385  *       isLeftAssociative boolean
386  *       canHash boolean
387  *       leftTypeObjectId -- type must already be defined
388  *       rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
389  *       resultType -- defer this, since it must be determined from
390  *                                 the pg_procedure catalog
391  *       commutatorObjectId -- if this is NULL, enter ObjectId=0
392  *                                        else if this already exists, enter its ObjectId
393  *                                        else if this does not yet exist, and is not
394  *                                              the same as the main operatorName, then create
395  *                                              a shell and enter the new ObjectId
396  *                                        else if this does not exist but IS the same
397  *                                              name & types as the main operator, set the ObjectId=0.
398  *                                              (We are creating a self-commutating operator.)
399  *                                              The link will be fixed later by OperatorUpd.
400  *       negatorObjectId   -- same as for commutatorObjectId
401  *       leftSortObjectId  -- same as for commutatorObjectId
402  *       rightSortObjectId -- same as for commutatorObjectId
403  *       operatorProcedure -- must access the pg_procedure catalog to get the
404  *                                 ObjectId of the procedure that actually does the operator
405  *                                 actions this is required.  Do a lookup to find out the
406  *                                 return type of the procedure
407  *       restrictionProcedure -- must access the pg_procedure catalog to get
408  *                                 the ObjectId but this is optional
409  *       joinProcedure -- same as restrictionProcedure
410  * now either insert or replace the operator into the pg_operator catalog
411  * if the operator shell is being filled in
412  *       access the catalog in order to get a valid buffer
413  *       create a tuple using ModifyHeapTuple
414  *       get the t_self from the modified tuple and call RelationReplaceHeapTuple
415  * else if a new operator is being created
416  *       create a tuple using heap_formtuple
417  *       call heap_insert
418  * --------------------------------
419  *              "X" indicates an optional argument (i.e. one that can be NULL)
420  *              operatorName;                   -- operator name
421  *              leftTypeName;                   -- X left type name
422  *              rightTypeName;                  -- X right type name
423  *              procedureName;                  -- procedure name for operator code
424  *              precedence;                             -- operator precedence
425  *              isLeftAssociative;              -- operator is left associative?
426  *              commutatorName;                 -- X commutator operator name
427  *              negatorName;                    -- X negator operator name
428  *              restrictionName;                -- X restriction sel. procedure name
429  *              joinName;                               -- X join sel. procedure name
430  *              canHash;                                -- can hash join be used with operator?
431  *              leftSortName;                   -- X left sort operator (for merge join)
432  *              rightSortName;                  -- X right sort operator (for merge join)
433  */
434 static void
435 OperatorDef(char *operatorName,
436                         char *leftTypeName,
437                         char *rightTypeName,
438                         char *procedureName,
439                         uint16 precedence,
440                         bool isLeftAssociative,
441                         char *commutatorName,
442                         char *negatorName,
443                         char *restrictionName,
444                         char *joinName,
445                         bool canHash,
446                         char *leftSortName,
447                         char *rightSortName)
448 {
449         int                     i,
450                                 j;
451         Relation        pg_operator_desc;
452         HeapScanDesc pg_operator_scan;
453         HeapTuple       tup;
454         char            nulls[Natts_pg_operator];
455         char            replaces[Natts_pg_operator];
456         Datum           values[Natts_pg_operator];
457         Oid                     operatorObjectId;
458         bool            operatorAlreadyDefined;
459         Oid                     leftTypeId = InvalidOid;
460         Oid                     rightTypeId = InvalidOid;
461         Oid                     commutatorId = InvalidOid;
462         Oid                     negatorId = InvalidOid;
463         bool            leftDefined = false;
464         bool            rightDefined = false;
465         bool            selfCommutator = false;
466         char       *name[4];
467         Oid                     typeId[FUNC_MAX_ARGS];
468         int                     nargs;
469         NameData        oname;
470         TupleDesc       tupDesc;
471         ScanKeyData     opKey[3];
472
473         operatorObjectId = OperatorGet(operatorName,
474                                                                    leftTypeName,
475                                                                    rightTypeName,
476                                                                    &operatorAlreadyDefined);
477
478         if (operatorAlreadyDefined)
479                 elog(ERROR, "OperatorDef: operator \"%s\" already defined",
480                          operatorName);
481
482         /*
483          * At this point, if operatorObjectId is not InvalidOid then we are
484          * filling in a previously-created shell.
485          */
486
487         /*
488          * look up the operator data types.
489          *
490          * Note: types must be defined before operators
491          */
492         if (leftTypeName)
493         {
494                 leftTypeId = TypeGet(leftTypeName, &leftDefined);
495
496                 if (!OidIsValid(leftTypeId) || !leftDefined)
497                         elog(ERROR, "left type \"%s\" does not exist",
498                                  leftTypeName);
499         }
500
501         if (rightTypeName)
502         {
503                 rightTypeId = TypeGet(rightTypeName, &rightDefined);
504
505                 if (!OidIsValid(rightTypeId) || !rightDefined)
506                         elog(ERROR, "right type \"%s\" does not exist",
507                                  rightTypeName);
508         }
509
510         if (!((OidIsValid(leftTypeId) && leftDefined) ||
511                   (OidIsValid(rightTypeId) && rightDefined)))
512                 elog(ERROR, "operator must have at least one operand type");
513
514         for (i = 0; i < Natts_pg_operator; ++i)
515         {
516                 values[i] = (Datum) NULL;
517                 replaces[i] = 'r';
518                 nulls[i] = ' ';
519         }
520
521         /*
522          * Look up registered procedures -- find the return type of
523          * procedureName to place in "result" field. Do this before shells are
524          * created so we don't have to worry about deleting them later.
525          */
526         MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
527         if (!leftTypeName)
528         {
529                 typeId[0] = rightTypeId;
530                 nargs = 1;
531         }
532         else if (!rightTypeName)
533         {
534                 typeId[0] = leftTypeId;
535                 nargs = 1;
536         }
537         else
538         {
539                 typeId[0] = leftTypeId;
540                 typeId[1] = rightTypeId;
541                 nargs = 2;
542         }
543         tup = SearchSysCache(PROCNAME,
544                                                  PointerGetDatum(procedureName),
545                                                  Int32GetDatum(nargs),
546                                                  PointerGetDatum(typeId),
547                                                  0);
548         if (!HeapTupleIsValid(tup))
549                 func_error("OperatorDef", procedureName, nargs, typeId, NULL);
550
551         values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
552         values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
553                                                                                         GETSTRUCT(tup))->prorettype);
554
555         ReleaseSysCache(tup);
556
557         /*
558          * find restriction estimator
559          */
560         if (restrictionName)
561         {                                                       /* optional */
562                 Oid                     restOid;
563
564                 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
565                 typeId[0] = 0;                  /* Query (opaque type) */
566                 typeId[1] = OIDOID;             /* operator OID */
567                 typeId[2] = 0;                  /* args list (opaque type) */
568                 typeId[3] = INT4OID;    /* varRelid */
569
570                 restOid = GetSysCacheOid(PROCNAME,
571                                                                  PointerGetDatum(restrictionName),
572                                                                  Int32GetDatum(4),
573                                                                  PointerGetDatum(typeId),
574                                                                  0);
575                 if (!OidIsValid(restOid))
576                         func_error("OperatorDef", restrictionName, 4, typeId, NULL);
577
578                 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
579         }
580         else
581                 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
582
583         /*
584          * find join estimator
585          */
586         if (joinName)
587         {                                                       /* optional */
588                 Oid                     joinOid;
589
590                 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
591                 typeId[0] = 0;                  /* Query (opaque type) */
592                 typeId[1] = OIDOID;             /* operator OID */
593                 typeId[2] = 0;                  /* args list (opaque type) */
594
595                 joinOid = GetSysCacheOid(PROCNAME,
596                                                                  PointerGetDatum(joinName),
597                                                                  Int32GetDatum(3),
598                                                                  PointerGetDatum(typeId),
599                                                                  0);
600                 if (!OidIsValid(joinOid))
601                         func_error("OperatorDef", joinName, 3, typeId, NULL);
602
603                 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
604         }
605         else
606                 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
607
608         /*
609          * set up values in the operator tuple
610          */
611         i = 0;
612         namestrcpy(&oname, operatorName);
613         values[i++] = NameGetDatum(&oname);
614         values[i++] = Int32GetDatum(GetUserId());
615         values[i++] = UInt16GetDatum(precedence);
616         values[i++] = CharGetDatum(leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l');
617         values[i++] = BoolGetDatum(isLeftAssociative);
618         values[i++] = BoolGetDatum(canHash);
619         values[i++] = ObjectIdGetDatum(leftTypeId);
620         values[i++] = ObjectIdGetDatum(rightTypeId);
621
622         ++i;                                            /* Skip "oprresult", it was filled in
623                                                                  * above */
624
625         /*
626          * Set up the other operators.  If they do not currently exist, create
627          * shells in order to get ObjectId's.
628          */
629         name[0] = commutatorName;
630         name[1] = negatorName;
631         name[2] = leftSortName;
632         name[3] = rightSortName;
633
634         for (j = 0; j < 4; ++j)
635         {
636                 if (name[j])
637                 {
638                         char       *otherLeftTypeName = NULL;
639                         char       *otherRightTypeName = NULL;
640                         Oid                     otherLeftTypeId = InvalidOid;
641                         Oid                     otherRightTypeId = InvalidOid;
642                         Oid                     other_oid = InvalidOid;
643                         bool            otherDefined = false;
644
645                         switch (j)
646                         {
647                                 case 0: /* commutator has reversed arg types */
648                                         otherLeftTypeName = rightTypeName;
649                                         otherRightTypeName = leftTypeName;
650                                         otherLeftTypeId = rightTypeId;
651                                         otherRightTypeId = leftTypeId;
652                                         other_oid = OperatorGet(name[j],
653                                                                                         otherLeftTypeName,
654                                                                                         otherRightTypeName,
655                                                                                         &otherDefined);
656                                         commutatorId = other_oid;
657                                         break;
658                                 case 1: /* negator has same arg types */
659                                         otherLeftTypeName = leftTypeName;
660                                         otherRightTypeName = rightTypeName;
661                                         otherLeftTypeId = leftTypeId;
662                                         otherRightTypeId = rightTypeId;
663                                         other_oid = OperatorGet(name[j],
664                                                                                         otherLeftTypeName,
665                                                                                         otherRightTypeName,
666                                                                                         &otherDefined);
667                                         negatorId = other_oid;
668                                         break;
669                                 case 2: /* left sort op takes left-side data type */
670                                         otherLeftTypeName = leftTypeName;
671                                         otherRightTypeName = leftTypeName;
672                                         otherLeftTypeId = leftTypeId;
673                                         otherRightTypeId = leftTypeId;
674                                         other_oid = OperatorGet(name[j],
675                                                                                         otherLeftTypeName,
676                                                                                         otherRightTypeName,
677                                                                                         &otherDefined);
678                                         break;
679                                 case 3: /* right sort op takes right-side data
680                                                                  * type */
681                                         otherLeftTypeName = rightTypeName;
682                                         otherRightTypeName = rightTypeName;
683                                         otherLeftTypeId = rightTypeId;
684                                         otherRightTypeId = rightTypeId;
685                                         other_oid = OperatorGet(name[j],
686                                                                                         otherLeftTypeName,
687                                                                                         otherRightTypeName,
688                                                                                         &otherDefined);
689                                         break;
690                         }
691
692                         if (OidIsValid(other_oid))
693                         {
694                                 /* other op already in catalogs */
695                                 values[i++] = ObjectIdGetDatum(other_oid);
696                         }
697                         else if (strcmp(operatorName, name[j]) != 0 ||
698                                          otherLeftTypeId != leftTypeId ||
699                                          otherRightTypeId != rightTypeId)
700                         {
701                                 /* not in catalogs, different from operator */
702                                 other_oid = OperatorShellMake(name[j],
703                                                                                           otherLeftTypeName,
704                                                                                           otherRightTypeName);
705                                 if (!OidIsValid(other_oid))
706                                         elog(ERROR,
707                                            "OperatorDef: can't create operator shell \"%s\"",
708                                                  name[j]);
709                                 values[i++] = ObjectIdGetDatum(other_oid);
710                         }
711                         else
712                         {
713
714                                 /*
715                                  * self-linkage to this operator; will fix below. Note
716                                  * that only self-linkage for commutation makes sense.
717                                  */
718                                 if (j != 0)
719                                         elog(ERROR,
720                                                  "operator cannot be its own negator or sort operator");
721                                 selfCommutator = true;
722                                 values[i++] = ObjectIdGetDatum(InvalidOid);
723                         }
724                 }
725                 else
726                 {
727                         /* other operator is omitted */
728                         values[i++] = ObjectIdGetDatum(InvalidOid);
729                 }
730         }
731
732         /* last three fields were filled in above */
733
734         pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
735
736         /*
737          * If we are adding to an operator shell, get its t_self
738          */
739         if (operatorObjectId)
740         {
741                 /* Make sure we can see the shell even if it is new in current cmd */
742                 CommandCounterIncrement();
743
744                 ScanKeyEntryInitialize(&opKey[0], 0x0,
745                                                            Anum_pg_operator_oprname,
746                                                            F_NAMEEQ,
747                                                            PointerGetDatum(operatorName));
748                 ScanKeyEntryInitialize(&opKey[1], 0x0,
749                                                            Anum_pg_operator_oprleft,
750                                                            F_OIDEQ,
751                                                            ObjectIdGetDatum(leftTypeId));
752                 ScanKeyEntryInitialize(&opKey[2], 0x0,
753                                                            Anum_pg_operator_oprright,
754                                                            F_OIDEQ,
755                                                            ObjectIdGetDatum(rightTypeId));
756
757                 pg_operator_scan = heap_beginscan(pg_operator_desc,
758                                                                                   0,
759                                                                                   SnapshotSelf, /* no cache? */
760                                                                                   3,
761                                                                                   opKey);
762
763                 tup = heap_getnext(pg_operator_scan, 0);
764                 if (HeapTupleIsValid(tup))
765                 {
766                         tup = heap_modifytuple(tup,
767                                                                    pg_operator_desc,
768                                                                    values,
769                                                                    nulls,
770                                                                    replaces);
771
772                         simple_heap_update(pg_operator_desc, &tup->t_self, tup);
773                 }
774                 else
775                         elog(ERROR, "OperatorDef: operator %u not found", operatorObjectId);
776
777                 heap_endscan(pg_operator_scan);
778         }
779         else
780         {
781                 tupDesc = pg_operator_desc->rd_att;
782                 tup = heap_formtuple(tupDesc, values, nulls);
783
784                 heap_insert(pg_operator_desc, tup);
785                 operatorObjectId = tup->t_data->t_oid;
786         }
787
788         if (RelationGetForm(pg_operator_desc)->relhasindex)
789         {
790                 Relation        idescs[Num_pg_operator_indices];
791
792                 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
793                 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
794                 CatalogCloseIndices(Num_pg_operator_indices, idescs);
795         }
796
797         heap_close(pg_operator_desc, RowExclusiveLock);
798
799         /*
800          * If a commutator and/or negator link is provided, update the other
801          * operator(s) to point at this one, if they don't already have a
802          * link. This supports an alternate style of operator definition
803          * wherein the user first defines one operator without giving negator
804          * or commutator, then defines the other operator of the pair with the
805          * proper commutator or negator attribute.      That style doesn't require
806          * creation of a shell, and it's the only style that worked right
807          * before Postgres version 6.5. This code also takes care of the
808          * situation where the new operator is its own commutator.
809          */
810         if (selfCommutator)
811                 commutatorId = operatorObjectId;
812
813         if (OidIsValid(commutatorId) || OidIsValid(negatorId))
814                 OperatorUpd(operatorObjectId, commutatorId, negatorId);
815 }
816
817 /* ----------------------------------------------------------------
818  * OperatorUpd
819  *
820  *      For a given operator, look up its negator and commutator operators.
821  *      If they are defined, but their negator and commutator fields
822  *      (respectively) are empty, then use the new operator for neg or comm.
823  *      This solves a problem for users who need to insert two new operators
824  *      which are the negator or commutator of each other.
825  * ----------------------------------------------------------------
826  */
827 static void
828 OperatorUpd(Oid baseId, Oid commId, Oid negId)
829 {
830         int                     i;
831         Relation        pg_operator_desc;
832         HeapScanDesc pg_operator_scan;
833         HeapTuple       tup;
834         char            nulls[Natts_pg_operator];
835         char            replaces[Natts_pg_operator];
836         Datum           values[Natts_pg_operator];
837         ScanKeyData     opKey[1];
838
839         for (i = 0; i < Natts_pg_operator; ++i)
840         {
841                 values[i] = (Datum) 0;
842                 replaces[i] = ' ';
843                 nulls[i] = ' ';
844         }
845
846         pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
847
848         /*
849          * check and update the commutator & negator, if necessary
850          *
851          * First make sure we can see them...
852          */
853         CommandCounterIncrement();
854
855         ScanKeyEntryInitialize(&opKey[0], 0x0,
856                                                    ObjectIdAttributeNumber,
857                                                    F_OIDEQ,
858                                                    ObjectIdGetDatum(commId));
859
860         pg_operator_scan = heap_beginscan(pg_operator_desc,
861                                                                           0,
862                                                                           SnapshotSelf,         /* no cache? */
863                                                                           1,
864                                                                           opKey);
865
866         tup = heap_getnext(pg_operator_scan, 0);
867
868         /*
869          * if the commutator and negator are the same operator, do one update.
870          * XXX this is probably useless code --- I doubt it ever makes sense
871          * for commutator and negator to be the same thing...
872          */
873         if (commId == negId)
874         {
875                 if (HeapTupleIsValid(tup))
876                 {
877                         Form_pg_operator t;
878
879                         t = (Form_pg_operator) GETSTRUCT(tup);
880                         if (!OidIsValid(t->oprcom)
881                                 || !OidIsValid(t->oprnegate))
882                         {
883
884                                 if (!OidIsValid(t->oprnegate))
885                                 {
886                                         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
887                                         replaces[Anum_pg_operator_oprnegate - 1] = 'r';
888                                 }
889
890                                 if (!OidIsValid(t->oprcom))
891                                 {
892                                         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
893                                         replaces[Anum_pg_operator_oprcom - 1] = 'r';
894                                 }
895
896                                 tup = heap_modifytuple(tup,
897                                                                            pg_operator_desc,
898                                                                            values,
899                                                                            nulls,
900                                                                            replaces);
901
902                                 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
903
904                                 if (RelationGetForm(pg_operator_desc)->relhasindex)
905                                 {
906                                         Relation        idescs[Num_pg_operator_indices];
907
908                                         CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
909                                         CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
910                                         CatalogCloseIndices(Num_pg_operator_indices, idescs);
911                                 }
912                         }
913                 }
914                 heap_endscan(pg_operator_scan);
915
916                 heap_close(pg_operator_desc, RowExclusiveLock);
917
918                 return;
919         }
920
921         /* if commutator and negator are different, do two updates */
922
923         if (HeapTupleIsValid(tup) &&
924                 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
925         {
926                 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
927                 replaces[Anum_pg_operator_oprcom - 1] = 'r';
928                 tup = heap_modifytuple(tup,
929                                                            pg_operator_desc,
930                                                            values,
931                                                            nulls,
932                                                            replaces);
933
934                 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
935
936                 if (RelationGetForm(pg_operator_desc)->relhasindex)
937                 {
938                         Relation        idescs[Num_pg_operator_indices];
939
940                         CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
941                         CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
942                         CatalogCloseIndices(Num_pg_operator_indices, idescs);
943                 }
944
945                 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
946                 replaces[Anum_pg_operator_oprcom - 1] = ' ';
947         }
948
949         heap_endscan(pg_operator_scan);
950
951         /* check and update the negator, if necessary */
952         opKey[0].sk_argument = ObjectIdGetDatum(negId);
953
954         pg_operator_scan = heap_beginscan(pg_operator_desc,
955                                                                           0,
956                                                                           SnapshotSelf,         /* no cache? */
957                                                                           1,
958                                                                           opKey);
959
960         tup = heap_getnext(pg_operator_scan, 0);
961         if (HeapTupleIsValid(tup) &&
962                 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
963         {
964                 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
965                 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
966                 tup = heap_modifytuple(tup,
967                                                            pg_operator_desc,
968                                                            values,
969                                                            nulls,
970                                                            replaces);
971
972                 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
973
974                 if (RelationGetForm(pg_operator_desc)->relhasindex)
975                 {
976                         Relation        idescs[Num_pg_operator_indices];
977
978                         CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
979                         CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
980                         CatalogCloseIndices(Num_pg_operator_indices, idescs);
981                 }
982         }
983
984         heap_endscan(pg_operator_scan);
985
986         heap_close(pg_operator_desc, RowExclusiveLock);
987 }
988
989
990 /* ----------------------------------------------------------------
991  * OperatorCreate
992  *
993  * This is now just an interface procedure for OperatorDef ...
994  *
995  * "X" indicates an optional argument (i.e. one that can be NULL)
996  *              operatorName;                   -- operator name
997  *              leftTypeName;                   -- X left type name
998  *              rightTypeName;                  -- X right type name
999  *              procedureName;                  -- procedure for operator
1000  *              precedence;                             -- operator precedence
1001  *              isLeftAssociative;              -- operator is left associative
1002  *              commutatorName;                 -- X commutator operator name
1003  *              negatorName;                    -- X negator operator name
1004  *              restrictionName;                -- X restriction sel. procedure
1005  *              joinName;                               -- X join sel. procedure
1006  *              canHash;                                -- hash join can be used with this operator
1007  *              leftSortName;                   -- X left sort operator (for merge join)
1008  *              rightSortName;                  -- X right sort operator (for merge join)
1009  */
1010 void
1011 OperatorCreate(char *operatorName,
1012                            char *leftTypeName,
1013                            char *rightTypeName,
1014                            char *procedureName,
1015                            uint16 precedence,
1016                            bool isLeftAssociative,
1017                            char *commutatorName,
1018                            char *negatorName,
1019                            char *restrictionName,
1020                            char *joinName,
1021                            bool canHash,
1022                            char *leftSortName,
1023                            char *rightSortName)
1024 {
1025         if (!leftTypeName && !rightTypeName)
1026                 elog(ERROR, "at least one of leftarg or rightarg must be specified");
1027
1028         if (!(leftTypeName && rightTypeName))
1029         {
1030                 /* If it's not a binary op, these things mustn't be set: */
1031                 if (commutatorName)
1032                         elog(ERROR, "only binary operators can have commutators");
1033                 if (joinName)
1034                         elog(ERROR, "only binary operators can have join selectivity");
1035                 if (canHash)
1036                         elog(ERROR, "only binary operators can hash");
1037                 if (leftSortName || rightSortName)
1038                         elog(ERROR, "only binary operators can have sort links");
1039         }
1040
1041         /*
1042          * Use OperatorDef() to define the specified operator and also create
1043          * shells for the operator's associated operators if they don't
1044          * already exist.
1045          */
1046         OperatorDef(operatorName,
1047                                 leftTypeName,
1048                                 rightTypeName,
1049                                 procedureName,
1050                                 precedence,
1051                                 isLeftAssociative,
1052                                 commutatorName,
1053                                 negatorName,
1054                                 restrictionName,
1055                                 joinName,
1056                                 canHash,
1057                                 leftSortName,
1058                                 rightSortName);
1059 }