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.51 2000/08/21 17:22:35 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' nonexistent",
190 rightObjectId = TypeGet(rightTypeName, &rightDefined);
192 if (!OidIsValid(rightObjectId) || !rightDefined)
193 elog(ERROR, "OperatorGet: right type '%s' nonexistent",
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' nonexistent",
536 rightTypeId = TypeGet(rightTypeName, &rightDefined);
538 if (!OidIsValid(rightTypeId) || !rightDefined)
539 elog(ERROR, "OperatorDef: right type '%s' nonexistent",
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 = SearchSysCacheTuple(PROCNAME,
579 PointerGetDatum(procedureName),
580 Int32GetDatum(nargs),
581 PointerGetDatum(typeId),
584 if (!HeapTupleIsValid(tup))
585 func_error("OperatorDef", procedureName, nargs, typeId, NULL);
587 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
588 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
589 GETSTRUCT(tup))->prorettype);
597 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
598 typeId[0] = OIDOID; /* operator OID */
599 typeId[1] = OIDOID; /* relation OID */
600 typeId[2] = INT2OID; /* attribute number */
601 typeId[3] = 0; /* value - can be any type */
602 typeId[4] = INT4OID; /* flags - left or right selectivity */
603 tup = SearchSysCacheTuple(PROCNAME,
604 PointerGetDatum(restrictionName),
606 PointerGetDatum(typeId),
608 if (!HeapTupleIsValid(tup))
609 func_error("OperatorDef", restrictionName, 5, typeId, NULL);
611 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
614 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
617 * find join - only valid for binary operators
622 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
623 typeId[0] = OIDOID; /* operator OID */
624 typeId[1] = OIDOID; /* relation OID 1 */
625 typeId[2] = INT2OID; /* attribute number 1 */
626 typeId[3] = OIDOID; /* relation OID 2 */
627 typeId[4] = INT2OID; /* attribute number 2 */
629 tup = SearchSysCacheTuple(PROCNAME,
630 PointerGetDatum(joinName),
632 PointerGetDatum(typeId),
634 if (!HeapTupleIsValid(tup))
635 func_error("OperatorDef", joinName, 5, typeId, NULL);
637 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
640 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
643 * set up values in the operator tuple
647 namestrcpy(&oname, operatorName);
648 values[i++] = NameGetDatum(&oname);
649 values[i++] = Int32GetDatum(GetUserId());
650 values[i++] = UInt16GetDatum(precedence);
651 values[i++] = CharGetDatum(leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l');
652 values[i++] = BoolGetDatum(isLeftAssociative);
653 values[i++] = BoolGetDatum(canHash);
654 values[i++] = ObjectIdGetDatum(leftTypeId);
655 values[i++] = ObjectIdGetDatum(rightTypeId);
657 ++i; /* Skip "oprresult", it was filled in
661 * Set up the other operators. If they do not currently exist, create
662 * shells in order to get ObjectId's.
664 name[0] = commutatorName;
665 name[1] = negatorName;
666 name[2] = leftSortName;
667 name[3] = rightSortName;
669 for (j = 0; j < 4; ++j)
673 char *otherLeftTypeName = NULL;
674 char *otherRightTypeName = NULL;
675 Oid otherLeftTypeId = InvalidOid;
676 Oid otherRightTypeId = InvalidOid;
677 Oid other_oid = InvalidOid;
678 bool otherDefined = false;
682 case 0: /* commutator has reversed arg types */
683 otherLeftTypeName = rightTypeName;
684 otherRightTypeName = leftTypeName;
685 otherLeftTypeId = rightTypeId;
686 otherRightTypeId = leftTypeId;
687 other_oid = OperatorGet(name[j],
691 commutatorId = other_oid;
693 case 1: /* negator has same arg types */
694 otherLeftTypeName = leftTypeName;
695 otherRightTypeName = rightTypeName;
696 otherLeftTypeId = leftTypeId;
697 otherRightTypeId = rightTypeId;
698 other_oid = OperatorGet(name[j],
702 negatorId = other_oid;
704 case 2: /* left sort op takes left-side data type */
705 otherLeftTypeName = leftTypeName;
706 otherRightTypeName = leftTypeName;
707 otherLeftTypeId = leftTypeId;
708 otherRightTypeId = leftTypeId;
709 other_oid = OperatorGet(name[j],
714 case 3: /* right sort op takes right-side data
716 otherLeftTypeName = rightTypeName;
717 otherRightTypeName = rightTypeName;
718 otherLeftTypeId = rightTypeId;
719 otherRightTypeId = rightTypeId;
720 other_oid = OperatorGet(name[j],
727 if (OidIsValid(other_oid))
729 /* other op already in catalogs */
730 values[i++] = ObjectIdGetDatum(other_oid);
732 else if (strcmp(operatorName, name[j]) != 0 ||
733 otherLeftTypeId != leftTypeId ||
734 otherRightTypeId != rightTypeId)
736 /* not in catalogs, different from operator */
737 other_oid = OperatorShellMake(name[j],
740 if (!OidIsValid(other_oid))
742 "OperatorDef: can't create operator shell '%s'",
744 values[i++] = ObjectIdGetDatum(other_oid);
750 * self-linkage to this operator; will fix below. Note
751 * that only self-linkage for commutation makes sense.
755 "OperatorDef: operator can't be its own negator or sort op");
756 selfCommutator = true;
757 values[i++] = ObjectIdGetDatum(InvalidOid);
762 /* other operator is omitted */
763 values[i++] = ObjectIdGetDatum(InvalidOid);
767 /* last three fields were filled in above */
769 pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
772 * If we are adding to an operator shell, get its t_self
774 if (operatorObjectId)
776 opKey[0].sk_argument = PointerGetDatum(operatorName);
777 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
778 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
780 /* Make sure we can see the shell even if it is new in current cmd */
781 CommandCounterIncrement();
783 pg_operator_scan = heap_beginscan(pg_operator_desc,
785 SnapshotSelf, /* no cache? */
789 tup = heap_getnext(pg_operator_scan, 0);
790 if (HeapTupleIsValid(tup))
792 tup = heap_modifytuple(tup,
798 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
801 elog(ERROR, "OperatorDef: no operator %u", operatorObjectId);
803 heap_endscan(pg_operator_scan);
807 tupDesc = pg_operator_desc->rd_att;
808 tup = heap_formtuple(tupDesc, values, nulls);
810 heap_insert(pg_operator_desc, tup);
811 operatorObjectId = tup->t_data->t_oid;
815 if (RelationGetForm(pg_operator_desc)->relhasindex)
817 Relation idescs[Num_pg_operator_indices];
819 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
820 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
821 CatalogCloseIndices(Num_pg_operator_indices, idescs);
824 heap_close(pg_operator_desc, RowExclusiveLock);
827 * If a commutator and/or negator link is provided, update the other
828 * operator(s) to point at this one, if they don't already have a
829 * link. This supports an alternate style of operator definition
830 * wherein the user first defines one operator without giving negator
831 * or commutator, then defines the other operator of the pair with the
832 * proper commutator or negator attribute. That style doesn't require
833 * creation of a shell, and it's the only style that worked right
834 * before Postgres version 6.5. This code also takes care of the
835 * situation where the new operator is its own commutator.
838 commutatorId = operatorObjectId;
840 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
841 OperatorUpd(operatorObjectId, commutatorId, negatorId);
844 /* ----------------------------------------------------------------
847 * For a given operator, look up its negator and commutator operators.
848 * If they are defined, but their negator and commutator fields
849 * (respectively) are empty, then use the new operator for neg or comm.
850 * This solves a problem for users who need to insert two new operators
851 * which are the negator or commutator of each other.
852 * ----------------------------------------------------------------
855 OperatorUpd(Oid baseId, Oid commId, Oid negId)
858 Relation pg_operator_desc;
859 HeapScanDesc pg_operator_scan;
861 char nulls[Natts_pg_operator];
862 char replaces[Natts_pg_operator];
863 Datum values[Natts_pg_operator];
865 static ScanKeyData opKey[1] = {
866 {0, ObjectIdAttributeNumber, F_OIDEQ},
869 fmgr_info(F_OIDEQ, &opKey[0].sk_func);
870 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
872 for (i = 0; i < Natts_pg_operator; ++i)
874 values[i] = (Datum) NULL;
879 pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
882 * check and update the commutator & negator, if necessary
884 * First make sure we can see them...
886 CommandCounterIncrement();
888 opKey[0].sk_argument = ObjectIdGetDatum(commId);
890 pg_operator_scan = heap_beginscan(pg_operator_desc,
892 SnapshotSelf, /* no cache? */
896 tup = heap_getnext(pg_operator_scan, 0);
899 * if the commutator and negator are the same operator, do one update.
900 * XXX this is probably useless code --- I doubt it ever makes sense
901 * for commutator and negator to be the same thing...
905 if (HeapTupleIsValid(tup))
909 t = (Form_pg_operator) GETSTRUCT(tup);
910 if (!OidIsValid(t->oprcom)
911 || !OidIsValid(t->oprnegate))
914 if (!OidIsValid(t->oprnegate))
916 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
917 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
920 if (!OidIsValid(t->oprcom))
922 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
923 replaces[Anum_pg_operator_oprcom - 1] = 'r';
926 tup = heap_modifytuple(tup,
932 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
934 if (RelationGetForm(pg_operator_desc)->relhasindex)
936 Relation idescs[Num_pg_operator_indices];
938 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
939 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
940 CatalogCloseIndices(Num_pg_operator_indices, idescs);
944 heap_endscan(pg_operator_scan);
946 heap_close(pg_operator_desc, RowExclusiveLock);
951 /* if commutator and negator are different, do two updates */
953 if (HeapTupleIsValid(tup) &&
954 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
956 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
957 replaces[Anum_pg_operator_oprcom - 1] = 'r';
958 tup = heap_modifytuple(tup,
964 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
966 if (RelationGetForm(pg_operator_desc)->relhasindex)
968 Relation idescs[Num_pg_operator_indices];
970 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
971 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
972 CatalogCloseIndices(Num_pg_operator_indices, idescs);
975 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
976 replaces[Anum_pg_operator_oprcom - 1] = ' ';
979 heap_endscan(pg_operator_scan);
981 /* check and update the negator, if necessary */
982 opKey[0].sk_argument = ObjectIdGetDatum(negId);
984 pg_operator_scan = heap_beginscan(pg_operator_desc,
986 SnapshotSelf, /* no cache? */
990 tup = heap_getnext(pg_operator_scan, 0);
991 if (HeapTupleIsValid(tup) &&
992 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
994 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
995 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
996 tup = heap_modifytuple(tup,
1002 heap_update(pg_operator_desc, &tup->t_self, tup, NULL);
1004 if (RelationGetForm(pg_operator_desc)->relhasindex)
1006 Relation idescs[Num_pg_operator_indices];
1008 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
1009 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
1010 CatalogCloseIndices(Num_pg_operator_indices, idescs);
1014 heap_endscan(pg_operator_scan);
1017 heap_close(pg_operator_desc, RowExclusiveLock);
1021 /* ----------------------------------------------------------------
1024 * This is now just an interface procedure for OperatorDef ...
1026 * "X" indicates an optional argument (i.e. one that can be NULL)
1027 * operatorName; -- operator name
1028 * leftTypeName; -- X left type name
1029 * rightTypeName; -- X right type name
1030 * procedureName; -- procedure for operator
1031 * precedence; -- operator precedence
1032 * isLeftAssociative; -- operator is left associative
1033 * commutatorName; -- X commutator operator name
1034 * negatorName; -- X negator operator name
1035 * restrictionName; -- X restriction sel. procedure
1036 * joinName; -- X join sel. procedure
1037 * canHash; -- hash join can be used with this operator
1038 * leftSortName; -- X left sort operator (for merge join)
1039 * rightSortName; -- X right sort operator (for merge join)
1042 OperatorCreate(char *operatorName,
1044 char *rightTypeName,
1045 char *procedureName,
1047 bool isLeftAssociative,
1048 char *commutatorName,
1050 char *restrictionName,
1054 char *rightSortName)
1056 if (!leftTypeName && !rightTypeName)
1057 elog(ERROR, "OperatorCreate: at least one of leftarg or rightarg must be defined");
1059 if (!(leftTypeName && rightTypeName))
1061 /* If it's not a binary op, these things mustn't be set: */
1063 elog(ERROR, "OperatorCreate: only binary operators can have commutators");
1065 elog(ERROR, "OperatorCreate: only binary operators can have negators");
1066 if (restrictionName || joinName)
1067 elog(ERROR, "OperatorCreate: only binary operators can have selectivity");
1069 elog(ERROR, "OperatorCreate: only binary operators can hash");
1070 if (leftSortName || rightSortName)
1071 elog(ERROR, "OperatorCreate: only binary operators can have sort links");
1075 * Use OperatorDef() to define the specified operator and
1076 * also create shells for the operator's associated operators
1077 * if they don't already exist.
1080 OperatorDef(operatorName,