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