]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_operator.c
Inline memset() as MemSet().
[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.14 1997/09/18 20:20:18 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 <catalog/pg_proc.h>
20 #include <utils/syscache.h>
21 #include <access/heapam.h>
22 #include <parser/catalog_utils.h>
23 #include <catalog/catname.h>
24 #include <catalog/pg_operator.h>
25 #include <storage/bufmgr.h>
26 #include <fmgr.h>
27 #include <miscadmin.h>
28 #ifndef HAVE_MEMMOVE
29 #include <regex/utils.h>
30 #else
31 #include <string.h>
32 #endif
33
34 static Oid
35 OperatorGetWithOpenRelation(Relation pg_operator_desc,
36                                                         const char *operatorName,
37                                                         Oid leftObjectId,
38                                                         Oid rightObjectId);
39 static Oid
40 OperatorGet(char *operatorName,
41                         char *leftTypeName,
42                         char *rightTypeName);
43
44 static Oid
45 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
46                                                                   char *operatorName,
47                                                                   Oid leftObjectId,
48                                                                   Oid rightObjectId);
49 static Oid
50 OperatorShellMake(char *operatorName,
51                                   char *leftTypeName,
52                                   char *rightTypeName);
53
54 static void
55 OperatorDef(char *operatorName,
56                         int definedOK,
57                         char *leftTypeName,
58                         char *rightTypeName,
59                         char *procedureName,
60                         uint16 precedence,
61                         bool isLeftAssociative,
62                         char *commutatorName,
63                         char *negatorName,
64                         char *restrictionName,
65                         char *oinName,
66                         bool canHash,
67                         char *leftSortName,
68                         char *rightSortName);
69 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
70
71 /* ----------------------------------------------------------------
72  *              OperatorGetWithOpenRelation
73  *
74  *              preforms a scan on pg_operator for an operator tuple
75  *              with given name and left/right type oids.
76  * ----------------------------------------------------------------
77  *        pg_operator_desc      -- reldesc for pg_operator
78  *        operatorName          -- name of operator to fetch
79  *        leftObjectId          -- left oid of operator to fetch
80  *        rightObjectId         -- right oid of operator to fetch
81  */
82 static Oid
83 OperatorGetWithOpenRelation(Relation pg_operator_desc,
84                                                         const char *operatorName,
85                                                         Oid leftObjectId,
86                                                         Oid rightObjectId)
87 {
88         HeapScanDesc pg_operator_scan;
89         Oid                     operatorObjectId;
90         HeapTuple       tup;
91
92         static ScanKeyData opKey[3] = {
93                 {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
94                 {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
95                 {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
96         };
97
98         fmgr_info(NameEqualRegProcedure,
99                           &opKey[0].sk_func, &opKey[0].sk_nargs);
100         fmgr_info(ObjectIdEqualRegProcedure,
101                           &opKey[1].sk_func, &opKey[1].sk_nargs);
102         fmgr_info(ObjectIdEqualRegProcedure,
103                           &opKey[2].sk_func, &opKey[2].sk_nargs);
104
105         /* ----------------
106          *      form scan key
107          * ----------------
108          */
109         opKey[0].sk_argument = PointerGetDatum(operatorName);
110         opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
111         opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
112
113         /* ----------------
114          *      begin the scan
115          * ----------------
116          */
117         pg_operator_scan = heap_beginscan(pg_operator_desc,
118                                                                           0,
119                                                                           SelfTimeQual,
120                                                                           3,
121                                                                           opKey);
122
123         /* ----------------
124          *      fetch the operator tuple, if it exists, and determine
125          *      the proper return oid value.
126          * ----------------
127          */
128         tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
129         operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
130
131         /* ----------------
132          *      close the scan and return the oid.
133          * ----------------
134          */
135         heap_endscan(pg_operator_scan);
136
137         return
138                 operatorObjectId;
139 }
140
141 /* ----------------------------------------------------------------
142  *              OperatorGet
143  *
144  *              finds the operator associated with the specified name
145  *              and left and right type names.
146  * ----------------------------------------------------------------
147  */
148 static Oid
149 OperatorGet(char *operatorName,
150                         char *leftTypeName,
151                         char *rightTypeName)
152 {
153         Relation        pg_operator_desc;
154
155         Oid                     operatorObjectId;
156         Oid                     leftObjectId = InvalidOid;
157         Oid                     rightObjectId = InvalidOid;
158         bool            leftDefined = false;
159         bool            rightDefined = false;
160
161         /* ----------------
162          *      look up the operator types.
163          *
164          *      Note: types must be defined before operators
165          * ----------------
166          */
167         if (leftTypeName)
168         {
169                 leftObjectId = TypeGet(leftTypeName, &leftDefined);
170
171                 if (!OidIsValid(leftObjectId) || !leftDefined)
172                         elog(WARN, "OperatorGet: left type '%s' nonexistent", leftTypeName);
173         }
174
175         if (rightTypeName)
176         {
177                 rightObjectId = TypeGet(rightTypeName, &rightDefined);
178
179                 if (!OidIsValid(rightObjectId) || !rightDefined)
180                         elog(WARN, "OperatorGet: right type '%s' nonexistent",
181                                  rightTypeName);
182         }
183
184         if (!((OidIsValid(leftObjectId) && leftDefined) ||
185                   (OidIsValid(rightObjectId) && rightDefined)))
186                 elog(WARN, "OperatorGet: no argument types??");
187
188         /* ----------------
189          *      open the pg_operator relation
190          * ----------------
191          */
192         pg_operator_desc = heap_openr(OperatorRelationName);
193
194         /* ----------------
195          *      get the oid for the operator with the appropriate name
196          *      and left/right types.
197          * ----------------
198          */
199         operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
200                                                                                                    operatorName,
201                                                                                                    leftObjectId,
202                                                                                                    rightObjectId);
203
204         /* ----------------
205          *      close the relation and return the operator oid.
206          * ----------------
207          */
208         heap_close(pg_operator_desc);
209
210         return
211                 operatorObjectId;
212 }
213
214 /* ----------------------------------------------------------------
215  *              OperatorShellMakeWithOpenRelation
216  *
217  * ----------------------------------------------------------------
218  */
219 static Oid
220 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
221                                                                   char *operatorName,
222                                                                   Oid leftObjectId,
223                                                                   Oid rightObjectId)
224 {
225         register int i;
226         HeapTuple       tup;
227         Datum           values[Natts_pg_operator];
228         char            nulls[Natts_pg_operator];
229         Oid                     operatorObjectId;
230         TupleDesc       tupDesc;
231
232         /* ----------------
233          *      initialize our nulls[] and values[] arrays
234          * ----------------
235          */
236         for (i = 0; i < Natts_pg_operator; ++i)
237         {
238                 nulls[i] = ' ';
239                 values[i] = (Datum) NULL;               /* redundant, but safe */
240         }
241
242         /* ----------------
243          *      initialize values[] with the type name and
244          * ----------------
245          */
246         i = 0;
247         values[i++] = PointerGetDatum(operatorName);
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(WARN, "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         register        i,
454                                 j;
455         Relation        pg_operator_desc;
456
457         HeapScanDesc pg_operator_scan;
458         HeapTuple       tup;
459         Buffer          buffer;
460         ItemPointerData itemPointerData;
461         char            nulls[Natts_pg_operator];
462         char            replaces[Natts_pg_operator];
463         Datum           values[Natts_pg_operator];
464         Oid                     other_oid = 0;
465         Oid                     operatorObjectId;
466         Oid                     leftTypeId = InvalidOid;
467         Oid                     rightTypeId = InvalidOid;
468         Oid                     commutatorId = InvalidOid;
469         Oid                     negatorId = InvalidOid;
470         bool            leftDefined = false;
471         bool            rightDefined = false;
472         char       *name[4];
473         Oid                     typeId[8];
474         int                     nargs;
475         TupleDesc       tupDesc;
476
477         static ScanKeyData opKey[3] = {
478                 {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
479                 {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
480                 {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
481         };
482
483         fmgr_info(NameEqualRegProcedure,
484                           &opKey[0].sk_func, &opKey[0].sk_nargs);
485         fmgr_info(ObjectIdEqualRegProcedure,
486                           &opKey[1].sk_func, &opKey[1].sk_nargs);
487         fmgr_info(ObjectIdEqualRegProcedure,
488                           &opKey[2].sk_func, &opKey[2].sk_nargs);
489
490         operatorObjectId = OperatorGet(operatorName,
491                                                                    leftTypeName,
492                                                                    rightTypeName);
493
494         if (OidIsValid(operatorObjectId) && !definedOK)
495                 elog(WARN, "OperatorDef: operator \"%s\" already defined",
496                          operatorName);
497
498         if (leftTypeName)
499                 leftTypeId = TypeGet(leftTypeName, &leftDefined);
500
501         if (rightTypeName)
502                 rightTypeId = TypeGet(rightTypeName, &rightDefined);
503
504         if (!((OidIsValid(leftTypeId && leftDefined)) ||
505                   (OidIsValid(rightTypeId && rightDefined))))
506                 elog(WARN, "OperatorGet: no argument types??");
507
508         for (i = 0; i < Natts_pg_operator; ++i)
509         {
510                 values[i] = (Datum) NULL;
511                 replaces[i] = 'r';
512                 nulls[i] = ' ';
513         }
514
515         /* ----------------
516          * Look up registered procedures -- find the return type
517          * of procedureName to place in "result" field.
518          * Do this before shells are created so we don't
519          * have to worry about deleting them later.
520          * ----------------
521          */
522         MemSet(typeId, 0, 8 * sizeof(Oid));
523         if (!leftTypeName)
524         {
525                 typeId[0] = rightTypeId;
526                 nargs = 1;
527         }
528         else if (!rightTypeName)
529         {
530                 typeId[0] = leftTypeId;
531                 nargs = 1;
532         }
533         else
534         {
535                 typeId[0] = leftTypeId;
536                 typeId[1] = rightTypeId;
537                 nargs = 2;
538         }
539         tup = SearchSysCacheTuple(PRONAME,
540                                                           PointerGetDatum(procedureName),
541                                                           Int32GetDatum(nargs),
542                                                           PointerGetDatum(typeId),
543                                                           0);
544
545         if (!PointerIsValid(tup))
546                 func_error("OperatorDef", procedureName, nargs, typeId);
547
548         values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_oid);
549         values[Anum_pg_operator_oprresult - 1] =
550                 ObjectIdGetDatum(((Form_pg_proc)
551                                                   GETSTRUCT(tup))->prorettype);
552
553         /* ----------------
554          *      find restriction
555          * ----------------
556          */
557         if (restrictionName)
558         {                                                       /* optional */
559                 MemSet(typeId, 0, 8 * sizeof(Oid));
560                 typeId[0] = OIDOID;             /* operator OID */
561                 typeId[1] = OIDOID;             /* relation OID */
562                 typeId[2] = INT2OID;    /* attribute number */
563                 typeId[3] = 0;                  /* value - can be any type      */
564                 typeId[4] = INT4OID;    /* flags - left or right selectivity */
565                 tup = SearchSysCacheTuple(PRONAME,
566                                                                   PointerGetDatum(restrictionName),
567                                                                   Int32GetDatum(5),
568                                                                   PointerGetDatum(typeId),
569                                                                   0);
570                 if (!HeapTupleIsValid(tup))
571                         func_error("OperatorDef", restrictionName, 5, typeId);
572
573                 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_oid);
574         }
575         else
576                 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
577
578         /* ----------------
579          *      find join - only valid for binary operators
580          * ----------------
581          */
582         if (joinName)
583         {                                                       /* optional */
584                 MemSet(typeId, 0, 8 * sizeof(Oid));
585                 typeId[0] = OIDOID;             /* operator OID */
586                 typeId[1] = OIDOID;             /* relation OID 1 */
587                 typeId[2] = INT2OID;    /* attribute number 1 */
588                 typeId[3] = OIDOID;             /* relation OID 2 */
589                 typeId[4] = INT2OID;    /* attribute number 2 */
590
591                 tup = SearchSysCacheTuple(PRONAME,
592                                                                   PointerGetDatum(joinName),
593                                                                   Int32GetDatum(5),
594                                                                   PointerGetDatum(typeId),
595                                                                   0);
596                 if (!HeapTupleIsValid(tup))
597                         func_error("OperatorDef", joinName, 5, typeId);
598
599                 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_oid);
600         }
601         else
602                 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
603
604         /* ----------------
605          * set up values in the operator tuple
606          * ----------------
607          */
608         i = 0;
609         values[i++] = PointerGetDatum(operatorName);
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(WARN,
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 and a buffer.
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                                                                                   SelfTimeQual,
701                                                                                   3,
702                                                                                   opKey);
703
704                 tup = heap_getnext(pg_operator_scan, 0, &buffer);
705                 if (HeapTupleIsValid(tup))
706                 {
707                         tup = heap_modifytuple(tup,
708                                                                    buffer,
709                                                                    pg_operator_desc,
710                                                                    values,
711                                                                    nulls,
712                                                                    replaces);
713
714                         ItemPointerCopy(&tup->t_ctid, &itemPointerData);
715                         setheapoverride(true);
716                         heap_replace(pg_operator_desc, &itemPointerData, tup);
717                         setheapoverride(false);
718                 }
719                 else
720                         elog(WARN, "OperatorDef: no operator %d", other_oid);
721
722                 heap_endscan(pg_operator_scan);
723
724         }
725         else
726         {
727                 tupDesc = pg_operator_desc->rd_att;
728                 tup = heap_formtuple(tupDesc, values, nulls);
729
730                 heap_insert(pg_operator_desc, tup);
731                 operatorObjectId = tup->t_oid;
732         }
733
734         heap_close(pg_operator_desc);
735
736         /*
737          * It's possible that we're creating a skeleton operator here for the
738          * commute or negate attributes of a real operator.  If we are, then
739          * we're done.  If not, we may need to update the negator and
740          * commutator for this attribute.  The reason for this is that the
741          * user may want to create two operators (say < and >=).  When he
742          * defines <, if he uses >= as the negator or commutator, he won't be
743          * able to insert it later, since (for some reason) define operator
744          * defines it for him.  So what he does is to define > without a
745          * negator or commutator.  Then he defines >= with < as the negator
746          * and commutator.      As a side effect, this will update the > tuple if
747          * it has no commutator or negator defined.
748          *
749          * Alstublieft, Tom Vijlbrief.
750          */
751         if (!definedOK)
752                 OperatorUpd(operatorObjectId, commutatorId, negatorId);
753 }
754
755 /* ----------------------------------------------------------------
756  * OperatorUpd
757  *
758  *      For a given operator, look up its negator and commutator operators.
759  *      If they are defined, but their negator and commutator operators
760  *      (respectively) are not, then use the new operator for neg and comm.
761  *      This solves a problem for users who need to insert two new operators
762  *      which are the negator or commutator of each other.
763  * ----------------------------------------------------------------
764  */
765 static void
766 OperatorUpd(Oid baseId, Oid commId, Oid negId)
767 {
768         register        i;
769         Relation        pg_operator_desc;
770         HeapScanDesc pg_operator_scan;
771         HeapTuple       tup;
772         Buffer          buffer;
773         ItemPointerData itemPointerData;
774         char            nulls[Natts_pg_operator];
775         char            replaces[Natts_pg_operator];
776         Datum           values[Natts_pg_operator];
777
778         static ScanKeyData opKey[1] = {
779                 {0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure},
780         };
781
782         fmgr_info(ObjectIdEqualRegProcedure,
783                           &opKey[0].sk_func, &opKey[0].sk_nargs);
784
785         for (i = 0; i < Natts_pg_operator; ++i)
786         {
787                 values[i] = (Datum) NULL;
788                 replaces[i] = ' ';
789                 nulls[i] = ' ';
790         }
791
792         pg_operator_desc = heap_openr(OperatorRelationName);
793
794         /* check and update the commutator, if necessary */
795         opKey[0].sk_argument = ObjectIdGetDatum(commId);
796
797         pg_operator_scan = heap_beginscan(pg_operator_desc,
798                                                                           0,
799                                                                           SelfTimeQual,
800                                                                           1,
801                                                                           opKey);
802
803         tup = heap_getnext(pg_operator_scan, 0, &buffer);
804
805         /* if the commutator and negator are the same operator, do one update */
806         if (commId == negId)
807         {
808                 if (HeapTupleIsValid(tup))
809                 {
810                         OperatorTupleForm t;
811
812                         t = (OperatorTupleForm) GETSTRUCT(tup);
813                         if (!OidIsValid(t->oprcom)
814                                 || !OidIsValid(t->oprnegate))
815                         {
816
817                                 if (!OidIsValid(t->oprnegate))
818                                 {
819                                         values[Anum_pg_operator_oprnegate - 1] =
820                                                 ObjectIdGetDatum(baseId);
821                                         replaces[Anum_pg_operator_oprnegate - 1] = 'r';
822                                 }
823
824                                 if (!OidIsValid(t->oprcom))
825                                 {
826                                         values[Anum_pg_operator_oprcom - 1] =
827                                                 ObjectIdGetDatum(baseId);
828                                         replaces[Anum_pg_operator_oprcom - 1] = 'r';
829                                 }
830
831                                 tup = heap_modifytuple(tup,
832                                                                            buffer,
833                                                                            pg_operator_desc,
834                                                                            values,
835                                                                            nulls,
836                                                                            replaces);
837
838                                 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
839
840                                 setheapoverride(true);
841                                 heap_replace(pg_operator_desc, &itemPointerData, tup);
842                                 setheapoverride(false);
843
844                         }
845                 }
846                 heap_endscan(pg_operator_scan);
847
848                 heap_close(pg_operator_desc);
849
850                 /* release the buffer properly */
851                 if (BufferIsValid(buffer))
852                         ReleaseBuffer(buffer);
853
854                 return;
855         }
856
857         /* if commutator and negator are different, do two updates */
858         if (HeapTupleIsValid(tup) &&
859                 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom)))
860         {
861                 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
862                 replaces[Anum_pg_operator_oprcom - 1] = 'r';
863                 tup = heap_modifytuple(tup,
864                                                            buffer,
865                                                            pg_operator_desc,
866                                                            values,
867                                                            nulls,
868                                                            replaces);
869
870                 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
871                 setheapoverride(true);
872                 heap_replace(pg_operator_desc, &itemPointerData, tup);
873                 setheapoverride(false);
874
875                 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
876                 replaces[Anum_pg_operator_oprcom - 1] = ' ';
877
878                 /* release the buffer properly */
879                 if (BufferIsValid(buffer))
880                         ReleaseBuffer(buffer);
881
882         }
883
884         /* check and update the negator, if necessary */
885         opKey[0].sk_argument = ObjectIdGetDatum(negId);
886
887         pg_operator_scan = heap_beginscan(pg_operator_desc,
888                                                                           0,
889                                                                           SelfTimeQual,
890                                                                           1,
891                                                                           opKey);
892
893         tup = heap_getnext(pg_operator_scan, 0, &buffer);
894         if (HeapTupleIsValid(tup) &&
895                 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate)))
896         {
897                 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
898                 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
899                 tup = heap_modifytuple(tup,
900                                                            buffer,
901                                                            pg_operator_desc,
902                                                            values,
903                                                            nulls,
904                                                            replaces);
905
906                 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
907
908                 setheapoverride(true);
909                 heap_replace(pg_operator_desc, &itemPointerData, tup);
910                 setheapoverride(false);
911         }
912
913         /* release the buffer properly */
914         if (BufferIsValid(buffer))
915                 ReleaseBuffer(buffer);
916
917         heap_endscan(pg_operator_scan);
918
919         heap_close(pg_operator_desc);
920 }
921
922
923 /* ----------------------------------------------------------------
924  * OperatorCreate
925  *
926  * Algorithm:
927  *
928  *      Since the commutator, negator, leftsortoperator, and rightsortoperator
929  *      can be defined implicitly through OperatorCreate, must check before
930  *      the main operator is added to see if they already exist.  If they
931  *      do not already exist, OperatorDef makes a "shell" for each undefined
932  *      one, and then OperatorCreate must call OperatorDef again to fill in
933  *      each shell.  All this is necessary in order to get the right ObjectId's
934  *      filled into the right fields.
935  *
936  *      The "definedOk" flag indicates that OperatorDef can be called on
937  *      the operator even though it already has an entry in the PG_OPERATOR
938  *      relation.  This allows shells to be filled in.  The user cannot
939  *      forward declare operators, this is strictly an internal capability.
940  *
941  *      When the shells are filled in by subsequent calls to OperatorDef,
942  *      all the fields are the same as the definition of the original operator
943  *      except that the target operator name and the original operatorName
944  *      are switched.  In the case of commutator and negator, special flags
945  *      are set to indicate their status, telling the executor(?) that
946  *      the operands are to be switched, or the outcome of the procedure
947  *      negated.
948  *
949  * ************************* NOTE NOTE NOTE ******************************
950  *
951  *      If the execution of this utility is interrupted, the pg_operator
952  *      catalog may be left in an inconsistent state.  Similarly, if
953  *      something is removed from the pg_operator, pg_type, or pg_procedure
954  *      catalog while this is executing, the results may be inconsistent.
955  * ----------------------------------------------------------------
956  *
957  * "X" indicates an optional argument (i.e. one that can be NULL)
958  *              operatorName;                   -- operator name
959  *              leftTypeName;                   -- X left type name
960  *              rightTypeName;                  -- X right type name
961  *              procedureName;                  -- procedure for operator
962  *              precedence;                             -- operator precedence
963  *              isLeftAssociative;              -- operator is left associative
964  *              commutatorName;                 -- X commutator operator name
965  *              negatorName;                    -- X negator operator name
966  *              restrictionName;                -- X restriction sel. procedure
967  *              joinName;                               -- X join sel. procedure name
968  *              canHash;                                -- operator hashes
969  *              leftSortName;                   -- X left sort operator
970  *              rightSortName;                  -- X right sort operator
971  *
972  */
973 void
974 OperatorCreate(char *operatorName,
975                            char *leftTypeName,
976                            char *rightTypeName,
977                            char *procedureName,
978                            uint16 precedence,
979                            bool isLeftAssociative,
980                            char *commutatorName,
981                            char *negatorName,
982                            char *restrictionName,
983                            char *joinName,
984                            bool canHash,
985                            char *leftSortName,
986                            char *rightSortName)
987 {
988         Oid                     commObjectId,
989                                 negObjectId;
990         Oid                     leftSortObjectId,
991                                 rightSortObjectId;
992         int                     definedOK;
993
994         if (!leftTypeName && !rightTypeName)
995                 elog(WARN, "OperatorCreate : at least one of leftarg or rightarg must be defined");
996
997         /* ----------------
998          *      get the oid's of the operator's associated operators, if possible.
999          * ----------------
1000          */
1001         if (commutatorName)
1002                 commObjectId = OperatorGet(commutatorName,              /* commute type order */
1003                                                                    rightTypeName,
1004                                                                    leftTypeName);
1005         else
1006                 commObjectId = 0;
1007
1008         if (negatorName)
1009                 negObjectId = OperatorGet(negatorName,
1010                                                                   leftTypeName,
1011                                                                   rightTypeName);
1012         else
1013                 negObjectId = 0;
1014
1015         if (leftSortName)
1016                 leftSortObjectId = OperatorGet(leftSortName,
1017                                                                            leftTypeName,
1018                                                                            rightTypeName);
1019         else
1020                 leftSortObjectId = 0;
1021
1022         if (rightSortName)
1023                 rightSortObjectId = OperatorGet(rightSortName,
1024                                                                                 rightTypeName,
1025                                                                                 leftTypeName);
1026         else
1027                 rightSortObjectId = 0;
1028
1029         /* ----------------
1030          *      Use OperatorDef() to define the specified operator and
1031          *      also create shells for the operator's associated operators
1032          *      if they don't already exist.
1033          *
1034          *      This operator should not be defined yet.
1035          * ----------------
1036          */
1037         definedOK = 0;
1038
1039         OperatorDef(operatorName,
1040                                 definedOK,
1041                                 leftTypeName,
1042                                 rightTypeName,
1043                                 procedureName,
1044                                 precedence,
1045                                 isLeftAssociative,
1046                                 commutatorName,
1047                                 negatorName,
1048                                 restrictionName,
1049                                 joinName,
1050                                 canHash,
1051                                 leftSortName,
1052                                 rightSortName);
1053
1054         /* ----------------
1055          *      Now fill in information in the operator's associated
1056          *      operators.
1057          *
1058          *      These operators should be defined or have shells defined.
1059          * ----------------
1060          */
1061         definedOK = 1;
1062
1063         if (!OidIsValid(commObjectId) && commutatorName)
1064                 OperatorDef(commutatorName,
1065                                         definedOK,
1066                                         leftTypeName,           /* should eventually */
1067                                         rightTypeName,          /* commute order */
1068                                         procedureName,
1069                                         precedence,
1070                                         isLeftAssociative,
1071                                         operatorName,           /* commutator */
1072                                         negatorName,
1073                                         restrictionName,
1074                                         joinName,
1075                                         canHash,
1076                                         rightSortName,
1077                                         leftSortName);
1078
1079         if (negatorName && !OidIsValid(negObjectId))
1080                 OperatorDef(negatorName,
1081                                         definedOK,
1082                                         leftTypeName,
1083                                         rightTypeName,
1084                                         procedureName,
1085                                         precedence,
1086                                         isLeftAssociative,
1087                                         commutatorName,
1088                                         operatorName,           /* negator */
1089                                         restrictionName,
1090                                         joinName,
1091                                         canHash,
1092                                         leftSortName,
1093                                         rightSortName);
1094
1095         if (leftSortName && !OidIsValid(leftSortObjectId))
1096                 OperatorDef(leftSortName,
1097                                         definedOK,
1098                                         leftTypeName,
1099                                         rightTypeName,
1100                                         procedureName,
1101                                         precedence,
1102                                         isLeftAssociative,
1103                                         commutatorName,
1104                                         negatorName,
1105                                         restrictionName,
1106                                         joinName,
1107                                         canHash,
1108                                         operatorName,           /* left sort */
1109                                         rightSortName);
1110
1111         if (rightSortName && !OidIsValid(rightSortObjectId))
1112                 OperatorDef(rightSortName,
1113                                         definedOK,
1114                                         leftTypeName,
1115                                         rightTypeName,
1116                                         procedureName,
1117                                         precedence,
1118                                         isLeftAssociative,
1119                                         commutatorName,
1120                                         negatorName,
1121                                         restrictionName,
1122                                         joinName,
1123                                         canHash,
1124                                         leftSortName,
1125                                         operatorName);          /* right sort */
1126 }