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