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.19 1998/01/06 19:42:31 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 <catalog/catname.h>
24 #include <catalog/pg_operator.h>
25 #include <catalog/pg_type.h>
26 #include <parser/parse_oper.h>
27 #include <storage/bufmgr.h>
29 #include <miscadmin.h>
31 #include <regex/utils.h>
37 OperatorGetWithOpenRelation(Relation pg_operator_desc,
38 const char *operatorName,
42 OperatorGet(char *operatorName,
47 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
52 OperatorShellMake(char *operatorName,
57 OperatorDef(char *operatorName,
63 bool isLeftAssociative,
66 char *restrictionName,
71 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
73 /* ----------------------------------------------------------------
74 * OperatorGetWithOpenRelation
76 * preforms a scan on pg_operator for an operator tuple
77 * with given name and left/right type oids.
78 * ----------------------------------------------------------------
79 * pg_operator_desc -- reldesc for pg_operator
80 * operatorName -- name of operator to fetch
81 * leftObjectId -- left oid of operator to fetch
82 * rightObjectId -- right oid of operator to fetch
85 OperatorGetWithOpenRelation(Relation pg_operator_desc,
86 const char *operatorName,
90 HeapScanDesc pg_operator_scan;
94 static ScanKeyData opKey[3] = {
95 {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
96 {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
97 {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
100 fmgr_info(NameEqualRegProcedure,
101 &opKey[0].sk_func, &opKey[0].sk_nargs);
102 fmgr_info(ObjectIdEqualRegProcedure,
103 &opKey[1].sk_func, &opKey[1].sk_nargs);
104 fmgr_info(ObjectIdEqualRegProcedure,
105 &opKey[2].sk_func, &opKey[2].sk_nargs);
111 opKey[0].sk_argument = PointerGetDatum(operatorName);
112 opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
113 opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
119 pg_operator_scan = heap_beginscan(pg_operator_desc,
126 * fetch the operator tuple, if it exists, and determine
127 * the proper return oid value.
130 tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
131 operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
134 * close the scan and return the oid.
137 heap_endscan(pg_operator_scan);
143 /* ----------------------------------------------------------------
146 * finds the operator associated with the specified name
147 * and left and right type names.
148 * ----------------------------------------------------------------
151 OperatorGet(char *operatorName,
155 Relation pg_operator_desc;
157 Oid operatorObjectId;
158 Oid leftObjectId = InvalidOid;
159 Oid rightObjectId = InvalidOid;
160 bool leftDefined = false;
161 bool rightDefined = false;
164 * look up the operator types.
166 * Note: types must be defined before operators
171 leftObjectId = TypeGet(leftTypeName, &leftDefined);
173 if (!OidIsValid(leftObjectId) || !leftDefined)
174 elog(ERROR, "OperatorGet: left type '%s' nonexistent", leftTypeName);
179 rightObjectId = TypeGet(rightTypeName, &rightDefined);
181 if (!OidIsValid(rightObjectId) || !rightDefined)
182 elog(ERROR, "OperatorGet: right type '%s' nonexistent",
186 if (!((OidIsValid(leftObjectId) && leftDefined) ||
187 (OidIsValid(rightObjectId) && rightDefined)))
188 elog(ERROR, "OperatorGet: no argument types??");
191 * open the pg_operator relation
194 pg_operator_desc = heap_openr(OperatorRelationName);
197 * get the oid for the operator with the appropriate name
198 * and left/right types.
201 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
207 * close the relation and return the operator oid.
210 heap_close(pg_operator_desc);
216 /* ----------------------------------------------------------------
217 * OperatorShellMakeWithOpenRelation
219 * ----------------------------------------------------------------
222 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
229 Datum values[Natts_pg_operator];
230 char nulls[Natts_pg_operator];
231 Oid operatorObjectId;
235 * initialize our nulls[] and values[] arrays
238 for (i = 0; i < Natts_pg_operator; ++i)
241 values[i] = (Datum) NULL; /* redundant, but safe */
245 * initialize values[] with the type name and
249 values[i++] = PointerGetDatum(operatorName);
250 values[i++] = Int32GetDatum(GetUserId());
251 values[i++] = (Datum) (uint16) 0;
253 values[i++] = (Datum) 'b'; /* fill oprkind with a bogus value */
255 values[i++] = (Datum) (bool) 0;
256 values[i++] = (Datum) (bool) 0;
257 values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
258 values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
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);
266 values[i++] = ObjectIdGetDatum(InvalidOid);
269 * create a new operator tuple
272 tupDesc = pg_operator_desc->rd_att;
274 tup = heap_formtuple(tupDesc,
279 * insert our "shell" operator tuple and
283 heap_insert(pg_operator_desc, tup);
284 operatorObjectId = tup->t_oid;
287 * free the tuple and return the operator oid
296 /* ----------------------------------------------------------------
299 * Specify operator name and left and right type names,
300 * fill an operator struct with this info and NULL's,
301 * call heap_insert and return the Oid
303 * ----------------------------------------------------------------
306 OperatorShellMake(char *operatorName,
310 Relation pg_operator_desc;
311 Oid operatorObjectId;
313 Oid leftObjectId = InvalidOid;
314 Oid rightObjectId = InvalidOid;
315 bool leftDefined = false;
316 bool rightDefined = false;
319 * get the left and right type oid's for this operator
323 leftObjectId = TypeGet(leftTypeName, &leftDefined);
326 rightObjectId = TypeGet(rightTypeName, &rightDefined);
328 if (!((OidIsValid(leftObjectId) && leftDefined) ||
329 (OidIsValid(rightObjectId) && rightDefined)))
330 elog(ERROR, "OperatorShellMake: no valid argument types??");
336 pg_operator_desc = heap_openr(OperatorRelationName);
339 * add a "shell" operator tuple to the operator relation
340 * and recover the shell tuple's oid.
344 OperatorShellMakeWithOpenRelation(pg_operator_desc,
349 * close the operator relation and return the oid.
352 heap_close(pg_operator_desc);
358 /* --------------------------------
361 * This routine gets complicated because it allows the user to
362 * specify operators that do not exist. For example, if operator
363 * "op" is being defined, the negator operator "negop" and the
364 * commutator "commop" can also be defined without specifying
365 * any information other than their names. Since in order to
366 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
367 * operators must be placed in the fields of "op", a forward
368 * declaration is done on the commutator and negator operators.
369 * This is called creating a shell, and its main effect is to
370 * create a tuple in the PG_OPERATOR catalog with minimal
371 * information about the operator (just its name and types).
372 * Forward declaration is used only for this purpose, it is
373 * not available to the user as it is for type definition.
377 * check if operator already defined
378 * if so issue error if not definedOk, this is a duplicate
379 * but if definedOk, save the Oid -- filling in a shell
380 * get the attribute types from relation descriptor for pg_operator
381 * assign values to the fields of the operator:
383 * owner id (simply the user id of the caller)
385 * operator "kind" either "b" for binary or "l" for left unary
386 * isLeftAssociative boolean
388 * leftTypeObjectId -- type must already be defined
389 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
390 * resultType -- defer this, since it must be determined from
391 * the pg_procedure catalog
392 * commutatorObjectId -- if this is NULL, enter ObjectId=0
393 * else if this already exists, enter it's ObjectId
394 * else if this does not yet exist, and is not
395 * the same as the main operatorName, then create
396 * a shell and enter the new ObjectId
397 * else if this does not exist but IS the same
398 * name as the main operator, set the ObjectId=0.
399 * Later OperatorCreate will make another call
400 * to OperatorDef which will cause this field
401 * to be filled in (because even though the names
402 * will be switched, they are the same name and
403 * at this point this ObjectId will then be defined)
404 * negatorObjectId -- same as for commutatorObjectId
405 * leftSortObjectId -- same as for commutatorObjectId
406 * rightSortObjectId -- same as for commutatorObjectId
407 * operatorProcedure -- must access the pg_procedure catalog to get the
408 * ObjectId of the procedure that actually does the operator
409 * actions this is required. Do an amgetattr to find out the
410 * return type of the procedure
411 * restrictionProcedure -- must access the pg_procedure catalog to get
412 * the ObjectId but this is optional
413 * joinProcedure -- same as restrictionProcedure
414 * now either insert or replace the operator into the pg_operator catalog
415 * if the operator shell is being filled in
416 * access the catalog in order to get a valid buffer
417 * create a tuple using ModifyHeapTuple
418 * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple
419 * else if a new operator is being created
420 * create a tuple using heap_formtuple
422 * --------------------------------
423 * "X" indicates an optional argument (i.e. one that can be NULL)
424 * operatorName; -- operator name
425 * definedOK; -- operator can already have an oid?
426 * leftTypeName; -- X left type name
427 * rightTypeName; -- X right type name
428 * procedureName; -- procedure oid for operator code
429 * precedence; -- operator precedence
430 * isLeftAssociative; -- operator is left associative?
431 * commutatorName; -- X commutator operator name
432 * negatorName; -- X negator operator name
433 * restrictionName; -- X restriction sel. procedure name
434 * joinName; -- X join sel. procedure name
435 * canHash; -- possible hash operator?
436 * leftSortName; -- X left sort operator
437 * rightSortName; -- X right sort operator
440 OperatorDef(char *operatorName,
446 bool isLeftAssociative,
447 char *commutatorName,
449 char *restrictionName,
457 Relation pg_operator_desc;
459 HeapScanDesc pg_operator_scan;
462 ItemPointerData itemPointerData;
463 char nulls[Natts_pg_operator];
464 char replaces[Natts_pg_operator];
465 Datum values[Natts_pg_operator];
467 Oid operatorObjectId;
468 Oid leftTypeId = InvalidOid;
469 Oid rightTypeId = InvalidOid;
470 Oid commutatorId = InvalidOid;
471 Oid negatorId = InvalidOid;
472 bool leftDefined = false;
473 bool rightDefined = false;
479 static ScanKeyData opKey[3] = {
480 {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
481 {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
482 {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
485 fmgr_info(NameEqualRegProcedure,
486 &opKey[0].sk_func, &opKey[0].sk_nargs);
487 fmgr_info(ObjectIdEqualRegProcedure,
488 &opKey[1].sk_func, &opKey[1].sk_nargs);
489 fmgr_info(ObjectIdEqualRegProcedure,
490 &opKey[2].sk_func, &opKey[2].sk_nargs);
492 operatorObjectId = OperatorGet(operatorName,
496 if (OidIsValid(operatorObjectId) && !definedOK)
497 elog(ERROR, "OperatorDef: operator \"%s\" already defined",
501 leftTypeId = TypeGet(leftTypeName, &leftDefined);
504 rightTypeId = TypeGet(rightTypeName, &rightDefined);
506 if (!((OidIsValid(leftTypeId && leftDefined)) ||
507 (OidIsValid(rightTypeId && rightDefined))))
508 elog(ERROR, "OperatorGet: no argument types??");
510 for (i = 0; i < Natts_pg_operator; ++i)
512 values[i] = (Datum) NULL;
518 * Look up registered procedures -- find the return type
519 * of procedureName to place in "result" field.
520 * Do this before shells are created so we don't
521 * have to worry about deleting them later.
524 MemSet(typeId, 0, 8 * sizeof(Oid));
527 typeId[0] = rightTypeId;
530 else if (!rightTypeName)
532 typeId[0] = leftTypeId;
537 typeId[0] = leftTypeId;
538 typeId[1] = rightTypeId;
541 tup = SearchSysCacheTuple(PRONAME,
542 PointerGetDatum(procedureName),
543 Int32GetDatum(nargs),
544 PointerGetDatum(typeId),
547 if (!PointerIsValid(tup))
548 func_error("OperatorDef", procedureName, nargs, typeId);
550 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_oid);
551 values[Anum_pg_operator_oprresult - 1] =
552 ObjectIdGetDatum(((Form_pg_proc)
553 GETSTRUCT(tup))->prorettype);
561 MemSet(typeId, 0, 8 * sizeof(Oid));
562 typeId[0] = OIDOID; /* operator OID */
563 typeId[1] = OIDOID; /* relation OID */
564 typeId[2] = INT2OID; /* attribute number */
565 typeId[3] = 0; /* value - can be any type */
566 typeId[4] = INT4OID; /* flags - left or right selectivity */
567 tup = SearchSysCacheTuple(PRONAME,
568 PointerGetDatum(restrictionName),
570 PointerGetDatum(typeId),
572 if (!HeapTupleIsValid(tup))
573 func_error("OperatorDef", restrictionName, 5, typeId);
575 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_oid);
578 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
581 * find join - only valid for binary operators
586 MemSet(typeId, 0, 8 * sizeof(Oid));
587 typeId[0] = OIDOID; /* operator OID */
588 typeId[1] = OIDOID; /* relation OID 1 */
589 typeId[2] = INT2OID; /* attribute number 1 */
590 typeId[3] = OIDOID; /* relation OID 2 */
591 typeId[4] = INT2OID; /* attribute number 2 */
593 tup = SearchSysCacheTuple(PRONAME,
594 PointerGetDatum(joinName),
596 PointerGetDatum(typeId),
598 if (!HeapTupleIsValid(tup))
599 func_error("OperatorDef", joinName, 5, typeId);
601 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_oid);
604 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
607 * set up values in the operator tuple
611 values[i++] = PointerGetDatum(operatorName);
612 values[i++] = Int32GetDatum(GetUserId());
613 values[i++] = UInt16GetDatum(precedence);
614 values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
615 values[i++] = Int8GetDatum(isLeftAssociative);
616 values[i++] = Int8GetDatum(canHash);
617 values[i++] = ObjectIdGetDatum(leftTypeId);
618 values[i++] = ObjectIdGetDatum(rightTypeId);
620 ++i; /* Skip "prorettype", this was done above */
623 * Set up the other operators. If they do not currently exist, set up
624 * shells in order to get ObjectId's and call OperatorDef again later
625 * to fill in the shells.
627 name[0] = commutatorName;
628 name[1] = negatorName;
629 name[2] = leftSortName;
630 name[3] = rightSortName;
632 for (j = 0; j < 4; ++j)
637 /* for the commutator, switch order of arguments */
640 other_oid = OperatorGet(name[j], rightTypeName, leftTypeName);
641 commutatorId = other_oid;
645 other_oid = OperatorGet(name[j], leftTypeName, rightTypeName);
647 negatorId = other_oid;
650 if (OidIsValid(other_oid)) /* already in catalogs */
651 values[i++] = ObjectIdGetDatum(other_oid);
652 else if (strcmp(operatorName, name[j]) != 0)
654 /* not in catalogs, different from operator */
656 /* for the commutator, switch order of arguments */
659 other_oid = OperatorShellMake(name[j],
665 other_oid = OperatorShellMake(name[j],
670 if (!OidIsValid(other_oid))
672 "OperatorDef: can't create operator '%s'",
674 values[i++] = ObjectIdGetDatum(other_oid);
678 /* not in catalogs, same as operator ??? */
679 values[i++] = ObjectIdGetDatum(InvalidOid);
683 /* new operator is optional */
684 values[i++] = ObjectIdGetDatum(InvalidOid);
687 /* last three fields were filled in first */
690 * If we are adding to an operator shell, get its t_ctid and a buffer.
692 pg_operator_desc = heap_openr(OperatorRelationName);
694 if (operatorObjectId)
696 opKey[0].sk_argument = PointerGetDatum(operatorName);
697 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
698 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
700 pg_operator_scan = heap_beginscan(pg_operator_desc,
706 tup = heap_getnext(pg_operator_scan, 0, &buffer);
707 if (HeapTupleIsValid(tup))
709 tup = heap_modifytuple(tup,
716 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
717 setheapoverride(true);
718 heap_replace(pg_operator_desc, &itemPointerData, tup);
719 setheapoverride(false);
722 elog(ERROR, "OperatorDef: no operator %d", other_oid);
724 heap_endscan(pg_operator_scan);
729 tupDesc = pg_operator_desc->rd_att;
730 tup = heap_formtuple(tupDesc, values, nulls);
732 heap_insert(pg_operator_desc, tup);
733 operatorObjectId = tup->t_oid;
736 heap_close(pg_operator_desc);
739 * It's possible that we're creating a skeleton operator here for the
740 * commute or negate attributes of a real operator. If we are, then
741 * we're done. If not, we may need to update the negator and
742 * commutator for this attribute. The reason for this is that the
743 * user may want to create two operators (say < and >=). When he
744 * defines <, if he uses >= as the negator or commutator, he won't be
745 * able to insert it later, since (for some reason) define operator
746 * defines it for him. So what he does is to define > without a
747 * negator or commutator. Then he defines >= with < as the negator
748 * and commutator. As a side effect, this will update the > tuple if
749 * it has no commutator or negator defined.
751 * Alstublieft, Tom Vijlbrief.
754 OperatorUpd(operatorObjectId, commutatorId, negatorId);
757 /* ----------------------------------------------------------------
760 * For a given operator, look up its negator and commutator operators.
761 * If they are defined, but their negator and commutator operators
762 * (respectively) are not, then use the new operator for neg and comm.
763 * This solves a problem for users who need to insert two new operators
764 * which are the negator or commutator of each other.
765 * ----------------------------------------------------------------
768 OperatorUpd(Oid baseId, Oid commId, Oid negId)
771 Relation pg_operator_desc;
772 HeapScanDesc pg_operator_scan;
775 ItemPointerData itemPointerData;
776 char nulls[Natts_pg_operator];
777 char replaces[Natts_pg_operator];
778 Datum values[Natts_pg_operator];
780 static ScanKeyData opKey[1] = {
781 {0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure},
784 fmgr_info(ObjectIdEqualRegProcedure,
785 &opKey[0].sk_func, &opKey[0].sk_nargs);
787 for (i = 0; i < Natts_pg_operator; ++i)
789 values[i] = (Datum) NULL;
794 pg_operator_desc = heap_openr(OperatorRelationName);
796 /* check and update the commutator, if necessary */
797 opKey[0].sk_argument = ObjectIdGetDatum(commId);
799 pg_operator_scan = heap_beginscan(pg_operator_desc,
805 tup = heap_getnext(pg_operator_scan, 0, &buffer);
807 /* if the commutator and negator are the same operator, do one update */
810 if (HeapTupleIsValid(tup))
814 t = (OperatorTupleForm) GETSTRUCT(tup);
815 if (!OidIsValid(t->oprcom)
816 || !OidIsValid(t->oprnegate))
819 if (!OidIsValid(t->oprnegate))
821 values[Anum_pg_operator_oprnegate - 1] =
822 ObjectIdGetDatum(baseId);
823 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
826 if (!OidIsValid(t->oprcom))
828 values[Anum_pg_operator_oprcom - 1] =
829 ObjectIdGetDatum(baseId);
830 replaces[Anum_pg_operator_oprcom - 1] = 'r';
833 tup = heap_modifytuple(tup,
840 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
842 setheapoverride(true);
843 heap_replace(pg_operator_desc, &itemPointerData, tup);
844 setheapoverride(false);
848 heap_endscan(pg_operator_scan);
850 heap_close(pg_operator_desc);
852 /* release the buffer properly */
853 if (BufferIsValid(buffer))
854 ReleaseBuffer(buffer);
859 /* if commutator and negator are different, do two updates */
860 if (HeapTupleIsValid(tup) &&
861 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom)))
863 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
864 replaces[Anum_pg_operator_oprcom - 1] = 'r';
865 tup = heap_modifytuple(tup,
872 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
873 setheapoverride(true);
874 heap_replace(pg_operator_desc, &itemPointerData, tup);
875 setheapoverride(false);
877 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
878 replaces[Anum_pg_operator_oprcom - 1] = ' ';
880 /* release the buffer properly */
881 if (BufferIsValid(buffer))
882 ReleaseBuffer(buffer);
886 /* check and update the negator, if necessary */
887 opKey[0].sk_argument = ObjectIdGetDatum(negId);
889 pg_operator_scan = heap_beginscan(pg_operator_desc,
895 tup = heap_getnext(pg_operator_scan, 0, &buffer);
896 if (HeapTupleIsValid(tup) &&
897 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate)))
899 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
900 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
901 tup = heap_modifytuple(tup,
908 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
910 setheapoverride(true);
911 heap_replace(pg_operator_desc, &itemPointerData, tup);
912 setheapoverride(false);
915 /* release the buffer properly */
916 if (BufferIsValid(buffer))
917 ReleaseBuffer(buffer);
919 heap_endscan(pg_operator_scan);
921 heap_close(pg_operator_desc);
925 /* ----------------------------------------------------------------
930 * Since the commutator, negator, leftsortoperator, and rightsortoperator
931 * can be defined implicitly through OperatorCreate, must check before
932 * the main operator is added to see if they already exist. If they
933 * do not already exist, OperatorDef makes a "shell" for each undefined
934 * one, and then OperatorCreate must call OperatorDef again to fill in
935 * each shell. All this is necessary in order to get the right ObjectId's
936 * filled into the right fields.
938 * The "definedOk" flag indicates that OperatorDef can be called on
939 * the operator even though it already has an entry in the PG_OPERATOR
940 * relation. This allows shells to be filled in. The user cannot
941 * forward declare operators, this is strictly an internal capability.
943 * When the shells are filled in by subsequent calls to OperatorDef,
944 * all the fields are the same as the definition of the original operator
945 * except that the target operator name and the original operatorName
946 * are switched. In the case of commutator and negator, special flags
947 * are set to indicate their status, telling the executor(?) that
948 * the operands are to be switched, or the outcome of the procedure
951 * ************************* NOTE NOTE NOTE ******************************
953 * If the execution of this utility is interrupted, the pg_operator
954 * catalog may be left in an inconsistent state. Similarly, if
955 * something is removed from the pg_operator, pg_type, or pg_procedure
956 * catalog while this is executing, the results may be inconsistent.
957 * ----------------------------------------------------------------
959 * "X" indicates an optional argument (i.e. one that can be NULL)
960 * operatorName; -- operator name
961 * leftTypeName; -- X left type name
962 * rightTypeName; -- X right type name
963 * procedureName; -- procedure for operator
964 * precedence; -- operator precedence
965 * isLeftAssociative; -- operator is left associative
966 * commutatorName; -- X commutator operator name
967 * negatorName; -- X negator operator name
968 * restrictionName; -- X restriction sel. procedure
969 * joinName; -- X join sel. procedure name
970 * canHash; -- operator hashes
971 * leftSortName; -- X left sort operator
972 * rightSortName; -- X right sort operator
976 OperatorCreate(char *operatorName,
981 bool isLeftAssociative,
982 char *commutatorName,
984 char *restrictionName,
992 Oid leftSortObjectId,
996 if (!leftTypeName && !rightTypeName)
997 elog(ERROR, "OperatorCreate : at least one of leftarg or rightarg must be defined");
1000 * get the oid's of the operator's associated operators, if possible.
1004 commObjectId = OperatorGet(commutatorName, /* commute type order */
1011 negObjectId = OperatorGet(negatorName,
1018 leftSortObjectId = OperatorGet(leftSortName,
1022 leftSortObjectId = 0;
1025 rightSortObjectId = OperatorGet(rightSortName,
1029 rightSortObjectId = 0;
1032 * Use OperatorDef() to define the specified operator and
1033 * also create shells for the operator's associated operators
1034 * if they don't already exist.
1036 * This operator should not be defined yet.
1041 OperatorDef(operatorName,
1057 * Now fill in information in the operator's associated
1060 * These operators should be defined or have shells defined.
1065 if (!OidIsValid(commObjectId) && commutatorName)
1066 OperatorDef(commutatorName,
1068 leftTypeName, /* should eventually */
1069 rightTypeName, /* commute order */
1073 operatorName, /* commutator */
1081 if (negatorName && !OidIsValid(negObjectId))
1082 OperatorDef(negatorName,
1090 operatorName, /* negator */
1097 if (leftSortName && !OidIsValid(leftSortObjectId))
1098 OperatorDef(leftSortName,
1110 operatorName, /* left sort */
1113 if (rightSortName && !OidIsValid(rightSortObjectId))
1114 OperatorDef(rightSortName,
1127 operatorName); /* right sort */