1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_operator relation
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.53 2000/11/16 22:30:17 tgl Exp $
14 * these routines moved here from commands/define.c and somewhat cleaned up.
16 *-------------------------------------------------------------------------
20 #include "access/heapam.h"
21 #include "catalog/catname.h"
22 #include "catalog/indexing.h"
23 #include "catalog/pg_operator.h"
24 #include "catalog/pg_proc.h"
25 #include "catalog/pg_type.h"
26 #include "miscadmin.h"
27 #include "parser/parse_func.h"
28 #include "utils/builtins.h"
29 #include "utils/fmgroids.h"
30 #include "utils/syscache.h"
33 static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
34 const char *operatorName,
39 static Oid OperatorGet(char *operatorName,
44 static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
49 static Oid OperatorShellMake(char *operatorName,
53 static void OperatorDef(char *operatorName,
58 bool isLeftAssociative,
61 char *restrictionName,
67 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
69 /* ----------------------------------------------------------------
70 * OperatorGetWithOpenRelation
72 * preforms a scan on pg_operator for an operator tuple
73 * with given name and left/right type oids.
74 * ----------------------------------------------------------------
75 * pg_operator_desc -- reldesc for pg_operator
76 * operatorName -- name of operator to fetch
77 * leftObjectId -- left data type oid of operator to fetch
78 * rightObjectId -- right data type oid of operator to fetch
79 * defined -- set TRUE if defined (not a shell)
82 OperatorGetWithOpenRelation(Relation pg_operator_desc,
83 const char *operatorName,
88 HeapScanDesc pg_operator_scan;
92 static ScanKeyData opKey[3] = {
93 {0, Anum_pg_operator_oprname, F_NAMEEQ},
94 {0, Anum_pg_operator_oprleft, F_OIDEQ},
95 {0, Anum_pg_operator_oprright, F_OIDEQ},
98 fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
99 fmgr_info(F_OIDEQ, &opKey[1].sk_func);
100 fmgr_info(F_OIDEQ, &opKey[2].sk_func);
101 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
102 opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
103 opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
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,
119 SnapshotSelf, /* no cache? */
124 * fetch the operator tuple, if it exists, and determine
125 * the proper return oid value.
128 tup = heap_getnext(pg_operator_scan, 0);
130 if (HeapTupleIsValid(tup))
132 regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
134 operatorObjectId = tup->t_data->t_oid;
135 *defined = RegProcedureIsValid(oprcode);
139 operatorObjectId = InvalidOid;
144 * close the scan and return the oid.
147 heap_endscan(pg_operator_scan);
149 return operatorObjectId;
152 /* ----------------------------------------------------------------
155 * finds the operator associated with the specified name
156 * and left and right type names.
157 * ----------------------------------------------------------------
160 OperatorGet(char *operatorName,
165 Relation pg_operator_desc;
167 Oid operatorObjectId;
168 Oid leftObjectId = InvalidOid;
169 Oid rightObjectId = InvalidOid;
170 bool leftDefined = false;
171 bool rightDefined = false;
174 * look up the operator data types.
176 * Note: types must be defined before operators
181 leftObjectId = TypeGet(leftTypeName, &leftDefined);
183 if (!OidIsValid(leftObjectId) || !leftDefined)
184 elog(ERROR, "OperatorGet: left type \"%s\" does not exist",
190 rightObjectId = TypeGet(rightTypeName, &rightDefined);
192 if (!OidIsValid(rightObjectId) || !rightDefined)
193 elog(ERROR, "OperatorGet: right type \"%s\" does not exist",
197 if (!((OidIsValid(leftObjectId) && leftDefined) ||
198 (OidIsValid(rightObjectId) && rightDefined)))
199 elog(ERROR, "OperatorGet: must have at least one argument type");
202 * open the pg_operator relation
205 pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
208 * get the oid for the operator with the appropriate name
209 * and left/right types.
212 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
219 * close the relation and return the operator oid.
222 heap_close(pg_operator_desc, AccessShareLock);
224 return operatorObjectId;
227 /* ----------------------------------------------------------------
228 * OperatorShellMakeWithOpenRelation
230 * ----------------------------------------------------------------
233 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
240 Datum values[Natts_pg_operator];
241 char nulls[Natts_pg_operator];
242 Oid operatorObjectId;
247 * initialize our *nulls and *values arrays
250 for (i = 0; i < Natts_pg_operator; ++i)
253 values[i] = (Datum) NULL; /* redundant, but safe */
257 * initialize *values with the operator name and input data types.
258 * Note that oprcode is set to InvalidOid, indicating it's a shell.
262 namestrcpy(&oname, operatorName);
263 values[i++] = NameGetDatum(&oname);
264 values[i++] = Int32GetDatum(GetUserId());
265 values[i++] = UInt16GetDatum(0);
266 values[i++] = CharGetDatum('b'); /* assume it's binary */
267 values[i++] = BoolGetDatum(false);
268 values[i++] = BoolGetDatum(false);
269 values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
270 values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
271 values[i++] = ObjectIdGetDatum(InvalidOid);
272 values[i++] = ObjectIdGetDatum(InvalidOid);
273 values[i++] = ObjectIdGetDatum(InvalidOid);
274 values[i++] = ObjectIdGetDatum(InvalidOid);
275 values[i++] = ObjectIdGetDatum(InvalidOid);
276 values[i++] = ObjectIdGetDatum(InvalidOid);
277 values[i++] = ObjectIdGetDatum(InvalidOid);
278 values[i++] = ObjectIdGetDatum(InvalidOid);
281 * create a new operator tuple
284 tupDesc = pg_operator_desc->rd_att;
286 tup = heap_formtuple(tupDesc,
291 * insert our "shell" operator tuple and
295 heap_insert(pg_operator_desc, tup);
296 operatorObjectId = tup->t_data->t_oid;
298 if (RelationGetForm(pg_operator_desc)->relhasindex)
300 Relation idescs[Num_pg_operator_indices];
302 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
303 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
304 CatalogCloseIndices(Num_pg_operator_indices, idescs);
308 * free the tuple and return the operator oid
313 return operatorObjectId;
316 /* ----------------------------------------------------------------
319 * Specify operator name and left and right type names,
320 * fill an operator struct with this info and NULL's,
321 * call heap_insert and return the Oid
323 * ----------------------------------------------------------------
326 OperatorShellMake(char *operatorName,
330 Relation pg_operator_desc;
331 Oid operatorObjectId;
333 Oid leftObjectId = InvalidOid;
334 Oid rightObjectId = InvalidOid;
335 bool leftDefined = false;
336 bool rightDefined = false;
339 * get the left and right type oid's for this operator
343 leftObjectId = TypeGet(leftTypeName, &leftDefined);
346 rightObjectId = TypeGet(rightTypeName, &rightDefined);
348 if (!((OidIsValid(leftObjectId) && leftDefined) ||
349 (OidIsValid(rightObjectId) && rightDefined)))
350 elog(ERROR, "OperatorShellMake: no valid argument types??");
356 pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
359 * add a "shell" operator tuple to the operator relation
360 * and recover the shell tuple's oid.
363 operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
368 * close the operator relation and return the oid.
371 heap_close(pg_operator_desc, RowExclusiveLock);
373 return operatorObjectId;
376 /* --------------------------------
379 * This routine gets complicated because it allows the user to
380 * specify operators that do not exist. For example, if operator
381 * "op" is being defined, the negator operator "negop" and the
382 * commutator "commop" can also be defined without specifying
383 * any information other than their names. Since in order to
384 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
385 * operators must be placed in the fields of "op", a forward
386 * declaration is done on the commutator and negator operators.
387 * This is called creating a shell, and its main effect is to
388 * create a tuple in the PG_OPERATOR catalog with minimal
389 * information about the operator (just its name and types).
390 * Forward declaration is used only for this purpose, it is
391 * not available to the user as it is for type definition.
395 * check if operator already defined
396 * if so, but oprcode is null, save the Oid -- we are filling in a shell
398 * get the attribute types from relation descriptor for pg_operator
399 * assign values to the fields of the operator:
401 * owner id (simply the user id of the caller)
403 * operator "kind" either "b" for binary or "l" for left unary
404 * isLeftAssociative boolean
406 * leftTypeObjectId -- type must already be defined
407 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
408 * resultType -- defer this, since it must be determined from
409 * the pg_procedure catalog
410 * commutatorObjectId -- if this is NULL, enter ObjectId=0
411 * else if this already exists, enter its ObjectId
412 * else if this does not yet exist, and is not
413 * the same as the main operatorName, then create
414 * a shell and enter the new ObjectId
415 * else if this does not exist but IS the same
416 * name & types as the main operator, set the ObjectId=0.
417 * (We are creating a self-commutating operator.)
418 * The link will be fixed later by OperatorUpd.
419 * negatorObjectId -- same as for commutatorObjectId
420 * leftSortObjectId -- same as for commutatorObjectId
421 * rightSortObjectId -- same as for commutatorObjectId
422 * operatorProcedure -- must access the pg_procedure catalog to get the
423 * ObjectId of the procedure that actually does the operator
424 * actions this is required. Do an amgetattr to find out the
425 * return type of the procedure
426 * restrictionProcedure -- must access the pg_procedure catalog to get
427 * the ObjectId but this is optional
428 * joinProcedure -- same as restrictionProcedure
429 * now either insert or replace the operator into the pg_operator catalog
430 * if the operator shell is being filled in
431 * access the catalog in order to get a valid buffer
432 * create a tuple using ModifyHeapTuple
433 * get the t_self from the modified tuple and call RelationReplaceHeapTuple
434 * else if a new operator is being created
435 * create a tuple using heap_formtuple
437 * --------------------------------
438 * "X" indicates an optional argument (i.e. one that can be NULL)
439 * operatorName; -- operator name
440 * leftTypeName; -- X left type name
441 * rightTypeName; -- X right type name
442 * procedureName; -- procedure name for operator code
443 * precedence; -- operator precedence
444 * isLeftAssociative; -- operator is left associative?
445 * commutatorName; -- X commutator operator name
446 * negatorName; -- X negator operator name
447 * restrictionName; -- X restriction sel. procedure name
448 * joinName; -- X join sel. procedure name
449 * canHash; -- can hash join be used with operator?
450 * leftSortName; -- X left sort operator (for merge join)
451 * rightSortName; -- X right sort operator (for merge join)
454 OperatorDef(char *operatorName,
459 bool isLeftAssociative,
460 char *commutatorName,
462 char *restrictionName,
470 Relation pg_operator_desc;
472 HeapScanDesc pg_operator_scan;
474 char nulls[Natts_pg_operator];
475 char replaces[Natts_pg_operator];
476 Datum values[Natts_pg_operator];
477 Oid operatorObjectId;
478 bool operatorAlreadyDefined;
479 Oid leftTypeId = InvalidOid;
480 Oid rightTypeId = InvalidOid;
481 Oid commutatorId = InvalidOid;
482 Oid negatorId = InvalidOid;
483 bool leftDefined = false;
484 bool rightDefined = false;
485 bool selfCommutator = false;
487 Oid typeId[FUNC_MAX_ARGS];
492 static ScanKeyData opKey[3] = {
493 {0, Anum_pg_operator_oprname, F_NAMEEQ},
494 {0, Anum_pg_operator_oprleft, F_OIDEQ},
495 {0, Anum_pg_operator_oprright, F_OIDEQ},
498 fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
499 fmgr_info(F_OIDEQ, &opKey[1].sk_func);
500 fmgr_info(F_OIDEQ, &opKey[2].sk_func);
501 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
502 opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
503 opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
505 operatorObjectId = OperatorGet(operatorName,
508 &operatorAlreadyDefined);
510 if (operatorAlreadyDefined)
511 elog(ERROR, "OperatorDef: operator \"%s\" already defined",
515 * At this point, if operatorObjectId is not InvalidOid then we are
516 * filling in a previously-created shell.
520 * look up the operator data types.
522 * Note: types must be defined before operators
527 leftTypeId = TypeGet(leftTypeName, &leftDefined);
529 if (!OidIsValid(leftTypeId) || !leftDefined)
530 elog(ERROR, "OperatorDef: left type \"%s\" does not exist",
536 rightTypeId = TypeGet(rightTypeName, &rightDefined);
538 if (!OidIsValid(rightTypeId) || !rightDefined)
539 elog(ERROR, "OperatorDef: right type \"%s\" does not exist",
543 if (!((OidIsValid(leftTypeId) && leftDefined) ||
544 (OidIsValid(rightTypeId) && rightDefined)))
545 elog(ERROR, "OperatorDef: must have at least one argument type");
547 for (i = 0; i < Natts_pg_operator; ++i)
549 values[i] = (Datum) NULL;
555 * Look up registered procedures -- find the return type
556 * of procedureName to place in "result" field.
557 * Do this before shells are created so we don't
558 * have to worry about deleting them later.
561 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
564 typeId[0] = rightTypeId;
567 else if (!rightTypeName)
569 typeId[0] = leftTypeId;
574 typeId[0] = leftTypeId;
575 typeId[1] = rightTypeId;
578 tup = SearchSysCache(PROCNAME,
579 PointerGetDatum(procedureName),
580 Int32GetDatum(nargs),
581 PointerGetDatum(typeId),
583 if (!HeapTupleIsValid(tup))
584 func_error("OperatorDef", procedureName, nargs, typeId, NULL);
586 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
587 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
588 GETSTRUCT(tup))->prorettype);
590 ReleaseSysCache(tup);
600 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
601 typeId[0] = OIDOID; /* operator OID */
602 typeId[1] = OIDOID; /* relation OID */
603 typeId[2] = INT2OID; /* attribute number */
604 typeId[3] = 0; /* value - can be any type */
605 typeId[4] = INT4OID; /* flags - left or right selectivity */
607 restOid = GetSysCacheOid(PROCNAME,
608 PointerGetDatum(restrictionName),
610 PointerGetDatum(typeId),
612 if (!OidIsValid(restOid))
613 func_error("OperatorDef", restrictionName, 5, typeId, NULL);
615 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
618 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
621 * find join - only valid for binary operators
628 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
629 typeId[0] = OIDOID; /* operator OID */
630 typeId[1] = OIDOID; /* relation OID 1 */
631 typeId[2] = INT2OID; /* attribute number 1 */
632 typeId[3] = OIDOID; /* relation OID 2 */
633 typeId[4] = INT2OID; /* attribute number 2 */
635 joinOid = GetSysCacheOid(PROCNAME,
636 PointerGetDatum(joinName),
638 PointerGetDatum(typeId),
640 if (!OidIsValid(joinOid))
641 func_error("OperatorDef", joinName, 5, typeId, NULL);
643 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
646 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
649 * set up values in the operator tuple
653 namestrcpy(&oname, operatorName);
654 values[i++] = NameGetDatum(&oname);
655 values[i++] = Int32GetDatum(GetUserId());
656 values[i++] = UInt16GetDatum(precedence);
657 values[i++] = CharGetDatum(leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l');
658 values[i++] = BoolGetDatum(isLeftAssociative);
659 values[i++] = BoolGetDatum(canHash);
660 values[i++] = ObjectIdGetDatum(leftTypeId);
661 values[i++] = ObjectIdGetDatum(rightTypeId);
663 ++i; /* Skip "oprresult", it was filled in
667 * Set up the other operators. If they do not currently exist, create
668 * shells in order to get ObjectId's.
670 name[0] = commutatorName;
671 name[1] = negatorName;
672 name[2] = leftSortName;
673 name[3] = rightSortName;
675 for (j = 0; j < 4; ++j)
679 char *otherLeftTypeName = NULL;
680 char *otherRightTypeName = NULL;
681 Oid otherLeftTypeId = InvalidOid;
682 Oid otherRightTypeId = InvalidOid;
683 Oid other_oid = InvalidOid;
684 bool otherDefined = false;
688 case 0: /* commutator has reversed arg types */
689 otherLeftTypeName = rightTypeName;
690 otherRightTypeName = leftTypeName;
691 otherLeftTypeId = rightTypeId;
692 otherRightTypeId = leftTypeId;
693 other_oid = OperatorGet(name[j],
697 commutatorId = other_oid;
699 case 1: /* negator has same arg types */
700 otherLeftTypeName = leftTypeName;
701 otherRightTypeName = rightTypeName;
702 otherLeftTypeId = leftTypeId;
703 otherRightTypeId = rightTypeId;
704 other_oid = OperatorGet(name[j],
708 negatorId = other_oid;
710 case 2: /* left sort op takes left-side data type */
711 otherLeftTypeName = leftTypeName;
712 otherRightTypeName = leftTypeName;
713 otherLeftTypeId = leftTypeId;
714 otherRightTypeId = leftTypeId;
715 other_oid = OperatorGet(name[j],
720 case 3: /* right sort op takes right-side data
722 otherLeftTypeName = rightTypeName;
723 otherRightTypeName = rightTypeName;
724 otherLeftTypeId = rightTypeId;
725 otherRightTypeId = rightTypeId;
726 other_oid = OperatorGet(name[j],
733 if (OidIsValid(other_oid))
735 /* other op already in catalogs */
736 values[i++] = ObjectIdGetDatum(other_oid);
738 else if (strcmp(operatorName, name[j]) != 0 ||
739 otherLeftTypeId != leftTypeId ||
740 otherRightTypeId != rightTypeId)
742 /* not in catalogs, different from operator */
743 other_oid = OperatorShellMake(name[j],
746 if (!OidIsValid(other_oid))
748 "OperatorDef: can't create operator shell \"%s\"",
750 values[i++] = ObjectIdGetDatum(other_oid);
756 * self-linkage to this operator; will fix below. Note
757 * that only self-linkage for commutation makes sense.
761 "OperatorDef: operator can't be its own negator or sort op");
762 selfCommutator = true;
763 values[i++] = ObjectIdGetDatum(InvalidOid);
768 /* other operator is omitted */
769 values[i++] = ObjectIdGetDatum(InvalidOid);
773 /* last three fields were filled in above */
775 pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
778 * If we are adding to an operator shell, get its t_self
780 if (operatorObjectId)
782 opKey[0].sk_argument = PointerGetDatum(operatorName);
783 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
784 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
786 /* Make sure we can see the shell even if it is new in current cmd */
787 CommandCounterIncrement();
789 pg_operator_scan = heap_beginscan(pg_operator_desc,
791 SnapshotSelf, /* no cache? */
795 tup = heap_getnext(pg_operator_scan, 0);
796 if (HeapTupleIsValid(tup))
798 tup = heap_modifytuple(tup,
804 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
807 elog(ERROR, "OperatorDef: no operator %u", operatorObjectId);
809 heap_endscan(pg_operator_scan);
813 tupDesc = pg_operator_desc->rd_att;
814 tup = heap_formtuple(tupDesc, values, nulls);
816 heap_insert(pg_operator_desc, tup);
817 operatorObjectId = tup->t_data->t_oid;
821 if (RelationGetForm(pg_operator_desc)->relhasindex)
823 Relation idescs[Num_pg_operator_indices];
825 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
826 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
827 CatalogCloseIndices(Num_pg_operator_indices, idescs);
830 heap_close(pg_operator_desc, RowExclusiveLock);
833 * If a commutator and/or negator link is provided, update the other
834 * operator(s) to point at this one, if they don't already have a
835 * link. This supports an alternate style of operator definition
836 * wherein the user first defines one operator without giving negator
837 * or commutator, then defines the other operator of the pair with the
838 * proper commutator or negator attribute. That style doesn't require
839 * creation of a shell, and it's the only style that worked right
840 * before Postgres version 6.5. This code also takes care of the
841 * situation where the new operator is its own commutator.
844 commutatorId = operatorObjectId;
846 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
847 OperatorUpd(operatorObjectId, commutatorId, negatorId);
850 /* ----------------------------------------------------------------
853 * For a given operator, look up its negator and commutator operators.
854 * If they are defined, but their negator and commutator fields
855 * (respectively) are empty, then use the new operator for neg or comm.
856 * This solves a problem for users who need to insert two new operators
857 * which are the negator or commutator of each other.
858 * ----------------------------------------------------------------
861 OperatorUpd(Oid baseId, Oid commId, Oid negId)
864 Relation pg_operator_desc;
865 HeapScanDesc pg_operator_scan;
867 char nulls[Natts_pg_operator];
868 char replaces[Natts_pg_operator];
869 Datum values[Natts_pg_operator];
871 static ScanKeyData opKey[1] = {
872 {0, ObjectIdAttributeNumber, F_OIDEQ},
875 fmgr_info(F_OIDEQ, &opKey[0].sk_func);
876 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
878 for (i = 0; i < Natts_pg_operator; ++i)
880 values[i] = (Datum) NULL;
885 pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
888 * check and update the commutator & negator, if necessary
890 * First make sure we can see them...
892 CommandCounterIncrement();
894 opKey[0].sk_argument = ObjectIdGetDatum(commId);
896 pg_operator_scan = heap_beginscan(pg_operator_desc,
898 SnapshotSelf, /* no cache? */
902 tup = heap_getnext(pg_operator_scan, 0);
905 * if the commutator and negator are the same operator, do one update.
906 * XXX this is probably useless code --- I doubt it ever makes sense
907 * for commutator and negator to be the same thing...
911 if (HeapTupleIsValid(tup))
915 t = (Form_pg_operator) GETSTRUCT(tup);
916 if (!OidIsValid(t->oprcom)
917 || !OidIsValid(t->oprnegate))
920 if (!OidIsValid(t->oprnegate))
922 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
923 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
926 if (!OidIsValid(t->oprcom))
928 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
929 replaces[Anum_pg_operator_oprcom - 1] = 'r';
932 tup = heap_modifytuple(tup,
938 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
940 if (RelationGetForm(pg_operator_desc)->relhasindex)
942 Relation idescs[Num_pg_operator_indices];
944 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
945 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
946 CatalogCloseIndices(Num_pg_operator_indices, idescs);
950 heap_endscan(pg_operator_scan);
952 heap_close(pg_operator_desc, RowExclusiveLock);
957 /* if commutator and negator are different, do two updates */
959 if (HeapTupleIsValid(tup) &&
960 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
962 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
963 replaces[Anum_pg_operator_oprcom - 1] = 'r';
964 tup = heap_modifytuple(tup,
970 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
972 if (RelationGetForm(pg_operator_desc)->relhasindex)
974 Relation idescs[Num_pg_operator_indices];
976 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
977 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
978 CatalogCloseIndices(Num_pg_operator_indices, idescs);
981 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
982 replaces[Anum_pg_operator_oprcom - 1] = ' ';
985 heap_endscan(pg_operator_scan);
987 /* check and update the negator, if necessary */
988 opKey[0].sk_argument = ObjectIdGetDatum(negId);
990 pg_operator_scan = heap_beginscan(pg_operator_desc,
992 SnapshotSelf, /* no cache? */
996 tup = heap_getnext(pg_operator_scan, 0);
997 if (HeapTupleIsValid(tup) &&
998 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
1000 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
1001 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
1002 tup = heap_modifytuple(tup,
1008 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
1010 if (RelationGetForm(pg_operator_desc)->relhasindex)
1012 Relation idescs[Num_pg_operator_indices];
1014 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
1015 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
1016 CatalogCloseIndices(Num_pg_operator_indices, idescs);
1020 heap_endscan(pg_operator_scan);
1023 heap_close(pg_operator_desc, RowExclusiveLock);
1027 /* ----------------------------------------------------------------
1030 * This is now just an interface procedure for OperatorDef ...
1032 * "X" indicates an optional argument (i.e. one that can be NULL)
1033 * operatorName; -- operator name
1034 * leftTypeName; -- X left type name
1035 * rightTypeName; -- X right type name
1036 * procedureName; -- procedure for operator
1037 * precedence; -- operator precedence
1038 * isLeftAssociative; -- operator is left associative
1039 * commutatorName; -- X commutator operator name
1040 * negatorName; -- X negator operator name
1041 * restrictionName; -- X restriction sel. procedure
1042 * joinName; -- X join sel. procedure
1043 * canHash; -- hash join can be used with this operator
1044 * leftSortName; -- X left sort operator (for merge join)
1045 * rightSortName; -- X right sort operator (for merge join)
1048 OperatorCreate(char *operatorName,
1050 char *rightTypeName,
1051 char *procedureName,
1053 bool isLeftAssociative,
1054 char *commutatorName,
1056 char *restrictionName,
1060 char *rightSortName)
1062 if (!leftTypeName && !rightTypeName)
1063 elog(ERROR, "OperatorCreate: at least one of leftarg or rightarg must be defined");
1065 if (!(leftTypeName && rightTypeName))
1067 /* If it's not a binary op, these things mustn't be set: */
1069 elog(ERROR, "OperatorCreate: only binary operators can have commutators");
1071 elog(ERROR, "OperatorCreate: only binary operators can have negators");
1072 if (restrictionName || joinName)
1073 elog(ERROR, "OperatorCreate: only binary operators can have selectivity");
1075 elog(ERROR, "OperatorCreate: only binary operators can hash");
1076 if (leftSortName || rightSortName)
1077 elog(ERROR, "OperatorCreate: only binary operators can have sort links");
1081 * Use OperatorDef() to define the specified operator and
1082 * also create shells for the operator's associated operators
1083 * if they don't already exist.
1086 OperatorDef(operatorName,