]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_operator.c
a0c6dd70a385d0e095c043b7c58f00fdae3c4ac0
[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.51 2000/08/21 17:22:35 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' nonexistent",
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' nonexistent",
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' nonexistent",
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' nonexistent",
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 = SearchSysCacheTuple(PROCNAME,
579                                                           PointerGetDatum(procedureName),
580                                                           Int32GetDatum(nargs),
581                                                           PointerGetDatum(typeId),
582                                                           0);
583
584         if (!HeapTupleIsValid(tup))
585                 func_error("OperatorDef", procedureName, nargs, typeId, NULL);
586
587         values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
588         values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
589                                                                                         GETSTRUCT(tup))->prorettype);
590
591         /* ----------------
592          *      find restriction
593          * ----------------
594          */
595         if (restrictionName)
596         {                                                       /* optional */
597                 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
598                 typeId[0] = OIDOID;             /* operator OID */
599                 typeId[1] = OIDOID;             /* relation OID */
600                 typeId[2] = INT2OID;    /* attribute number */
601                 typeId[3] = 0;                  /* value - can be any type      */
602                 typeId[4] = INT4OID;    /* flags - left or right selectivity */
603                 tup = SearchSysCacheTuple(PROCNAME,
604                                                                   PointerGetDatum(restrictionName),
605                                                                   Int32GetDatum(5),
606                                                                   PointerGetDatum(typeId),
607                                                                   0);
608                 if (!HeapTupleIsValid(tup))
609                         func_error("OperatorDef", restrictionName, 5, typeId, NULL);
610
611                 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
612         }
613         else
614                 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
615
616         /* ----------------
617          *      find join - only valid for binary operators
618          * ----------------
619          */
620         if (joinName)
621         {                                                       /* optional */
622                 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
623                 typeId[0] = OIDOID;             /* operator OID */
624                 typeId[1] = OIDOID;             /* relation OID 1 */
625                 typeId[2] = INT2OID;    /* attribute number 1 */
626                 typeId[3] = OIDOID;             /* relation OID 2 */
627                 typeId[4] = INT2OID;    /* attribute number 2 */
628
629                 tup = SearchSysCacheTuple(PROCNAME,
630                                                                   PointerGetDatum(joinName),
631                                                                   Int32GetDatum(5),
632                                                                   PointerGetDatum(typeId),
633                                                                   0);
634                 if (!HeapTupleIsValid(tup))
635                         func_error("OperatorDef", joinName, 5, typeId, NULL);
636
637                 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
638         }
639         else
640                 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
641
642         /* ----------------
643          * set up values in the operator tuple
644          * ----------------
645          */
646         i = 0;
647         namestrcpy(&oname, operatorName);
648         values[i++] = NameGetDatum(&oname);
649         values[i++] = Int32GetDatum(GetUserId());
650         values[i++] = UInt16GetDatum(precedence);
651         values[i++] = CharGetDatum(leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l');
652         values[i++] = BoolGetDatum(isLeftAssociative);
653         values[i++] = BoolGetDatum(canHash);
654         values[i++] = ObjectIdGetDatum(leftTypeId);
655         values[i++] = ObjectIdGetDatum(rightTypeId);
656
657         ++i;                                            /* Skip "oprresult", it was filled in
658                                                                  * above */
659
660         /*
661          * Set up the other operators.  If they do not currently exist, create
662          * shells in order to get ObjectId's.
663          */
664         name[0] = commutatorName;
665         name[1] = negatorName;
666         name[2] = leftSortName;
667         name[3] = rightSortName;
668
669         for (j = 0; j < 4; ++j)
670         {
671                 if (name[j])
672                 {
673                         char       *otherLeftTypeName = NULL;
674                         char       *otherRightTypeName = NULL;
675                         Oid                     otherLeftTypeId = InvalidOid;
676                         Oid                     otherRightTypeId = InvalidOid;
677                         Oid                     other_oid = InvalidOid;
678                         bool            otherDefined = false;
679
680                         switch (j)
681                         {
682                                 case 0: /* commutator has reversed arg types */
683                                         otherLeftTypeName = rightTypeName;
684                                         otherRightTypeName = leftTypeName;
685                                         otherLeftTypeId = rightTypeId;
686                                         otherRightTypeId = leftTypeId;
687                                         other_oid = OperatorGet(name[j],
688                                                                                         otherLeftTypeName,
689                                                                                         otherRightTypeName,
690                                                                                         &otherDefined);
691                                         commutatorId = other_oid;
692                                         break;
693                                 case 1: /* negator has same arg types */
694                                         otherLeftTypeName = leftTypeName;
695                                         otherRightTypeName = rightTypeName;
696                                         otherLeftTypeId = leftTypeId;
697                                         otherRightTypeId = rightTypeId;
698                                         other_oid = OperatorGet(name[j],
699                                                                                         otherLeftTypeName,
700                                                                                         otherRightTypeName,
701                                                                                         &otherDefined);
702                                         negatorId = other_oid;
703                                         break;
704                                 case 2: /* left sort op takes left-side data type */
705                                         otherLeftTypeName = leftTypeName;
706                                         otherRightTypeName = leftTypeName;
707                                         otherLeftTypeId = leftTypeId;
708                                         otherRightTypeId = leftTypeId;
709                                         other_oid = OperatorGet(name[j],
710                                                                                         otherLeftTypeName,
711                                                                                         otherRightTypeName,
712                                                                                         &otherDefined);
713                                         break;
714                                 case 3: /* right sort op takes right-side data
715                                                                  * type */
716                                         otherLeftTypeName = rightTypeName;
717                                         otherRightTypeName = rightTypeName;
718                                         otherLeftTypeId = rightTypeId;
719                                         otherRightTypeId = rightTypeId;
720                                         other_oid = OperatorGet(name[j],
721                                                                                         otherLeftTypeName,
722                                                                                         otherRightTypeName,
723                                                                                         &otherDefined);
724                                         break;
725                         }
726
727                         if (OidIsValid(other_oid))
728                         {
729                                 /* other op already in catalogs */
730                                 values[i++] = ObjectIdGetDatum(other_oid);
731                         }
732                         else if (strcmp(operatorName, name[j]) != 0 ||
733                                          otherLeftTypeId != leftTypeId ||
734                                          otherRightTypeId != rightTypeId)
735                         {
736                                 /* not in catalogs, different from operator */
737                                 other_oid = OperatorShellMake(name[j],
738                                                                                           otherLeftTypeName,
739                                                                                           otherRightTypeName);
740                                 if (!OidIsValid(other_oid))
741                                         elog(ERROR,
742                                                  "OperatorDef: can't create operator shell '%s'",
743                                                  name[j]);
744                                 values[i++] = ObjectIdGetDatum(other_oid);
745                         }
746                         else
747                         {
748
749                                 /*
750                                  * self-linkage to this operator; will fix below. Note
751                                  * that only self-linkage for commutation makes sense.
752                                  */
753                                 if (j != 0)
754                                         elog(ERROR,
755                                                  "OperatorDef: operator can't be its own negator or sort op");
756                                 selfCommutator = true;
757                                 values[i++] = ObjectIdGetDatum(InvalidOid);
758                         }
759                 }
760                 else
761                 {
762                         /* other operator is omitted */
763                         values[i++] = ObjectIdGetDatum(InvalidOid);
764                 }
765         }
766
767         /* last three fields were filled in above */
768
769         pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
770
771         /*
772          * If we are adding to an operator shell, get its t_self
773          */
774         if (operatorObjectId)
775         {
776                 opKey[0].sk_argument = PointerGetDatum(operatorName);
777                 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
778                 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
779
780                 /* Make sure we can see the shell even if it is new in current cmd */
781                 CommandCounterIncrement();
782
783                 pg_operator_scan = heap_beginscan(pg_operator_desc,
784                                                                                   0,
785                                                                                   SnapshotSelf, /* no cache? */
786                                                                                   3,
787                                                                                   opKey);
788
789                 tup = heap_getnext(pg_operator_scan, 0);
790                 if (HeapTupleIsValid(tup))
791                 {
792                         tup = heap_modifytuple(tup,
793                                                                    pg_operator_desc,
794                                                                    values,
795                                                                    nulls,
796                                                                    replaces);
797
798                         heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
799                 }
800                 else
801                         elog(ERROR, "OperatorDef: no operator %u", operatorObjectId);
802
803                 heap_endscan(pg_operator_scan);
804         }
805         else
806         {
807                 tupDesc = pg_operator_desc->rd_att;
808                 tup = heap_formtuple(tupDesc, values, nulls);
809
810                 heap_insert(pg_operator_desc, tup);
811                 operatorObjectId = tup->t_data->t_oid;
812
813         }
814
815         if (RelationGetForm(pg_operator_desc)->relhasindex)
816         {
817                 Relation        idescs[Num_pg_operator_indices];
818
819                 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
820                 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
821                 CatalogCloseIndices(Num_pg_operator_indices, idescs);
822         }
823
824         heap_close(pg_operator_desc, RowExclusiveLock);
825
826         /*
827          * If a commutator and/or negator link is provided, update the other
828          * operator(s) to point at this one, if they don't already have a
829          * link. This supports an alternate style of operator definition
830          * wherein the user first defines one operator without giving negator
831          * or commutator, then defines the other operator of the pair with the
832          * proper commutator or negator attribute.      That style doesn't require
833          * creation of a shell, and it's the only style that worked right
834          * before Postgres version 6.5. This code also takes care of the
835          * situation where the new operator is its own commutator.
836          */
837         if (selfCommutator)
838                 commutatorId = operatorObjectId;
839
840         if (OidIsValid(commutatorId) || OidIsValid(negatorId))
841                 OperatorUpd(operatorObjectId, commutatorId, negatorId);
842 }
843
844 /* ----------------------------------------------------------------
845  * OperatorUpd
846  *
847  *      For a given operator, look up its negator and commutator operators.
848  *      If they are defined, but their negator and commutator fields
849  *      (respectively) are empty, then use the new operator for neg or comm.
850  *      This solves a problem for users who need to insert two new operators
851  *      which are the negator or commutator of each other.
852  * ----------------------------------------------------------------
853  */
854 static void
855 OperatorUpd(Oid baseId, Oid commId, Oid negId)
856 {
857         int                     i;
858         Relation        pg_operator_desc;
859         HeapScanDesc pg_operator_scan;
860         HeapTuple       tup;
861         char            nulls[Natts_pg_operator];
862         char            replaces[Natts_pg_operator];
863         Datum           values[Natts_pg_operator];
864
865         static ScanKeyData opKey[1] = {
866                 {0, ObjectIdAttributeNumber, F_OIDEQ},
867         };
868
869         fmgr_info(F_OIDEQ, &opKey[0].sk_func);
870         opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
871
872         for (i = 0; i < Natts_pg_operator; ++i)
873         {
874                 values[i] = (Datum) NULL;
875                 replaces[i] = ' ';
876                 nulls[i] = ' ';
877         }
878
879         pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
880
881         /*
882          * check and update the commutator & negator, if necessary
883          *
884          * First make sure we can see them...
885          */
886         CommandCounterIncrement();
887
888         opKey[0].sk_argument = ObjectIdGetDatum(commId);
889
890         pg_operator_scan = heap_beginscan(pg_operator_desc,
891                                                                           0,
892                                                                           SnapshotSelf,         /* no cache? */
893                                                                           1,
894                                                                           opKey);
895
896         tup = heap_getnext(pg_operator_scan, 0);
897
898         /*
899          * if the commutator and negator are the same operator, do one update.
900          * XXX this is probably useless code --- I doubt it ever makes sense
901          * for commutator and negator to be the same thing...
902          */
903         if (commId == negId)
904         {
905                 if (HeapTupleIsValid(tup))
906                 {
907                         Form_pg_operator t;
908
909                         t = (Form_pg_operator) GETSTRUCT(tup);
910                         if (!OidIsValid(t->oprcom)
911                                 || !OidIsValid(t->oprnegate))
912                         {
913
914                                 if (!OidIsValid(t->oprnegate))
915                                 {
916                                         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
917                                         replaces[Anum_pg_operator_oprnegate - 1] = 'r';
918                                 }
919
920                                 if (!OidIsValid(t->oprcom))
921                                 {
922                                         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
923                                         replaces[Anum_pg_operator_oprcom - 1] = 'r';
924                                 }
925
926                                 tup = heap_modifytuple(tup,
927                                                                            pg_operator_desc,
928                                                                            values,
929                                                                            nulls,
930                                                                            replaces);
931
932                                 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
933
934                                 if (RelationGetForm(pg_operator_desc)->relhasindex)
935                                 {
936                                         Relation        idescs[Num_pg_operator_indices];
937
938                                         CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
939                                         CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
940                                         CatalogCloseIndices(Num_pg_operator_indices, idescs);
941                                 }
942                         }
943                 }
944                 heap_endscan(pg_operator_scan);
945
946                 heap_close(pg_operator_desc, RowExclusiveLock);
947
948                 return;
949         }
950
951         /* if commutator and negator are different, do two updates */
952
953         if (HeapTupleIsValid(tup) &&
954                 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
955         {
956                 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
957                 replaces[Anum_pg_operator_oprcom - 1] = 'r';
958                 tup = heap_modifytuple(tup,
959                                                            pg_operator_desc,
960                                                            values,
961                                                            nulls,
962                                                            replaces);
963
964                 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
965
966                 if (RelationGetForm(pg_operator_desc)->relhasindex)
967                 {
968                         Relation        idescs[Num_pg_operator_indices];
969
970                         CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
971                         CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
972                         CatalogCloseIndices(Num_pg_operator_indices, idescs);
973                 }
974
975                 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
976                 replaces[Anum_pg_operator_oprcom - 1] = ' ';
977         }
978
979         heap_endscan(pg_operator_scan);
980
981         /* check and update the negator, if necessary */
982         opKey[0].sk_argument = ObjectIdGetDatum(negId);
983
984         pg_operator_scan = heap_beginscan(pg_operator_desc,
985                                                                           0,
986                                                                           SnapshotSelf,         /* no cache? */
987                                                                           1,
988                                                                           opKey);
989
990         tup = heap_getnext(pg_operator_scan, 0);
991         if (HeapTupleIsValid(tup) &&
992                 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
993         {
994                 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
995                 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
996                 tup = heap_modifytuple(tup,
997                                                            pg_operator_desc,
998                                                            values,
999                                                            nulls,
1000                                                            replaces);
1001
1002                 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
1003
1004                 if (RelationGetForm(pg_operator_desc)->relhasindex)
1005                 {
1006                         Relation        idescs[Num_pg_operator_indices];
1007
1008                         CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
1009                         CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
1010                         CatalogCloseIndices(Num_pg_operator_indices, idescs);
1011                 }
1012         }
1013
1014         heap_endscan(pg_operator_scan);
1015
1016
1017         heap_close(pg_operator_desc, RowExclusiveLock);
1018 }
1019
1020
1021 /* ----------------------------------------------------------------
1022  * OperatorCreate
1023  *
1024  * This is now just an interface procedure for OperatorDef ...
1025  *
1026  * "X" indicates an optional argument (i.e. one that can be NULL)
1027  *              operatorName;                   -- operator name
1028  *              leftTypeName;                   -- X left type name
1029  *              rightTypeName;                  -- X right type name
1030  *              procedureName;                  -- procedure for operator
1031  *              precedence;                             -- operator precedence
1032  *              isLeftAssociative;              -- operator is left associative
1033  *              commutatorName;                 -- X commutator operator name
1034  *              negatorName;                    -- X negator operator name
1035  *              restrictionName;                -- X restriction sel. procedure
1036  *              joinName;                               -- X join sel. procedure
1037  *              canHash;                                -- hash join can be used with this operator
1038  *              leftSortName;                   -- X left sort operator (for merge join)
1039  *              rightSortName;                  -- X right sort operator (for merge join)
1040  */
1041 void
1042 OperatorCreate(char *operatorName,
1043                            char *leftTypeName,
1044                            char *rightTypeName,
1045                            char *procedureName,
1046                            uint16 precedence,
1047                            bool isLeftAssociative,
1048                            char *commutatorName,
1049                            char *negatorName,
1050                            char *restrictionName,
1051                            char *joinName,
1052                            bool canHash,
1053                            char *leftSortName,
1054                            char *rightSortName)
1055 {
1056         if (!leftTypeName && !rightTypeName)
1057                 elog(ERROR, "OperatorCreate: at least one of leftarg or rightarg must be defined");
1058
1059         if (!(leftTypeName && rightTypeName))
1060         {
1061                 /* If it's not a binary op, these things mustn't be set: */
1062                 if (commutatorName)
1063                         elog(ERROR, "OperatorCreate: only binary operators can have commutators");
1064                 if (negatorName)
1065                         elog(ERROR, "OperatorCreate: only binary operators can have negators");
1066                 if (restrictionName || joinName)
1067                         elog(ERROR, "OperatorCreate: only binary operators can have selectivity");
1068                 if (canHash)
1069                         elog(ERROR, "OperatorCreate: only binary operators can hash");
1070                 if (leftSortName || rightSortName)
1071                         elog(ERROR, "OperatorCreate: only binary operators can have sort links");
1072         }
1073
1074         /* ----------------
1075          *      Use OperatorDef() to define the specified operator and
1076          *      also create shells for the operator's associated operators
1077          *      if they don't already exist.
1078          * ----------------
1079          */
1080         OperatorDef(operatorName,
1081                                 leftTypeName,
1082                                 rightTypeName,
1083                                 procedureName,
1084                                 precedence,
1085                                 isLeftAssociative,
1086                                 commutatorName,
1087                                 negatorName,
1088                                 restrictionName,
1089                                 joinName,
1090                                 canHash,
1091                                 leftSortName,
1092                                 rightSortName);
1093 }