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.16 1997/11/24 05:08:15 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 <utils/tqual.h>
22 #include <access/heapam.h>
23 #include <parser/catalog_utils.h>
24 #include <catalog/catname.h>
25 #include <catalog/pg_operator.h>
26 #include <storage/bufmgr.h>
28 #include <miscadmin.h>
30 #include <regex/utils.h>
36 OperatorGetWithOpenRelation(Relation pg_operator_desc,
37 const char *operatorName,
41 OperatorGet(char *operatorName,
46 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
51 OperatorShellMake(char *operatorName,
56 OperatorDef(char *operatorName,
62 bool isLeftAssociative,
65 char *restrictionName,
70 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
72 /* ----------------------------------------------------------------
73 * OperatorGetWithOpenRelation
75 * preforms a scan on pg_operator for an operator tuple
76 * with given name and left/right type oids.
77 * ----------------------------------------------------------------
78 * pg_operator_desc -- reldesc for pg_operator
79 * operatorName -- name of operator to fetch
80 * leftObjectId -- left oid of operator to fetch
81 * rightObjectId -- right oid of operator to fetch
84 OperatorGetWithOpenRelation(Relation pg_operator_desc,
85 const char *operatorName,
89 HeapScanDesc pg_operator_scan;
93 static ScanKeyData opKey[3] = {
94 {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
95 {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
96 {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
99 fmgr_info(NameEqualRegProcedure,
100 &opKey[0].sk_func, &opKey[0].sk_nargs);
101 fmgr_info(ObjectIdEqualRegProcedure,
102 &opKey[1].sk_func, &opKey[1].sk_nargs);
103 fmgr_info(ObjectIdEqualRegProcedure,
104 &opKey[2].sk_func, &opKey[2].sk_nargs);
110 opKey[0].sk_argument = PointerGetDatum(operatorName);
111 opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
112 opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
118 pg_operator_scan = heap_beginscan(pg_operator_desc,
125 * fetch the operator tuple, if it exists, and determine
126 * the proper return oid value.
129 tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
130 operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
133 * close the scan and return the oid.
136 heap_endscan(pg_operator_scan);
142 /* ----------------------------------------------------------------
145 * finds the operator associated with the specified name
146 * and left and right type names.
147 * ----------------------------------------------------------------
150 OperatorGet(char *operatorName,
154 Relation pg_operator_desc;
156 Oid operatorObjectId;
157 Oid leftObjectId = InvalidOid;
158 Oid rightObjectId = InvalidOid;
159 bool leftDefined = false;
160 bool rightDefined = false;
163 * look up the operator types.
165 * Note: types must be defined before operators
170 leftObjectId = TypeGet(leftTypeName, &leftDefined);
172 if (!OidIsValid(leftObjectId) || !leftDefined)
173 elog(WARN, "OperatorGet: left type '%s' nonexistent", leftTypeName);
178 rightObjectId = TypeGet(rightTypeName, &rightDefined);
180 if (!OidIsValid(rightObjectId) || !rightDefined)
181 elog(WARN, "OperatorGet: right type '%s' nonexistent",
185 if (!((OidIsValid(leftObjectId) && leftDefined) ||
186 (OidIsValid(rightObjectId) && rightDefined)))
187 elog(WARN, "OperatorGet: no argument types??");
190 * open the pg_operator relation
193 pg_operator_desc = heap_openr(OperatorRelationName);
196 * get the oid for the operator with the appropriate name
197 * and left/right types.
200 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
206 * close the relation and return the operator oid.
209 heap_close(pg_operator_desc);
215 /* ----------------------------------------------------------------
216 * OperatorShellMakeWithOpenRelation
218 * ----------------------------------------------------------------
221 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
228 Datum values[Natts_pg_operator];
229 char nulls[Natts_pg_operator];
230 Oid operatorObjectId;
234 * initialize our nulls[] and values[] arrays
237 for (i = 0; i < Natts_pg_operator; ++i)
240 values[i] = (Datum) NULL; /* redundant, but safe */
244 * initialize values[] with the type name and
248 values[i++] = PointerGetDatum(operatorName);
249 values[i++] = Int32GetDatum(GetUserId());
250 values[i++] = (Datum) (uint16) 0;
252 values[i++] = (Datum) 'b'; /* fill oprkind with a bogus value */
254 values[i++] = (Datum) (bool) 0;
255 values[i++] = (Datum) (bool) 0;
256 values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
257 values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
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);
265 values[i++] = ObjectIdGetDatum(InvalidOid);
268 * create a new operator tuple
271 tupDesc = pg_operator_desc->rd_att;
273 tup = heap_formtuple(tupDesc,
278 * insert our "shell" operator tuple and
282 heap_insert(pg_operator_desc, tup);
283 operatorObjectId = tup->t_oid;
286 * free the tuple and return the operator oid
295 /* ----------------------------------------------------------------
298 * Specify operator name and left and right type names,
299 * fill an operator struct with this info and NULL's,
300 * call heap_insert and return the Oid
302 * ----------------------------------------------------------------
305 OperatorShellMake(char *operatorName,
309 Relation pg_operator_desc;
310 Oid operatorObjectId;
312 Oid leftObjectId = InvalidOid;
313 Oid rightObjectId = InvalidOid;
314 bool leftDefined = false;
315 bool rightDefined = false;
318 * get the left and right type oid's for this operator
322 leftObjectId = TypeGet(leftTypeName, &leftDefined);
325 rightObjectId = TypeGet(rightTypeName, &rightDefined);
327 if (!((OidIsValid(leftObjectId) && leftDefined) ||
328 (OidIsValid(rightObjectId) && rightDefined)))
329 elog(WARN, "OperatorShellMake: no valid argument types??");
335 pg_operator_desc = heap_openr(OperatorRelationName);
338 * add a "shell" operator tuple to the operator relation
339 * and recover the shell tuple's oid.
343 OperatorShellMakeWithOpenRelation(pg_operator_desc,
348 * close the operator relation and return the oid.
351 heap_close(pg_operator_desc);
357 /* --------------------------------
360 * This routine gets complicated because it allows the user to
361 * specify operators that do not exist. For example, if operator
362 * "op" is being defined, the negator operator "negop" and the
363 * commutator "commop" can also be defined without specifying
364 * any information other than their names. Since in order to
365 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
366 * operators must be placed in the fields of "op", a forward
367 * declaration is done on the commutator and negator operators.
368 * This is called creating a shell, and its main effect is to
369 * create a tuple in the PG_OPERATOR catalog with minimal
370 * information about the operator (just its name and types).
371 * Forward declaration is used only for this purpose, it is
372 * not available to the user as it is for type definition.
376 * check if operator already defined
377 * if so issue error if not definedOk, this is a duplicate
378 * but if definedOk, save the Oid -- filling in a shell
379 * get the attribute types from relation descriptor for pg_operator
380 * assign values to the fields of the operator:
382 * owner id (simply the user id of the caller)
384 * operator "kind" either "b" for binary or "l" for left unary
385 * isLeftAssociative boolean
387 * leftTypeObjectId -- type must already be defined
388 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
389 * resultType -- defer this, since it must be determined from
390 * the pg_procedure catalog
391 * commutatorObjectId -- if this is NULL, enter ObjectId=0
392 * else if this already exists, enter it's ObjectId
393 * else if this does not yet exist, and is not
394 * the same as the main operatorName, then create
395 * a shell and enter the new ObjectId
396 * else if this does not exist but IS the same
397 * name as the main operator, set the ObjectId=0.
398 * Later OperatorCreate will make another call
399 * to OperatorDef which will cause this field
400 * to be filled in (because even though the names
401 * will be switched, they are the same name and
402 * at this point this ObjectId will then be defined)
403 * negatorObjectId -- same as for commutatorObjectId
404 * leftSortObjectId -- same as for commutatorObjectId
405 * rightSortObjectId -- same as for commutatorObjectId
406 * operatorProcedure -- must access the pg_procedure catalog to get the
407 * ObjectId of the procedure that actually does the operator
408 * actions this is required. Do an amgetattr to find out the
409 * return type of the procedure
410 * restrictionProcedure -- must access the pg_procedure catalog to get
411 * the ObjectId but this is optional
412 * joinProcedure -- same as restrictionProcedure
413 * now either insert or replace the operator into the pg_operator catalog
414 * if the operator shell is being filled in
415 * access the catalog in order to get a valid buffer
416 * create a tuple using ModifyHeapTuple
417 * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple
418 * else if a new operator is being created
419 * create a tuple using heap_formtuple
421 * --------------------------------
422 * "X" indicates an optional argument (i.e. one that can be NULL)
423 * operatorName; -- operator name
424 * definedOK; -- operator can already have an oid?
425 * leftTypeName; -- X left type name
426 * rightTypeName; -- X right type name
427 * procedureName; -- procedure oid for operator code
428 * precedence; -- operator precedence
429 * isLeftAssociative; -- operator is left associative?
430 * commutatorName; -- X commutator operator name
431 * negatorName; -- X negator operator name
432 * restrictionName; -- X restriction sel. procedure name
433 * joinName; -- X join sel. procedure name
434 * canHash; -- possible hash operator?
435 * leftSortName; -- X left sort operator
436 * rightSortName; -- X right sort operator
439 OperatorDef(char *operatorName,
445 bool isLeftAssociative,
446 char *commutatorName,
448 char *restrictionName,
456 Relation pg_operator_desc;
458 HeapScanDesc pg_operator_scan;
461 ItemPointerData itemPointerData;
462 char nulls[Natts_pg_operator];
463 char replaces[Natts_pg_operator];
464 Datum values[Natts_pg_operator];
466 Oid operatorObjectId;
467 Oid leftTypeId = InvalidOid;
468 Oid rightTypeId = InvalidOid;
469 Oid commutatorId = InvalidOid;
470 Oid negatorId = InvalidOid;
471 bool leftDefined = false;
472 bool rightDefined = false;
478 static ScanKeyData opKey[3] = {
479 {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
480 {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
481 {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
484 fmgr_info(NameEqualRegProcedure,
485 &opKey[0].sk_func, &opKey[0].sk_nargs);
486 fmgr_info(ObjectIdEqualRegProcedure,
487 &opKey[1].sk_func, &opKey[1].sk_nargs);
488 fmgr_info(ObjectIdEqualRegProcedure,
489 &opKey[2].sk_func, &opKey[2].sk_nargs);
491 operatorObjectId = OperatorGet(operatorName,
495 if (OidIsValid(operatorObjectId) && !definedOK)
496 elog(WARN, "OperatorDef: operator \"%s\" already defined",
500 leftTypeId = TypeGet(leftTypeName, &leftDefined);
503 rightTypeId = TypeGet(rightTypeName, &rightDefined);
505 if (!((OidIsValid(leftTypeId && leftDefined)) ||
506 (OidIsValid(rightTypeId && rightDefined))))
507 elog(WARN, "OperatorGet: no argument types??");
509 for (i = 0; i < Natts_pg_operator; ++i)
511 values[i] = (Datum) NULL;
517 * Look up registered procedures -- find the return type
518 * of procedureName to place in "result" field.
519 * Do this before shells are created so we don't
520 * have to worry about deleting them later.
523 MemSet(typeId, 0, 8 * sizeof(Oid));
526 typeId[0] = rightTypeId;
529 else if (!rightTypeName)
531 typeId[0] = leftTypeId;
536 typeId[0] = leftTypeId;
537 typeId[1] = rightTypeId;
540 tup = SearchSysCacheTuple(PRONAME,
541 PointerGetDatum(procedureName),
542 Int32GetDatum(nargs),
543 PointerGetDatum(typeId),
546 if (!PointerIsValid(tup))
547 func_error("OperatorDef", procedureName, nargs, typeId);
549 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_oid);
550 values[Anum_pg_operator_oprresult - 1] =
551 ObjectIdGetDatum(((Form_pg_proc)
552 GETSTRUCT(tup))->prorettype);
560 MemSet(typeId, 0, 8 * sizeof(Oid));
561 typeId[0] = OIDOID; /* operator OID */
562 typeId[1] = OIDOID; /* relation OID */
563 typeId[2] = INT2OID; /* attribute number */
564 typeId[3] = 0; /* value - can be any type */
565 typeId[4] = INT4OID; /* flags - left or right selectivity */
566 tup = SearchSysCacheTuple(PRONAME,
567 PointerGetDatum(restrictionName),
569 PointerGetDatum(typeId),
571 if (!HeapTupleIsValid(tup))
572 func_error("OperatorDef", restrictionName, 5, typeId);
574 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_oid);
577 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
580 * find join - only valid for binary operators
585 MemSet(typeId, 0, 8 * sizeof(Oid));
586 typeId[0] = OIDOID; /* operator OID */
587 typeId[1] = OIDOID; /* relation OID 1 */
588 typeId[2] = INT2OID; /* attribute number 1 */
589 typeId[3] = OIDOID; /* relation OID 2 */
590 typeId[4] = INT2OID; /* attribute number 2 */
592 tup = SearchSysCacheTuple(PRONAME,
593 PointerGetDatum(joinName),
595 PointerGetDatum(typeId),
597 if (!HeapTupleIsValid(tup))
598 func_error("OperatorDef", joinName, 5, typeId);
600 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_oid);
603 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
606 * set up values in the operator tuple
610 values[i++] = PointerGetDatum(operatorName);
611 values[i++] = Int32GetDatum(GetUserId());
612 values[i++] = UInt16GetDatum(precedence);
613 values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
614 values[i++] = Int8GetDatum(isLeftAssociative);
615 values[i++] = Int8GetDatum(canHash);
616 values[i++] = ObjectIdGetDatum(leftTypeId);
617 values[i++] = ObjectIdGetDatum(rightTypeId);
619 ++i; /* Skip "prorettype", this was done above */
622 * Set up the other operators. If they do not currently exist, set up
623 * shells in order to get ObjectId's and call OperatorDef again later
624 * to fill in the shells.
626 name[0] = commutatorName;
627 name[1] = negatorName;
628 name[2] = leftSortName;
629 name[3] = rightSortName;
631 for (j = 0; j < 4; ++j)
636 /* for the commutator, switch order of arguments */
639 other_oid = OperatorGet(name[j], rightTypeName, leftTypeName);
640 commutatorId = other_oid;
644 other_oid = OperatorGet(name[j], leftTypeName, rightTypeName);
646 negatorId = other_oid;
649 if (OidIsValid(other_oid)) /* already in catalogs */
650 values[i++] = ObjectIdGetDatum(other_oid);
651 else if (strcmp(operatorName, name[j]) != 0)
653 /* not in catalogs, different from operator */
655 /* for the commutator, switch order of arguments */
658 other_oid = OperatorShellMake(name[j],
664 other_oid = OperatorShellMake(name[j],
669 if (!OidIsValid(other_oid))
671 "OperatorDef: can't create operator '%s'",
673 values[i++] = ObjectIdGetDatum(other_oid);
677 /* not in catalogs, same as operator ??? */
678 values[i++] = ObjectIdGetDatum(InvalidOid);
682 /* new operator is optional */
683 values[i++] = ObjectIdGetDatum(InvalidOid);
686 /* last three fields were filled in first */
689 * If we are adding to an operator shell, get its t_ctid and a buffer.
691 pg_operator_desc = heap_openr(OperatorRelationName);
693 if (operatorObjectId)
695 opKey[0].sk_argument = PointerGetDatum(operatorName);
696 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
697 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
699 pg_operator_scan = heap_beginscan(pg_operator_desc,
705 tup = heap_getnext(pg_operator_scan, 0, &buffer);
706 if (HeapTupleIsValid(tup))
708 tup = heap_modifytuple(tup,
715 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
716 setheapoverride(true);
717 heap_replace(pg_operator_desc, &itemPointerData, tup);
718 setheapoverride(false);
721 elog(WARN, "OperatorDef: no operator %d", other_oid);
723 heap_endscan(pg_operator_scan);
728 tupDesc = pg_operator_desc->rd_att;
729 tup = heap_formtuple(tupDesc, values, nulls);
731 heap_insert(pg_operator_desc, tup);
732 operatorObjectId = tup->t_oid;
735 heap_close(pg_operator_desc);
738 * It's possible that we're creating a skeleton operator here for the
739 * commute or negate attributes of a real operator. If we are, then
740 * we're done. If not, we may need to update the negator and
741 * commutator for this attribute. The reason for this is that the
742 * user may want to create two operators (say < and >=). When he
743 * defines <, if he uses >= as the negator or commutator, he won't be
744 * able to insert it later, since (for some reason) define operator
745 * defines it for him. So what he does is to define > without a
746 * negator or commutator. Then he defines >= with < as the negator
747 * and commutator. As a side effect, this will update the > tuple if
748 * it has no commutator or negator defined.
750 * Alstublieft, Tom Vijlbrief.
753 OperatorUpd(operatorObjectId, commutatorId, negatorId);
756 /* ----------------------------------------------------------------
759 * For a given operator, look up its negator and commutator operators.
760 * If they are defined, but their negator and commutator operators
761 * (respectively) are not, then use the new operator for neg and comm.
762 * This solves a problem for users who need to insert two new operators
763 * which are the negator or commutator of each other.
764 * ----------------------------------------------------------------
767 OperatorUpd(Oid baseId, Oid commId, Oid negId)
770 Relation pg_operator_desc;
771 HeapScanDesc pg_operator_scan;
774 ItemPointerData itemPointerData;
775 char nulls[Natts_pg_operator];
776 char replaces[Natts_pg_operator];
777 Datum values[Natts_pg_operator];
779 static ScanKeyData opKey[1] = {
780 {0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure},
783 fmgr_info(ObjectIdEqualRegProcedure,
784 &opKey[0].sk_func, &opKey[0].sk_nargs);
786 for (i = 0; i < Natts_pg_operator; ++i)
788 values[i] = (Datum) NULL;
793 pg_operator_desc = heap_openr(OperatorRelationName);
795 /* check and update the commutator, if necessary */
796 opKey[0].sk_argument = ObjectIdGetDatum(commId);
798 pg_operator_scan = heap_beginscan(pg_operator_desc,
804 tup = heap_getnext(pg_operator_scan, 0, &buffer);
806 /* if the commutator and negator are the same operator, do one update */
809 if (HeapTupleIsValid(tup))
813 t = (OperatorTupleForm) GETSTRUCT(tup);
814 if (!OidIsValid(t->oprcom)
815 || !OidIsValid(t->oprnegate))
818 if (!OidIsValid(t->oprnegate))
820 values[Anum_pg_operator_oprnegate - 1] =
821 ObjectIdGetDatum(baseId);
822 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
825 if (!OidIsValid(t->oprcom))
827 values[Anum_pg_operator_oprcom - 1] =
828 ObjectIdGetDatum(baseId);
829 replaces[Anum_pg_operator_oprcom - 1] = 'r';
832 tup = heap_modifytuple(tup,
839 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
841 setheapoverride(true);
842 heap_replace(pg_operator_desc, &itemPointerData, tup);
843 setheapoverride(false);
847 heap_endscan(pg_operator_scan);
849 heap_close(pg_operator_desc);
851 /* release the buffer properly */
852 if (BufferIsValid(buffer))
853 ReleaseBuffer(buffer);
858 /* if commutator and negator are different, do two updates */
859 if (HeapTupleIsValid(tup) &&
860 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom)))
862 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
863 replaces[Anum_pg_operator_oprcom - 1] = 'r';
864 tup = heap_modifytuple(tup,
871 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
872 setheapoverride(true);
873 heap_replace(pg_operator_desc, &itemPointerData, tup);
874 setheapoverride(false);
876 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
877 replaces[Anum_pg_operator_oprcom - 1] = ' ';
879 /* release the buffer properly */
880 if (BufferIsValid(buffer))
881 ReleaseBuffer(buffer);
885 /* check and update the negator, if necessary */
886 opKey[0].sk_argument = ObjectIdGetDatum(negId);
888 pg_operator_scan = heap_beginscan(pg_operator_desc,
894 tup = heap_getnext(pg_operator_scan, 0, &buffer);
895 if (HeapTupleIsValid(tup) &&
896 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate)))
898 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
899 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
900 tup = heap_modifytuple(tup,
907 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
909 setheapoverride(true);
910 heap_replace(pg_operator_desc, &itemPointerData, tup);
911 setheapoverride(false);
914 /* release the buffer properly */
915 if (BufferIsValid(buffer))
916 ReleaseBuffer(buffer);
918 heap_endscan(pg_operator_scan);
920 heap_close(pg_operator_desc);
924 /* ----------------------------------------------------------------
929 * Since the commutator, negator, leftsortoperator, and rightsortoperator
930 * can be defined implicitly through OperatorCreate, must check before
931 * the main operator is added to see if they already exist. If they
932 * do not already exist, OperatorDef makes a "shell" for each undefined
933 * one, and then OperatorCreate must call OperatorDef again to fill in
934 * each shell. All this is necessary in order to get the right ObjectId's
935 * filled into the right fields.
937 * The "definedOk" flag indicates that OperatorDef can be called on
938 * the operator even though it already has an entry in the PG_OPERATOR
939 * relation. This allows shells to be filled in. The user cannot
940 * forward declare operators, this is strictly an internal capability.
942 * When the shells are filled in by subsequent calls to OperatorDef,
943 * all the fields are the same as the definition of the original operator
944 * except that the target operator name and the original operatorName
945 * are switched. In the case of commutator and negator, special flags
946 * are set to indicate their status, telling the executor(?) that
947 * the operands are to be switched, or the outcome of the procedure
950 * ************************* NOTE NOTE NOTE ******************************
952 * If the execution of this utility is interrupted, the pg_operator
953 * catalog may be left in an inconsistent state. Similarly, if
954 * something is removed from the pg_operator, pg_type, or pg_procedure
955 * catalog while this is executing, the results may be inconsistent.
956 * ----------------------------------------------------------------
958 * "X" indicates an optional argument (i.e. one that can be NULL)
959 * operatorName; -- operator name
960 * leftTypeName; -- X left type name
961 * rightTypeName; -- X right type name
962 * procedureName; -- procedure for operator
963 * precedence; -- operator precedence
964 * isLeftAssociative; -- operator is left associative
965 * commutatorName; -- X commutator operator name
966 * negatorName; -- X negator operator name
967 * restrictionName; -- X restriction sel. procedure
968 * joinName; -- X join sel. procedure name
969 * canHash; -- operator hashes
970 * leftSortName; -- X left sort operator
971 * rightSortName; -- X right sort operator
975 OperatorCreate(char *operatorName,
980 bool isLeftAssociative,
981 char *commutatorName,
983 char *restrictionName,
991 Oid leftSortObjectId,
995 if (!leftTypeName && !rightTypeName)
996 elog(WARN, "OperatorCreate : at least one of leftarg or rightarg must be defined");
999 * get the oid's of the operator's associated operators, if possible.
1003 commObjectId = OperatorGet(commutatorName, /* commute type order */
1010 negObjectId = OperatorGet(negatorName,
1017 leftSortObjectId = OperatorGet(leftSortName,
1021 leftSortObjectId = 0;
1024 rightSortObjectId = OperatorGet(rightSortName,
1028 rightSortObjectId = 0;
1031 * Use OperatorDef() to define the specified operator and
1032 * also create shells for the operator's associated operators
1033 * if they don't already exist.
1035 * This operator should not be defined yet.
1040 OperatorDef(operatorName,
1056 * Now fill in information in the operator's associated
1059 * These operators should be defined or have shells defined.
1064 if (!OidIsValid(commObjectId) && commutatorName)
1065 OperatorDef(commutatorName,
1067 leftTypeName, /* should eventually */
1068 rightTypeName, /* commute order */
1072 operatorName, /* commutator */
1080 if (negatorName && !OidIsValid(negObjectId))
1081 OperatorDef(negatorName,
1089 operatorName, /* negator */
1096 if (leftSortName && !OidIsValid(leftSortObjectId))
1097 OperatorDef(leftSortName,
1109 operatorName, /* left sort */
1112 if (rightSortName && !OidIsValid(rightSortObjectId))
1113 OperatorDef(rightSortName,
1126 operatorName); /* right sort */