1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_operator relation
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.14 1997/09/18 20:20:18 momjian Exp $
13 * these routines moved here from commands/define.c and somewhat cleaned up.
15 *-------------------------------------------------------------------------
19 #include <catalog/pg_proc.h>
20 #include <utils/syscache.h>
21 #include <access/heapam.h>
22 #include <parser/catalog_utils.h>
23 #include <catalog/catname.h>
24 #include <catalog/pg_operator.h>
25 #include <storage/bufmgr.h>
27 #include <miscadmin.h>
29 #include <regex/utils.h>
35 OperatorGetWithOpenRelation(Relation pg_operator_desc,
36 const char *operatorName,
40 OperatorGet(char *operatorName,
45 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
50 OperatorShellMake(char *operatorName,
55 OperatorDef(char *operatorName,
61 bool isLeftAssociative,
64 char *restrictionName,
69 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
71 /* ----------------------------------------------------------------
72 * OperatorGetWithOpenRelation
74 * preforms a scan on pg_operator for an operator tuple
75 * with given name and left/right type oids.
76 * ----------------------------------------------------------------
77 * pg_operator_desc -- reldesc for pg_operator
78 * operatorName -- name of operator to fetch
79 * leftObjectId -- left oid of operator to fetch
80 * rightObjectId -- right oid of operator to fetch
83 OperatorGetWithOpenRelation(Relation pg_operator_desc,
84 const char *operatorName,
88 HeapScanDesc pg_operator_scan;
92 static ScanKeyData opKey[3] = {
93 {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
94 {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
95 {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
98 fmgr_info(NameEqualRegProcedure,
99 &opKey[0].sk_func, &opKey[0].sk_nargs);
100 fmgr_info(ObjectIdEqualRegProcedure,
101 &opKey[1].sk_func, &opKey[1].sk_nargs);
102 fmgr_info(ObjectIdEqualRegProcedure,
103 &opKey[2].sk_func, &opKey[2].sk_nargs);
109 opKey[0].sk_argument = PointerGetDatum(operatorName);
110 opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
111 opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
117 pg_operator_scan = heap_beginscan(pg_operator_desc,
124 * fetch the operator tuple, if it exists, and determine
125 * the proper return oid value.
128 tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
129 operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
132 * close the scan and return the oid.
135 heap_endscan(pg_operator_scan);
141 /* ----------------------------------------------------------------
144 * finds the operator associated with the specified name
145 * and left and right type names.
146 * ----------------------------------------------------------------
149 OperatorGet(char *operatorName,
153 Relation pg_operator_desc;
155 Oid operatorObjectId;
156 Oid leftObjectId = InvalidOid;
157 Oid rightObjectId = InvalidOid;
158 bool leftDefined = false;
159 bool rightDefined = false;
162 * look up the operator types.
164 * Note: types must be defined before operators
169 leftObjectId = TypeGet(leftTypeName, &leftDefined);
171 if (!OidIsValid(leftObjectId) || !leftDefined)
172 elog(WARN, "OperatorGet: left type '%s' nonexistent", leftTypeName);
177 rightObjectId = TypeGet(rightTypeName, &rightDefined);
179 if (!OidIsValid(rightObjectId) || !rightDefined)
180 elog(WARN, "OperatorGet: right type '%s' nonexistent",
184 if (!((OidIsValid(leftObjectId) && leftDefined) ||
185 (OidIsValid(rightObjectId) && rightDefined)))
186 elog(WARN, "OperatorGet: no argument types??");
189 * open the pg_operator relation
192 pg_operator_desc = heap_openr(OperatorRelationName);
195 * get the oid for the operator with the appropriate name
196 * and left/right types.
199 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
205 * close the relation and return the operator oid.
208 heap_close(pg_operator_desc);
214 /* ----------------------------------------------------------------
215 * OperatorShellMakeWithOpenRelation
217 * ----------------------------------------------------------------
220 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
227 Datum values[Natts_pg_operator];
228 char nulls[Natts_pg_operator];
229 Oid operatorObjectId;
233 * initialize our nulls[] and values[] arrays
236 for (i = 0; i < Natts_pg_operator; ++i)
239 values[i] = (Datum) NULL; /* redundant, but safe */
243 * initialize values[] with the type name and
247 values[i++] = PointerGetDatum(operatorName);
248 values[i++] = Int32GetDatum(GetUserId());
249 values[i++] = (Datum) (uint16) 0;
251 values[i++] = (Datum) 'b'; /* fill oprkind with a bogus value */
253 values[i++] = (Datum) (bool) 0;
254 values[i++] = (Datum) (bool) 0;
255 values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
256 values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
257 values[i++] = ObjectIdGetDatum(InvalidOid);
258 values[i++] = ObjectIdGetDatum(InvalidOid);
259 values[i++] = ObjectIdGetDatum(InvalidOid);
260 values[i++] = ObjectIdGetDatum(InvalidOid);
261 values[i++] = ObjectIdGetDatum(InvalidOid);
262 values[i++] = ObjectIdGetDatum(InvalidOid);
263 values[i++] = ObjectIdGetDatum(InvalidOid);
264 values[i++] = ObjectIdGetDatum(InvalidOid);
267 * create a new operator tuple
270 tupDesc = pg_operator_desc->rd_att;
272 tup = heap_formtuple(tupDesc,
277 * insert our "shell" operator tuple and
281 heap_insert(pg_operator_desc, tup);
282 operatorObjectId = tup->t_oid;
285 * free the tuple and return the operator oid
294 /* ----------------------------------------------------------------
297 * Specify operator name and left and right type names,
298 * fill an operator struct with this info and NULL's,
299 * call heap_insert and return the Oid
301 * ----------------------------------------------------------------
304 OperatorShellMake(char *operatorName,
308 Relation pg_operator_desc;
309 Oid operatorObjectId;
311 Oid leftObjectId = InvalidOid;
312 Oid rightObjectId = InvalidOid;
313 bool leftDefined = false;
314 bool rightDefined = false;
317 * get the left and right type oid's for this operator
321 leftObjectId = TypeGet(leftTypeName, &leftDefined);
324 rightObjectId = TypeGet(rightTypeName, &rightDefined);
326 if (!((OidIsValid(leftObjectId) && leftDefined) ||
327 (OidIsValid(rightObjectId) && rightDefined)))
328 elog(WARN, "OperatorShellMake: no valid argument types??");
334 pg_operator_desc = heap_openr(OperatorRelationName);
337 * add a "shell" operator tuple to the operator relation
338 * and recover the shell tuple's oid.
342 OperatorShellMakeWithOpenRelation(pg_operator_desc,
347 * close the operator relation and return the oid.
350 heap_close(pg_operator_desc);
356 /* --------------------------------
359 * This routine gets complicated because it allows the user to
360 * specify operators that do not exist. For example, if operator
361 * "op" is being defined, the negator operator "negop" and the
362 * commutator "commop" can also be defined without specifying
363 * any information other than their names. Since in order to
364 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
365 * operators must be placed in the fields of "op", a forward
366 * declaration is done on the commutator and negator operators.
367 * This is called creating a shell, and its main effect is to
368 * create a tuple in the PG_OPERATOR catalog with minimal
369 * information about the operator (just its name and types).
370 * Forward declaration is used only for this purpose, it is
371 * not available to the user as it is for type definition.
375 * check if operator already defined
376 * if so issue error if not definedOk, this is a duplicate
377 * but if definedOk, save the Oid -- filling in a shell
378 * get the attribute types from relation descriptor for pg_operator
379 * assign values to the fields of the operator:
381 * owner id (simply the user id of the caller)
383 * operator "kind" either "b" for binary or "l" for left unary
384 * isLeftAssociative boolean
386 * leftTypeObjectId -- type must already be defined
387 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
388 * resultType -- defer this, since it must be determined from
389 * the pg_procedure catalog
390 * commutatorObjectId -- if this is NULL, enter ObjectId=0
391 * else if this already exists, enter it's ObjectId
392 * else if this does not yet exist, and is not
393 * the same as the main operatorName, then create
394 * a shell and enter the new ObjectId
395 * else if this does not exist but IS the same
396 * name as the main operator, set the ObjectId=0.
397 * Later OperatorCreate will make another call
398 * to OperatorDef which will cause this field
399 * to be filled in (because even though the names
400 * will be switched, they are the same name and
401 * at this point this ObjectId will then be defined)
402 * negatorObjectId -- same as for commutatorObjectId
403 * leftSortObjectId -- same as for commutatorObjectId
404 * rightSortObjectId -- same as for commutatorObjectId
405 * operatorProcedure -- must access the pg_procedure catalog to get the
406 * ObjectId of the procedure that actually does the operator
407 * actions this is required. Do an amgetattr to find out the
408 * return type of the procedure
409 * restrictionProcedure -- must access the pg_procedure catalog to get
410 * the ObjectId but this is optional
411 * joinProcedure -- same as restrictionProcedure
412 * now either insert or replace the operator into the pg_operator catalog
413 * if the operator shell is being filled in
414 * access the catalog in order to get a valid buffer
415 * create a tuple using ModifyHeapTuple
416 * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple
417 * else if a new operator is being created
418 * create a tuple using heap_formtuple
420 * --------------------------------
421 * "X" indicates an optional argument (i.e. one that can be NULL)
422 * operatorName; -- operator name
423 * definedOK; -- operator can already have an oid?
424 * leftTypeName; -- X left type name
425 * rightTypeName; -- X right type name
426 * procedureName; -- procedure oid for operator code
427 * precedence; -- operator precedence
428 * isLeftAssociative; -- operator is left associative?
429 * commutatorName; -- X commutator operator name
430 * negatorName; -- X negator operator name
431 * restrictionName; -- X restriction sel. procedure name
432 * joinName; -- X join sel. procedure name
433 * canHash; -- possible hash operator?
434 * leftSortName; -- X left sort operator
435 * rightSortName; -- X right sort operator
438 OperatorDef(char *operatorName,
444 bool isLeftAssociative,
445 char *commutatorName,
447 char *restrictionName,
455 Relation pg_operator_desc;
457 HeapScanDesc pg_operator_scan;
460 ItemPointerData itemPointerData;
461 char nulls[Natts_pg_operator];
462 char replaces[Natts_pg_operator];
463 Datum values[Natts_pg_operator];
465 Oid operatorObjectId;
466 Oid leftTypeId = InvalidOid;
467 Oid rightTypeId = InvalidOid;
468 Oid commutatorId = InvalidOid;
469 Oid negatorId = InvalidOid;
470 bool leftDefined = false;
471 bool rightDefined = false;
477 static ScanKeyData opKey[3] = {
478 {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
479 {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
480 {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
483 fmgr_info(NameEqualRegProcedure,
484 &opKey[0].sk_func, &opKey[0].sk_nargs);
485 fmgr_info(ObjectIdEqualRegProcedure,
486 &opKey[1].sk_func, &opKey[1].sk_nargs);
487 fmgr_info(ObjectIdEqualRegProcedure,
488 &opKey[2].sk_func, &opKey[2].sk_nargs);
490 operatorObjectId = OperatorGet(operatorName,
494 if (OidIsValid(operatorObjectId) && !definedOK)
495 elog(WARN, "OperatorDef: operator \"%s\" already defined",
499 leftTypeId = TypeGet(leftTypeName, &leftDefined);
502 rightTypeId = TypeGet(rightTypeName, &rightDefined);
504 if (!((OidIsValid(leftTypeId && leftDefined)) ||
505 (OidIsValid(rightTypeId && rightDefined))))
506 elog(WARN, "OperatorGet: no argument types??");
508 for (i = 0; i < Natts_pg_operator; ++i)
510 values[i] = (Datum) NULL;
516 * Look up registered procedures -- find the return type
517 * of procedureName to place in "result" field.
518 * Do this before shells are created so we don't
519 * have to worry about deleting them later.
522 MemSet(typeId, 0, 8 * sizeof(Oid));
525 typeId[0] = rightTypeId;
528 else if (!rightTypeName)
530 typeId[0] = leftTypeId;
535 typeId[0] = leftTypeId;
536 typeId[1] = rightTypeId;
539 tup = SearchSysCacheTuple(PRONAME,
540 PointerGetDatum(procedureName),
541 Int32GetDatum(nargs),
542 PointerGetDatum(typeId),
545 if (!PointerIsValid(tup))
546 func_error("OperatorDef", procedureName, nargs, typeId);
548 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_oid);
549 values[Anum_pg_operator_oprresult - 1] =
550 ObjectIdGetDatum(((Form_pg_proc)
551 GETSTRUCT(tup))->prorettype);
559 MemSet(typeId, 0, 8 * sizeof(Oid));
560 typeId[0] = OIDOID; /* operator OID */
561 typeId[1] = OIDOID; /* relation OID */
562 typeId[2] = INT2OID; /* attribute number */
563 typeId[3] = 0; /* value - can be any type */
564 typeId[4] = INT4OID; /* flags - left or right selectivity */
565 tup = SearchSysCacheTuple(PRONAME,
566 PointerGetDatum(restrictionName),
568 PointerGetDatum(typeId),
570 if (!HeapTupleIsValid(tup))
571 func_error("OperatorDef", restrictionName, 5, typeId);
573 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_oid);
576 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
579 * find join - only valid for binary operators
584 MemSet(typeId, 0, 8 * sizeof(Oid));
585 typeId[0] = OIDOID; /* operator OID */
586 typeId[1] = OIDOID; /* relation OID 1 */
587 typeId[2] = INT2OID; /* attribute number 1 */
588 typeId[3] = OIDOID; /* relation OID 2 */
589 typeId[4] = INT2OID; /* attribute number 2 */
591 tup = SearchSysCacheTuple(PRONAME,
592 PointerGetDatum(joinName),
594 PointerGetDatum(typeId),
596 if (!HeapTupleIsValid(tup))
597 func_error("OperatorDef", joinName, 5, typeId);
599 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_oid);
602 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
605 * set up values in the operator tuple
609 values[i++] = PointerGetDatum(operatorName);
610 values[i++] = Int32GetDatum(GetUserId());
611 values[i++] = UInt16GetDatum(precedence);
612 values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
613 values[i++] = Int8GetDatum(isLeftAssociative);
614 values[i++] = Int8GetDatum(canHash);
615 values[i++] = ObjectIdGetDatum(leftTypeId);
616 values[i++] = ObjectIdGetDatum(rightTypeId);
618 ++i; /* Skip "prorettype", this was done above */
621 * Set up the other operators. If they do not currently exist, set up
622 * shells in order to get ObjectId's and call OperatorDef again later
623 * to fill in the shells.
625 name[0] = commutatorName;
626 name[1] = negatorName;
627 name[2] = leftSortName;
628 name[3] = rightSortName;
630 for (j = 0; j < 4; ++j)
635 /* for the commutator, switch order of arguments */
638 other_oid = OperatorGet(name[j], rightTypeName, leftTypeName);
639 commutatorId = other_oid;
643 other_oid = OperatorGet(name[j], leftTypeName, rightTypeName);
645 negatorId = other_oid;
648 if (OidIsValid(other_oid)) /* already in catalogs */
649 values[i++] = ObjectIdGetDatum(other_oid);
650 else if (strcmp(operatorName, name[j]) != 0)
652 /* not in catalogs, different from operator */
654 /* for the commutator, switch order of arguments */
657 other_oid = OperatorShellMake(name[j],
663 other_oid = OperatorShellMake(name[j],
668 if (!OidIsValid(other_oid))
670 "OperatorDef: can't create operator '%s'",
672 values[i++] = ObjectIdGetDatum(other_oid);
676 /* not in catalogs, same as operator ??? */
677 values[i++] = ObjectIdGetDatum(InvalidOid);
681 /* new operator is optional */
682 values[i++] = ObjectIdGetDatum(InvalidOid);
685 /* last three fields were filled in first */
688 * If we are adding to an operator shell, get its t_ctid and a buffer.
690 pg_operator_desc = heap_openr(OperatorRelationName);
692 if (operatorObjectId)
694 opKey[0].sk_argument = PointerGetDatum(operatorName);
695 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
696 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
698 pg_operator_scan = heap_beginscan(pg_operator_desc,
704 tup = heap_getnext(pg_operator_scan, 0, &buffer);
705 if (HeapTupleIsValid(tup))
707 tup = heap_modifytuple(tup,
714 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
715 setheapoverride(true);
716 heap_replace(pg_operator_desc, &itemPointerData, tup);
717 setheapoverride(false);
720 elog(WARN, "OperatorDef: no operator %d", other_oid);
722 heap_endscan(pg_operator_scan);
727 tupDesc = pg_operator_desc->rd_att;
728 tup = heap_formtuple(tupDesc, values, nulls);
730 heap_insert(pg_operator_desc, tup);
731 operatorObjectId = tup->t_oid;
734 heap_close(pg_operator_desc);
737 * It's possible that we're creating a skeleton operator here for the
738 * commute or negate attributes of a real operator. If we are, then
739 * we're done. If not, we may need to update the negator and
740 * commutator for this attribute. The reason for this is that the
741 * user may want to create two operators (say < and >=). When he
742 * defines <, if he uses >= as the negator or commutator, he won't be
743 * able to insert it later, since (for some reason) define operator
744 * defines it for him. So what he does is to define > without a
745 * negator or commutator. Then he defines >= with < as the negator
746 * and commutator. As a side effect, this will update the > tuple if
747 * it has no commutator or negator defined.
749 * Alstublieft, Tom Vijlbrief.
752 OperatorUpd(operatorObjectId, commutatorId, negatorId);
755 /* ----------------------------------------------------------------
758 * For a given operator, look up its negator and commutator operators.
759 * If they are defined, but their negator and commutator operators
760 * (respectively) are not, then use the new operator for neg and comm.
761 * This solves a problem for users who need to insert two new operators
762 * which are the negator or commutator of each other.
763 * ----------------------------------------------------------------
766 OperatorUpd(Oid baseId, Oid commId, Oid negId)
769 Relation pg_operator_desc;
770 HeapScanDesc pg_operator_scan;
773 ItemPointerData itemPointerData;
774 char nulls[Natts_pg_operator];
775 char replaces[Natts_pg_operator];
776 Datum values[Natts_pg_operator];
778 static ScanKeyData opKey[1] = {
779 {0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure},
782 fmgr_info(ObjectIdEqualRegProcedure,
783 &opKey[0].sk_func, &opKey[0].sk_nargs);
785 for (i = 0; i < Natts_pg_operator; ++i)
787 values[i] = (Datum) NULL;
792 pg_operator_desc = heap_openr(OperatorRelationName);
794 /* check and update the commutator, if necessary */
795 opKey[0].sk_argument = ObjectIdGetDatum(commId);
797 pg_operator_scan = heap_beginscan(pg_operator_desc,
803 tup = heap_getnext(pg_operator_scan, 0, &buffer);
805 /* if the commutator and negator are the same operator, do one update */
808 if (HeapTupleIsValid(tup))
812 t = (OperatorTupleForm) GETSTRUCT(tup);
813 if (!OidIsValid(t->oprcom)
814 || !OidIsValid(t->oprnegate))
817 if (!OidIsValid(t->oprnegate))
819 values[Anum_pg_operator_oprnegate - 1] =
820 ObjectIdGetDatum(baseId);
821 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
824 if (!OidIsValid(t->oprcom))
826 values[Anum_pg_operator_oprcom - 1] =
827 ObjectIdGetDatum(baseId);
828 replaces[Anum_pg_operator_oprcom - 1] = 'r';
831 tup = heap_modifytuple(tup,
838 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
840 setheapoverride(true);
841 heap_replace(pg_operator_desc, &itemPointerData, tup);
842 setheapoverride(false);
846 heap_endscan(pg_operator_scan);
848 heap_close(pg_operator_desc);
850 /* release the buffer properly */
851 if (BufferIsValid(buffer))
852 ReleaseBuffer(buffer);
857 /* if commutator and negator are different, do two updates */
858 if (HeapTupleIsValid(tup) &&
859 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom)))
861 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
862 replaces[Anum_pg_operator_oprcom - 1] = 'r';
863 tup = heap_modifytuple(tup,
870 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
871 setheapoverride(true);
872 heap_replace(pg_operator_desc, &itemPointerData, tup);
873 setheapoverride(false);
875 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
876 replaces[Anum_pg_operator_oprcom - 1] = ' ';
878 /* release the buffer properly */
879 if (BufferIsValid(buffer))
880 ReleaseBuffer(buffer);
884 /* check and update the negator, if necessary */
885 opKey[0].sk_argument = ObjectIdGetDatum(negId);
887 pg_operator_scan = heap_beginscan(pg_operator_desc,
893 tup = heap_getnext(pg_operator_scan, 0, &buffer);
894 if (HeapTupleIsValid(tup) &&
895 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate)))
897 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
898 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
899 tup = heap_modifytuple(tup,
906 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
908 setheapoverride(true);
909 heap_replace(pg_operator_desc, &itemPointerData, tup);
910 setheapoverride(false);
913 /* release the buffer properly */
914 if (BufferIsValid(buffer))
915 ReleaseBuffer(buffer);
917 heap_endscan(pg_operator_scan);
919 heap_close(pg_operator_desc);
923 /* ----------------------------------------------------------------
928 * Since the commutator, negator, leftsortoperator, and rightsortoperator
929 * can be defined implicitly through OperatorCreate, must check before
930 * the main operator is added to see if they already exist. If they
931 * do not already exist, OperatorDef makes a "shell" for each undefined
932 * one, and then OperatorCreate must call OperatorDef again to fill in
933 * each shell. All this is necessary in order to get the right ObjectId's
934 * filled into the right fields.
936 * The "definedOk" flag indicates that OperatorDef can be called on
937 * the operator even though it already has an entry in the PG_OPERATOR
938 * relation. This allows shells to be filled in. The user cannot
939 * forward declare operators, this is strictly an internal capability.
941 * When the shells are filled in by subsequent calls to OperatorDef,
942 * all the fields are the same as the definition of the original operator
943 * except that the target operator name and the original operatorName
944 * are switched. In the case of commutator and negator, special flags
945 * are set to indicate their status, telling the executor(?) that
946 * the operands are to be switched, or the outcome of the procedure
949 * ************************* NOTE NOTE NOTE ******************************
951 * If the execution of this utility is interrupted, the pg_operator
952 * catalog may be left in an inconsistent state. Similarly, if
953 * something is removed from the pg_operator, pg_type, or pg_procedure
954 * catalog while this is executing, the results may be inconsistent.
955 * ----------------------------------------------------------------
957 * "X" indicates an optional argument (i.e. one that can be NULL)
958 * operatorName; -- operator name
959 * leftTypeName; -- X left type name
960 * rightTypeName; -- X right type name
961 * procedureName; -- procedure for operator
962 * precedence; -- operator precedence
963 * isLeftAssociative; -- operator is left associative
964 * commutatorName; -- X commutator operator name
965 * negatorName; -- X negator operator name
966 * restrictionName; -- X restriction sel. procedure
967 * joinName; -- X join sel. procedure name
968 * canHash; -- operator hashes
969 * leftSortName; -- X left sort operator
970 * rightSortName; -- X right sort operator
974 OperatorCreate(char *operatorName,
979 bool isLeftAssociative,
980 char *commutatorName,
982 char *restrictionName,
990 Oid leftSortObjectId,
994 if (!leftTypeName && !rightTypeName)
995 elog(WARN, "OperatorCreate : at least one of leftarg or rightarg must be defined");
998 * get the oid's of the operator's associated operators, if possible.
1002 commObjectId = OperatorGet(commutatorName, /* commute type order */
1009 negObjectId = OperatorGet(negatorName,
1016 leftSortObjectId = OperatorGet(leftSortName,
1020 leftSortObjectId = 0;
1023 rightSortObjectId = OperatorGet(rightSortName,
1027 rightSortObjectId = 0;
1030 * Use OperatorDef() to define the specified operator and
1031 * also create shells for the operator's associated operators
1032 * if they don't already exist.
1034 * This operator should not be defined yet.
1039 OperatorDef(operatorName,
1055 * Now fill in information in the operator's associated
1058 * These operators should be defined or have shells defined.
1063 if (!OidIsValid(commObjectId) && commutatorName)
1064 OperatorDef(commutatorName,
1066 leftTypeName, /* should eventually */
1067 rightTypeName, /* commute order */
1071 operatorName, /* commutator */
1079 if (negatorName && !OidIsValid(negObjectId))
1080 OperatorDef(negatorName,
1088 operatorName, /* negator */
1095 if (leftSortName && !OidIsValid(leftSortObjectId))
1096 OperatorDef(leftSortName,
1108 operatorName, /* left sort */
1111 if (rightSortName && !OidIsValid(rightSortObjectId))
1112 OperatorDef(rightSortName,
1125 operatorName); /* right sort */