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