OSDN Git Service

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