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