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