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.29 1998/09/01 04:27:36 momjian Exp $
13 * these routines moved here from commands/define.c and somewhat cleaned up.
15 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "catalog/catname.h"
21 #include "catalog/pg_operator.h"
22 #include "catalog/pg_proc.h"
23 #include "catalog/pg_type.h"
25 #include "miscadmin.h"
26 #include "parser/parse_oper.h"
27 #include "storage/bufmgr.h"
28 #include "utils/builtins.h"
29 #include "utils/syscache.h"
30 #include "utils/tqual.h"
33 #include <regex/utils.h>
38 static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
39 const char *operatorName,
42 static Oid OperatorGet(char *operatorName,
46 static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
50 static Oid OperatorShellMake(char *operatorName,
54 static void OperatorDef(char *operatorName,
60 bool isLeftAssociative,
63 char *restrictionName,
68 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
70 /* ----------------------------------------------------------------
71 * OperatorGetWithOpenRelation
73 * preforms a scan on pg_operator for an operator tuple
74 * with given name and left/right type oids.
75 * ----------------------------------------------------------------
76 * pg_operator_desc -- reldesc for pg_operator
77 * operatorName -- name of operator to fetch
78 * leftObjectId -- left oid of operator to fetch
79 * rightObjectId -- right oid of operator to fetch
82 OperatorGetWithOpenRelation(Relation pg_operator_desc,
83 const char *operatorName,
87 HeapScanDesc pg_operator_scan;
91 static ScanKeyData opKey[3] = {
92 {0, Anum_pg_operator_oprname, F_NAMEEQ},
93 {0, Anum_pg_operator_oprleft, F_OIDEQ},
94 {0, Anum_pg_operator_oprright, F_OIDEQ},
97 fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
98 fmgr_info(F_OIDEQ, &opKey[1].sk_func);
99 fmgr_info(F_OIDEQ, &opKey[2].sk_func);
100 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
101 opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
102 opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
108 opKey[0].sk_argument = PointerGetDatum(operatorName);
109 opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
110 opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
116 pg_operator_scan = heap_beginscan(pg_operator_desc,
118 SnapshotSelf, /* no cache? */
123 * fetch the operator tuple, if it exists, and determine
124 * the proper return oid value.
127 tup = heap_getnext(pg_operator_scan, 0);
128 operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
131 * close the scan and return the oid.
134 heap_endscan(pg_operator_scan);
136 return operatorObjectId;
139 /* ----------------------------------------------------------------
142 * finds the operator associated with the specified name
143 * and left and right type names.
144 * ----------------------------------------------------------------
147 OperatorGet(char *operatorName,
151 Relation pg_operator_desc;
153 Oid operatorObjectId;
154 Oid leftObjectId = InvalidOid;
155 Oid rightObjectId = InvalidOid;
156 bool leftDefined = false;
157 bool rightDefined = false;
160 * look up the operator types.
162 * Note: types must be defined before operators
167 leftObjectId = TypeGet(leftTypeName, &leftDefined);
169 if (!OidIsValid(leftObjectId) || !leftDefined)
170 elog(ERROR, "OperatorGet: left type '%s' nonexistent", leftTypeName);
175 rightObjectId = TypeGet(rightTypeName, &rightDefined);
177 if (!OidIsValid(rightObjectId) || !rightDefined)
178 elog(ERROR, "OperatorGet: right type '%s' nonexistent",
182 if (!((OidIsValid(leftObjectId) && leftDefined) ||
183 (OidIsValid(rightObjectId) && rightDefined)))
184 elog(ERROR, "OperatorGet: no argument types??");
187 * open the pg_operator relation
190 pg_operator_desc = heap_openr(OperatorRelationName);
193 * get the oid for the operator with the appropriate name
194 * and left/right types.
197 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
203 * close the relation and return the operator oid.
206 heap_close(pg_operator_desc);
212 /* ----------------------------------------------------------------
213 * OperatorShellMakeWithOpenRelation
215 * ----------------------------------------------------------------
218 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
225 Datum values[Natts_pg_operator];
226 char nulls[Natts_pg_operator];
227 Oid operatorObjectId;
232 * initialize our *nulls and *values arrays
235 for (i = 0; i < Natts_pg_operator; ++i)
238 values[i] = (Datum) NULL; /* redundant, but safe */
242 * initialize *values with the type name and
246 namestrcpy(&oname, operatorName);
247 values[i++] = NameGetDatum(&oname);
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(ERROR, "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;
459 char nulls[Natts_pg_operator];
460 char replaces[Natts_pg_operator];
461 Datum values[Natts_pg_operator];
463 Oid operatorObjectId;
464 Oid leftTypeId = InvalidOid;
465 Oid rightTypeId = InvalidOid;
466 Oid commutatorId = InvalidOid;
467 Oid negatorId = InvalidOid;
468 bool leftDefined = false;
469 bool rightDefined = false;
476 static ScanKeyData opKey[3] = {
477 {0, Anum_pg_operator_oprname, F_NAMEEQ},
478 {0, Anum_pg_operator_oprleft, F_OIDEQ},
479 {0, Anum_pg_operator_oprright, F_OIDEQ},
482 fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
483 fmgr_info(F_OIDEQ, &opKey[1].sk_func);
484 fmgr_info(F_OIDEQ, &opKey[2].sk_func);
485 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
486 opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
487 opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
489 operatorObjectId = OperatorGet(operatorName,
493 if (OidIsValid(operatorObjectId) && !definedOK)
494 elog(ERROR, "OperatorDef: operator \"%s\" already defined",
498 leftTypeId = TypeGet(leftTypeName, &leftDefined);
501 rightTypeId = TypeGet(rightTypeName, &rightDefined);
503 if (!((OidIsValid(leftTypeId && leftDefined)) ||
504 (OidIsValid(rightTypeId && rightDefined))))
505 elog(ERROR, "OperatorGet: no argument types??");
507 for (i = 0; i < Natts_pg_operator; ++i)
509 values[i] = (Datum) NULL;
515 * Look up registered procedures -- find the return type
516 * of procedureName to place in "result" field.
517 * Do this before shells are created so we don't
518 * have to worry about deleting them later.
521 MemSet(typeId, 0, 8 * sizeof(Oid));
524 typeId[0] = rightTypeId;
527 else if (!rightTypeName)
529 typeId[0] = leftTypeId;
534 typeId[0] = leftTypeId;
535 typeId[1] = rightTypeId;
538 tup = SearchSysCacheTuple(PRONAME,
539 PointerGetDatum(procedureName),
540 Int32GetDatum(nargs),
541 PointerGetDatum(typeId),
544 if (!HeapTupleIsValid(tup))
545 func_error("OperatorDef", procedureName, nargs, typeId, NULL);
547 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_oid);
548 values[Anum_pg_operator_oprresult - 1] =
549 ObjectIdGetDatum(((Form_pg_proc)
550 GETSTRUCT(tup))->prorettype);
558 MemSet(typeId, 0, 8 * sizeof(Oid));
559 typeId[0] = OIDOID; /* operator OID */
560 typeId[1] = OIDOID; /* relation OID */
561 typeId[2] = INT2OID; /* attribute number */
562 typeId[3] = 0; /* value - can be any type */
563 typeId[4] = INT4OID; /* flags - left or right selectivity */
564 tup = SearchSysCacheTuple(PRONAME,
565 PointerGetDatum(restrictionName),
567 PointerGetDatum(typeId),
569 if (!HeapTupleIsValid(tup))
570 func_error("OperatorDef", restrictionName, 5, typeId, NULL);
572 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_oid);
575 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
578 * find join - only valid for binary operators
583 MemSet(typeId, 0, 8 * sizeof(Oid));
584 typeId[0] = OIDOID; /* operator OID */
585 typeId[1] = OIDOID; /* relation OID 1 */
586 typeId[2] = INT2OID; /* attribute number 1 */
587 typeId[3] = OIDOID; /* relation OID 2 */
588 typeId[4] = INT2OID; /* attribute number 2 */
590 tup = SearchSysCacheTuple(PRONAME,
591 PointerGetDatum(joinName),
593 PointerGetDatum(typeId),
595 if (!HeapTupleIsValid(tup))
596 func_error("OperatorDef", joinName, 5, typeId, NULL);
598 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_oid);
601 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
604 * set up values in the operator tuple
608 namestrcpy(&oname, operatorName);
609 values[i++] = NameGetDatum(&oname);
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
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,
700 SnapshotSelf, /* no cache? */
704 tup = heap_getnext(pg_operator_scan, 0);
705 if (HeapTupleIsValid(tup))
707 tup = heap_modifytuple(tup,
713 setheapoverride(true);
714 heap_replace(pg_operator_desc, &tup->t_ctid, tup);
715 setheapoverride(false);
718 elog(ERROR, "OperatorDef: no operator %d", other_oid);
720 heap_endscan(pg_operator_scan);
724 tupDesc = pg_operator_desc->rd_att;
725 tup = heap_formtuple(tupDesc, values, nulls);
727 heap_insert(pg_operator_desc, tup);
728 operatorObjectId = tup->t_oid;
731 heap_close(pg_operator_desc);
734 * It's possible that we're creating a skeleton operator here for the
735 * commute or negate attributes of a real operator. If we are, then
736 * we're done. If not, we may need to update the negator and
737 * commutator for this attribute. The reason for this is that the
738 * user may want to create two operators (say < and >=). When he
739 * defines <, if he uses >= as the negator or commutator, he won't be
740 * able to insert it later, since (for some reason) define operator
741 * defines it for him. So what he does is to define > without a
742 * negator or commutator. Then he defines >= with < as the negator
743 * and commutator. As a side effect, this will update the > tuple if
744 * it has no commutator or negator defined.
746 * Alstublieft, Tom Vijlbrief.
749 OperatorUpd(operatorObjectId, commutatorId, negatorId);
752 /* ----------------------------------------------------------------
755 * For a given operator, look up its negator and commutator operators.
756 * If they are defined, but their negator and commutator operators
757 * (respectively) are not, then use the new operator for neg and comm.
758 * This solves a problem for users who need to insert two new operators
759 * which are the negator or commutator of each other.
760 * ----------------------------------------------------------------
763 OperatorUpd(Oid baseId, Oid commId, Oid negId)
766 Relation pg_operator_desc;
767 HeapScanDesc pg_operator_scan;
769 char nulls[Natts_pg_operator];
770 char replaces[Natts_pg_operator];
771 Datum values[Natts_pg_operator];
773 static ScanKeyData opKey[1] = {
774 {0, ObjectIdAttributeNumber, F_OIDEQ},
777 fmgr_info(F_OIDEQ, &opKey[0].sk_func);
778 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
780 for (i = 0; i < Natts_pg_operator; ++i)
782 values[i] = (Datum) NULL;
787 pg_operator_desc = heap_openr(OperatorRelationName);
789 /* check and update the commutator, if necessary */
790 opKey[0].sk_argument = ObjectIdGetDatum(commId);
792 pg_operator_scan = heap_beginscan(pg_operator_desc,
794 SnapshotSelf, /* no cache? */
798 tup = heap_getnext(pg_operator_scan, 0);
800 /* if the commutator and negator are the same operator, do one update */
803 if (HeapTupleIsValid(tup))
807 t = (Form_pg_operator) GETSTRUCT(tup);
808 if (!OidIsValid(t->oprcom)
809 || !OidIsValid(t->oprnegate))
812 if (!OidIsValid(t->oprnegate))
814 values[Anum_pg_operator_oprnegate - 1] =
815 ObjectIdGetDatum(baseId);
816 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
819 if (!OidIsValid(t->oprcom))
821 values[Anum_pg_operator_oprcom - 1] =
822 ObjectIdGetDatum(baseId);
823 replaces[Anum_pg_operator_oprcom - 1] = 'r';
826 tup = heap_modifytuple(tup,
832 setheapoverride(true);
833 heap_replace(pg_operator_desc, &tup->t_ctid, tup);
834 setheapoverride(false);
838 heap_endscan(pg_operator_scan);
840 heap_close(pg_operator_desc);
845 /* if commutator and negator are different, do two updates */
846 if (HeapTupleIsValid(tup) &&
847 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
849 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
850 replaces[Anum_pg_operator_oprcom - 1] = 'r';
851 tup = heap_modifytuple(tup,
857 setheapoverride(true);
858 heap_replace(pg_operator_desc, &tup->t_ctid, tup);
859 setheapoverride(false);
861 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
862 replaces[Anum_pg_operator_oprcom - 1] = ' ';
865 /* check and update the negator, if necessary */
866 opKey[0].sk_argument = ObjectIdGetDatum(negId);
868 pg_operator_scan = heap_beginscan(pg_operator_desc,
870 SnapshotSelf, /* no cache? */
874 tup = heap_getnext(pg_operator_scan, 0);
875 if (HeapTupleIsValid(tup) &&
876 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
878 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
879 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
880 tup = heap_modifytuple(tup,
886 setheapoverride(true);
887 heap_replace(pg_operator_desc, &tup->t_ctid, tup);
888 setheapoverride(false);
891 heap_endscan(pg_operator_scan);
893 heap_close(pg_operator_desc);
897 /* ----------------------------------------------------------------
902 * Since the commutator, negator, leftsortoperator, and rightsortoperator
903 * can be defined implicitly through OperatorCreate, must check before
904 * the main operator is added to see if they already exist. If they
905 * do not already exist, OperatorDef makes a "shell" for each undefined
906 * one, and then OperatorCreate must call OperatorDef again to fill in
907 * each shell. All this is necessary in order to get the right ObjectId's
908 * filled into the right fields.
910 * The "definedOk" flag indicates that OperatorDef can be called on
911 * the operator even though it already has an entry in the PG_OPERATOR
912 * relation. This allows shells to be filled in. The user cannot
913 * forward declare operators, this is strictly an internal capability.
915 * When the shells are filled in by subsequent calls to OperatorDef,
916 * all the fields are the same as the definition of the original operator
917 * except that the target operator name and the original operatorName
918 * are switched. In the case of commutator and negator, special flags
919 * are set to indicate their status, telling the executor(?) that
920 * the operands are to be switched, or the outcome of the procedure
923 * ************************* NOTE NOTE NOTE ******************************
925 * If the execution of this utility is interrupted, the pg_operator
926 * catalog may be left in an inconsistent state. Similarly, if
927 * something is removed from the pg_operator, pg_type, or pg_procedure
928 * catalog while this is executing, the results may be inconsistent.
929 * ----------------------------------------------------------------
931 * "X" indicates an optional argument (i.e. one that can be NULL)
932 * operatorName; -- operator name
933 * leftTypeName; -- X left type name
934 * rightTypeName; -- X right type name
935 * procedureName; -- procedure for operator
936 * precedence; -- operator precedence
937 * isLeftAssociative; -- operator is left associative
938 * commutatorName; -- X commutator operator name
939 * negatorName; -- X negator operator name
940 * restrictionName; -- X restriction sel. procedure
941 * joinName; -- X join sel. procedure name
942 * canHash; -- operator hashes
943 * leftSortName; -- X left sort operator
944 * rightSortName; -- X right sort operator
948 OperatorCreate(char *operatorName,
953 bool isLeftAssociative,
954 char *commutatorName,
956 char *restrictionName,
964 Oid leftSortObjectId,
968 if (!leftTypeName && !rightTypeName)
969 elog(ERROR, "OperatorCreate : at least one of leftarg or rightarg must be defined");
972 * get the oid's of the operator's associated operators, if possible.
976 commObjectId = OperatorGet(commutatorName, /* commute type order */
983 negObjectId = OperatorGet(negatorName,
990 leftSortObjectId = OperatorGet(leftSortName,
994 leftSortObjectId = 0;
997 rightSortObjectId = OperatorGet(rightSortName,
1001 rightSortObjectId = 0;
1004 * Use OperatorDef() to define the specified operator and
1005 * also create shells for the operator's associated operators
1006 * if they don't already exist.
1008 * This operator should not be defined yet.
1013 OperatorDef(operatorName,
1029 * Now fill in information in the operator's associated
1032 * These operators should be defined or have shells defined.
1037 if (!OidIsValid(commObjectId) && commutatorName)
1038 OperatorDef(commutatorName,
1040 leftTypeName, /* should eventually */
1041 rightTypeName, /* commute order */
1045 operatorName, /* commutator */
1053 if (negatorName && !OidIsValid(negObjectId))
1054 OperatorDef(negatorName,
1062 operatorName, /* negator */
1069 if (leftSortName && !OidIsValid(leftSortObjectId))
1070 OperatorDef(leftSortName,
1082 operatorName, /* left sort */
1085 if (rightSortName && !OidIsValid(rightSortObjectId))
1086 OperatorDef(rightSortName,
1099 operatorName); /* right sort */