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.35 1999/04/23 00:50:57 tgl Exp $
13 * these routines moved here from commands/define.c and somewhat cleaned up.
15 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "catalog/catname.h"
21 #include "catalog/pg_operator.h"
22 #include "catalog/pg_proc.h"
23 #include "catalog/pg_type.h"
25 #include "miscadmin.h"
26 #include "parser/parse_oper.h"
27 #include "storage/bufmgr.h"
28 #include "utils/builtins.h"
29 #include "utils/syscache.h"
30 #include "utils/tqual.h"
33 #include <regex/utils.h>
38 static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
39 const char *operatorName,
44 static Oid OperatorGet(char *operatorName,
49 static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
54 static Oid OperatorShellMake(char *operatorName,
58 static void OperatorDef(char *operatorName,
63 bool isLeftAssociative,
66 char *restrictionName,
72 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
74 /* ----------------------------------------------------------------
75 * OperatorGetWithOpenRelation
77 * preforms a scan on pg_operator for an operator tuple
78 * with given name and left/right type oids.
79 * ----------------------------------------------------------------
80 * pg_operator_desc -- reldesc for pg_operator
81 * operatorName -- name of operator to fetch
82 * leftObjectId -- left data type oid of operator to fetch
83 * rightObjectId -- right data type oid of operator to fetch
84 * defined -- set TRUE if defined (not a shell)
87 OperatorGetWithOpenRelation(Relation pg_operator_desc,
88 const char *operatorName,
93 HeapScanDesc pg_operator_scan;
97 static ScanKeyData opKey[3] = {
98 {0, Anum_pg_operator_oprname, F_NAMEEQ},
99 {0, Anum_pg_operator_oprleft, F_OIDEQ},
100 {0, Anum_pg_operator_oprright, F_OIDEQ},
103 fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
104 fmgr_info(F_OIDEQ, &opKey[1].sk_func);
105 fmgr_info(F_OIDEQ, &opKey[2].sk_func);
106 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
107 opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
108 opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
114 opKey[0].sk_argument = PointerGetDatum(operatorName);
115 opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
116 opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
122 pg_operator_scan = heap_beginscan(pg_operator_desc,
124 SnapshotSelf, /* no cache? */
129 * fetch the operator tuple, if it exists, and determine
130 * the proper return oid value.
133 tup = heap_getnext(pg_operator_scan, 0);
135 if (HeapTupleIsValid(tup))
137 regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
138 operatorObjectId = tup->t_data->t_oid;
139 *defined = RegProcedureIsValid(oprcode);
143 operatorObjectId = InvalidOid;
148 * close the scan and return the oid.
151 heap_endscan(pg_operator_scan);
153 return operatorObjectId;
156 /* ----------------------------------------------------------------
159 * finds the operator associated with the specified name
160 * and left and right type names.
161 * ----------------------------------------------------------------
164 OperatorGet(char *operatorName,
169 Relation pg_operator_desc;
171 Oid operatorObjectId;
172 Oid leftObjectId = InvalidOid;
173 Oid rightObjectId = InvalidOid;
174 bool leftDefined = false;
175 bool rightDefined = false;
178 * look up the operator data types.
180 * Note: types must be defined before operators
185 leftObjectId = TypeGet(leftTypeName, &leftDefined);
187 if (!OidIsValid(leftObjectId) || !leftDefined)
188 elog(ERROR, "OperatorGet: left type '%s' nonexistent",
194 rightObjectId = TypeGet(rightTypeName, &rightDefined);
196 if (!OidIsValid(rightObjectId) || !rightDefined)
197 elog(ERROR, "OperatorGet: right type '%s' nonexistent",
201 if (!((OidIsValid(leftObjectId) && leftDefined) ||
202 (OidIsValid(rightObjectId) && rightDefined)))
203 elog(ERROR, "OperatorGet: must have at least one argument type");
206 * open the pg_operator relation
209 pg_operator_desc = heap_openr(OperatorRelationName);
212 * get the oid for the operator with the appropriate name
213 * and left/right types.
216 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
223 * close the relation and return the operator oid.
226 heap_close(pg_operator_desc);
228 return operatorObjectId;
231 /* ----------------------------------------------------------------
232 * OperatorShellMakeWithOpenRelation
234 * ----------------------------------------------------------------
237 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
244 Datum values[Natts_pg_operator];
245 char nulls[Natts_pg_operator];
246 Oid operatorObjectId;
251 * initialize our *nulls and *values arrays
254 for (i = 0; i < Natts_pg_operator; ++i)
257 values[i] = (Datum) NULL; /* redundant, but safe */
261 * initialize *values with the operator name and input data types.
262 * Note that oprcode is set to InvalidOid, indicating it's a shell.
266 namestrcpy(&oname, operatorName);
267 values[i++] = NameGetDatum(&oname);
268 values[i++] = Int32GetDatum(GetUserId());
269 values[i++] = (Datum) (uint16) 0;
270 values[i++] = (Datum) 'b'; /* assume it's binary */
271 values[i++] = (Datum) (bool) 0;
272 values[i++] = (Datum) (bool) 0;
273 values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
274 values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
275 values[i++] = ObjectIdGetDatum(InvalidOid);
276 values[i++] = ObjectIdGetDatum(InvalidOid);
277 values[i++] = ObjectIdGetDatum(InvalidOid);
278 values[i++] = ObjectIdGetDatum(InvalidOid);
279 values[i++] = ObjectIdGetDatum(InvalidOid);
280 values[i++] = ObjectIdGetDatum(InvalidOid);
281 values[i++] = ObjectIdGetDatum(InvalidOid);
282 values[i++] = ObjectIdGetDatum(InvalidOid);
285 * create a new operator tuple
288 tupDesc = pg_operator_desc->rd_att;
290 tup = heap_formtuple(tupDesc,
295 * insert our "shell" operator tuple and
299 heap_insert(pg_operator_desc, tup);
300 operatorObjectId = tup->t_data->t_oid;
303 * free the tuple and return the operator oid
308 return operatorObjectId;
311 /* ----------------------------------------------------------------
314 * Specify operator name and left and right type names,
315 * fill an operator struct with this info and NULL's,
316 * call heap_insert and return the Oid
318 * ----------------------------------------------------------------
321 OperatorShellMake(char *operatorName,
325 Relation pg_operator_desc;
326 Oid operatorObjectId;
328 Oid leftObjectId = InvalidOid;
329 Oid rightObjectId = InvalidOid;
330 bool leftDefined = false;
331 bool rightDefined = false;
334 * get the left and right type oid's for this operator
338 leftObjectId = TypeGet(leftTypeName, &leftDefined);
341 rightObjectId = TypeGet(rightTypeName, &rightDefined);
343 if (!((OidIsValid(leftObjectId) && leftDefined) ||
344 (OidIsValid(rightObjectId) && rightDefined)))
345 elog(ERROR, "OperatorShellMake: no valid argument types??");
351 pg_operator_desc = heap_openr(OperatorRelationName);
354 * add a "shell" operator tuple to the operator relation
355 * and recover the shell tuple's oid.
358 operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
363 * close the operator relation and return the oid.
366 heap_close(pg_operator_desc);
368 return operatorObjectId;
371 /* --------------------------------
374 * This routine gets complicated because it allows the user to
375 * specify operators that do not exist. For example, if operator
376 * "op" is being defined, the negator operator "negop" and the
377 * commutator "commop" can also be defined without specifying
378 * any information other than their names. Since in order to
379 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
380 * operators must be placed in the fields of "op", a forward
381 * declaration is done on the commutator and negator operators.
382 * This is called creating a shell, and its main effect is to
383 * create a tuple in the PG_OPERATOR catalog with minimal
384 * information about the operator (just its name and types).
385 * Forward declaration is used only for this purpose, it is
386 * not available to the user as it is for type definition.
390 * check if operator already defined
391 * if so, but oprcode is null, save the Oid -- we are filling in a shell
393 * get the attribute types from relation descriptor for pg_operator
394 * assign values to the fields of the operator:
396 * owner id (simply the user id of the caller)
398 * operator "kind" either "b" for binary or "l" for left unary
399 * isLeftAssociative boolean
401 * leftTypeObjectId -- type must already be defined
402 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
403 * resultType -- defer this, since it must be determined from
404 * the pg_procedure catalog
405 * commutatorObjectId -- if this is NULL, enter ObjectId=0
406 * else if this already exists, enter it's ObjectId
407 * else if this does not yet exist, and is not
408 * the same as the main operatorName, then create
409 * a shell and enter the new ObjectId
410 * else if this does not exist but IS the same
411 * name & types as the main operator, set the ObjectId=0.
412 * (We are creating a self-commutating operator.)
413 * The link will be fixed later by OperatorUpd.
414 * negatorObjectId -- same as for commutatorObjectId
415 * leftSortObjectId -- same as for commutatorObjectId
416 * rightSortObjectId -- same as for commutatorObjectId
417 * operatorProcedure -- must access the pg_procedure catalog to get the
418 * ObjectId of the procedure that actually does the operator
419 * actions this is required. Do an amgetattr to find out the
420 * return type of the procedure
421 * restrictionProcedure -- must access the pg_procedure catalog to get
422 * the ObjectId but this is optional
423 * joinProcedure -- same as restrictionProcedure
424 * now either insert or replace the operator into the pg_operator catalog
425 * if the operator shell is being filled in
426 * access the catalog in order to get a valid buffer
427 * create a tuple using ModifyHeapTuple
428 * get the t_self from the modified tuple and call RelationReplaceHeapTuple
429 * else if a new operator is being created
430 * create a tuple using heap_formtuple
432 * --------------------------------
433 * "X" indicates an optional argument (i.e. one that can be NULL)
434 * operatorName; -- operator name
435 * leftTypeName; -- X left type name
436 * rightTypeName; -- X right type name
437 * procedureName; -- procedure name for operator code
438 * precedence; -- operator precedence
439 * isLeftAssociative; -- operator is left associative?
440 * commutatorName; -- X commutator operator name
441 * negatorName; -- X negator operator name
442 * restrictionName; -- X restriction sel. procedure name
443 * joinName; -- X join sel. procedure name
444 * canHash; -- can hash join be used with operator?
445 * leftSortName; -- X left sort operator (for merge join)
446 * rightSortName; -- X right sort operator (for merge join)
449 OperatorDef(char *operatorName,
454 bool isLeftAssociative,
455 char *commutatorName,
457 char *restrictionName,
465 Relation pg_operator_desc;
467 HeapScanDesc pg_operator_scan;
469 char nulls[Natts_pg_operator];
470 char replaces[Natts_pg_operator];
471 Datum values[Natts_pg_operator];
472 Oid operatorObjectId;
473 bool operatorAlreadyDefined;
474 Oid leftTypeId = InvalidOid;
475 Oid rightTypeId = InvalidOid;
476 Oid commutatorId = InvalidOid;
477 Oid negatorId = InvalidOid;
478 bool leftDefined = false;
479 bool rightDefined = false;
480 bool selfCommutator = false;
487 static ScanKeyData opKey[3] = {
488 {0, Anum_pg_operator_oprname, F_NAMEEQ},
489 {0, Anum_pg_operator_oprleft, F_OIDEQ},
490 {0, Anum_pg_operator_oprright, F_OIDEQ},
493 fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
494 fmgr_info(F_OIDEQ, &opKey[1].sk_func);
495 fmgr_info(F_OIDEQ, &opKey[2].sk_func);
496 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
497 opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
498 opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
500 operatorObjectId = OperatorGet(operatorName,
503 &operatorAlreadyDefined);
505 if (operatorAlreadyDefined)
506 elog(ERROR, "OperatorDef: operator \"%s\" already defined",
509 /* At this point, if operatorObjectId is not InvalidOid then
510 * we are filling in a previously-created shell.
514 * look up the operator data types.
516 * Note: types must be defined before operators
521 leftTypeId = TypeGet(leftTypeName, &leftDefined);
523 if (!OidIsValid(leftTypeId) || !leftDefined)
524 elog(ERROR, "OperatorDef: left type '%s' nonexistent",
530 rightTypeId = TypeGet(rightTypeName, &rightDefined);
532 if (!OidIsValid(rightTypeId) || !rightDefined)
533 elog(ERROR, "OperatorDef: right type '%s' nonexistent",
537 if (!((OidIsValid(leftTypeId) && leftDefined) ||
538 (OidIsValid(rightTypeId) && rightDefined)))
539 elog(ERROR, "OperatorDef: must have at least one argument type");
541 for (i = 0; i < Natts_pg_operator; ++i)
543 values[i] = (Datum) NULL;
549 * Look up registered procedures -- find the return type
550 * of procedureName to place in "result" field.
551 * Do this before shells are created so we don't
552 * have to worry about deleting them later.
555 MemSet(typeId, 0, 8 * sizeof(Oid));
558 typeId[0] = rightTypeId;
561 else if (!rightTypeName)
563 typeId[0] = leftTypeId;
568 typeId[0] = leftTypeId;
569 typeId[1] = rightTypeId;
572 tup = SearchSysCacheTuple(PRONAME,
573 PointerGetDatum(procedureName),
574 Int32GetDatum(nargs),
575 PointerGetDatum(typeId),
578 if (!HeapTupleIsValid(tup))
579 func_error("OperatorDef", procedureName, nargs, typeId, NULL);
581 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
582 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
583 GETSTRUCT(tup))->prorettype);
591 MemSet(typeId, 0, 8 * sizeof(Oid));
592 typeId[0] = OIDOID; /* operator OID */
593 typeId[1] = OIDOID; /* relation OID */
594 typeId[2] = INT2OID; /* attribute number */
595 typeId[3] = 0; /* value - can be any type */
596 typeId[4] = INT4OID; /* flags - left or right selectivity */
597 tup = SearchSysCacheTuple(PRONAME,
598 PointerGetDatum(restrictionName),
600 PointerGetDatum(typeId),
602 if (!HeapTupleIsValid(tup))
603 func_error("OperatorDef", restrictionName, 5, typeId, NULL);
605 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
608 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
611 * find join - only valid for binary operators
616 MemSet(typeId, 0, 8 * sizeof(Oid));
617 typeId[0] = OIDOID; /* operator OID */
618 typeId[1] = OIDOID; /* relation OID 1 */
619 typeId[2] = INT2OID; /* attribute number 1 */
620 typeId[3] = OIDOID; /* relation OID 2 */
621 typeId[4] = INT2OID; /* attribute number 2 */
623 tup = SearchSysCacheTuple(PRONAME,
624 PointerGetDatum(joinName),
626 PointerGetDatum(typeId),
628 if (!HeapTupleIsValid(tup))
629 func_error("OperatorDef", joinName, 5, typeId, NULL);
631 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
634 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
637 * set up values in the operator tuple
641 namestrcpy(&oname, operatorName);
642 values[i++] = NameGetDatum(&oname);
643 values[i++] = Int32GetDatum(GetUserId());
644 values[i++] = UInt16GetDatum(precedence);
645 values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
646 values[i++] = Int8GetDatum(isLeftAssociative);
647 values[i++] = Int8GetDatum(canHash);
648 values[i++] = ObjectIdGetDatum(leftTypeId);
649 values[i++] = ObjectIdGetDatum(rightTypeId);
651 ++i; /* Skip "oprresult", it was filled in above */
654 * Set up the other operators. If they do not currently exist, create
655 * shells in order to get ObjectId's.
657 name[0] = commutatorName;
658 name[1] = negatorName;
659 name[2] = leftSortName;
660 name[3] = rightSortName;
662 for (j = 0; j < 4; ++j)
666 char *otherLeftTypeName = NULL;
667 char *otherRightTypeName = NULL;
668 Oid otherLeftTypeId = InvalidOid;
669 Oid otherRightTypeId = InvalidOid;
670 Oid other_oid = InvalidOid;
671 bool otherDefined = false;
675 case 0: /* commutator has reversed arg types */
676 otherLeftTypeName = rightTypeName;
677 otherRightTypeName = leftTypeName;
678 otherLeftTypeId = rightTypeId;
679 otherRightTypeId = leftTypeId;
680 other_oid = OperatorGet(name[j],
684 commutatorId = other_oid;
686 case 1: /* negator has same arg types */
687 otherLeftTypeName = leftTypeName;
688 otherRightTypeName = rightTypeName;
689 otherLeftTypeId = leftTypeId;
690 otherRightTypeId = rightTypeId;
691 other_oid = OperatorGet(name[j],
695 negatorId = other_oid;
697 case 2: /* left sort op takes left-side data type */
698 otherLeftTypeName = leftTypeName;
699 otherRightTypeName = leftTypeName;
700 otherLeftTypeId = leftTypeId;
701 otherRightTypeId = leftTypeId;
702 other_oid = OperatorGet(name[j],
707 case 3: /* right sort op takes right-side data type */
708 otherLeftTypeName = rightTypeName;
709 otherRightTypeName = rightTypeName;
710 otherLeftTypeId = rightTypeId;
711 otherRightTypeId = rightTypeId;
712 other_oid = OperatorGet(name[j],
719 if (OidIsValid(other_oid))
721 /* other op already in catalogs */
722 values[i++] = ObjectIdGetDatum(other_oid);
724 else if (strcmp(operatorName, name[j]) != 0 ||
725 otherLeftTypeId != leftTypeId ||
726 otherRightTypeId != rightTypeId)
728 /* not in catalogs, different from operator */
729 other_oid = OperatorShellMake(name[j],
732 if (!OidIsValid(other_oid))
734 "OperatorDef: can't create operator shell '%s'",
736 values[i++] = ObjectIdGetDatum(other_oid);
740 /* self-linkage to this operator; will fix below.
741 * Note that only self-linkage for commutation makes sense.
745 "OperatorDef: operator can't be its own negator or sort op");
746 selfCommutator = true;
747 values[i++] = ObjectIdGetDatum(InvalidOid);
752 /* other operator is omitted */
753 values[i++] = ObjectIdGetDatum(InvalidOid);
757 /* last three fields were filled in above */
760 * If we are adding to an operator shell, get its t_self
762 pg_operator_desc = heap_openr(OperatorRelationName);
764 if (operatorObjectId)
766 opKey[0].sk_argument = PointerGetDatum(operatorName);
767 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
768 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
770 pg_operator_scan = heap_beginscan(pg_operator_desc,
772 SnapshotSelf, /* no cache? */
776 tup = heap_getnext(pg_operator_scan, 0);
777 if (HeapTupleIsValid(tup))
779 tup = heap_modifytuple(tup,
785 setheapoverride(true);
786 heap_replace(pg_operator_desc, &tup->t_self, tup, NULL);
787 setheapoverride(false);
790 elog(ERROR, "OperatorDef: no operator %d", operatorObjectId);
792 heap_endscan(pg_operator_scan);
796 tupDesc = pg_operator_desc->rd_att;
797 tup = heap_formtuple(tupDesc, values, nulls);
799 heap_insert(pg_operator_desc, tup);
800 operatorObjectId = tup->t_data->t_oid;
803 heap_close(pg_operator_desc);
806 * If a commutator and/or negator link is provided, update the other
807 * operator(s) to point at this one, if they don't already have a link.
808 * This supports an alternate style of operator definition wherein the
809 * user first defines one operator without giving negator or
810 * commutator, then defines the other operator of the pair with the
811 * proper commutator or negator attribute. That style doesn't require
812 * creation of a shell, and it's the only style that worked right before
813 * Postgres version 6.5.
814 * This code also takes care of the situation where the new operator
815 * is its own commutator.
818 commutatorId = operatorObjectId;
820 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
821 OperatorUpd(operatorObjectId, commutatorId, negatorId);
824 /* ----------------------------------------------------------------
827 * For a given operator, look up its negator and commutator operators.
828 * If they are defined, but their negator and commutator fields
829 * (respectively) are empty, then use the new operator for neg or comm.
830 * This solves a problem for users who need to insert two new operators
831 * which are the negator or commutator of each other.
832 * ----------------------------------------------------------------
835 OperatorUpd(Oid baseId, Oid commId, Oid negId)
838 Relation pg_operator_desc;
839 HeapScanDesc pg_operator_scan;
841 char nulls[Natts_pg_operator];
842 char replaces[Natts_pg_operator];
843 Datum values[Natts_pg_operator];
845 static ScanKeyData opKey[1] = {
846 {0, ObjectIdAttributeNumber, F_OIDEQ},
849 fmgr_info(F_OIDEQ, &opKey[0].sk_func);
850 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
852 for (i = 0; i < Natts_pg_operator; ++i)
854 values[i] = (Datum) NULL;
859 pg_operator_desc = heap_openr(OperatorRelationName);
861 /* check and update the commutator, if necessary */
862 opKey[0].sk_argument = ObjectIdGetDatum(commId);
864 pg_operator_scan = heap_beginscan(pg_operator_desc,
866 SnapshotSelf, /* no cache? */
870 tup = heap_getnext(pg_operator_scan, 0);
872 /* if the commutator and negator are the same operator, do one update.
873 * XXX this is probably useless code --- I doubt it ever makes sense
874 * for commutator and negator to be the same thing...
878 if (HeapTupleIsValid(tup))
882 t = (Form_pg_operator) GETSTRUCT(tup);
883 if (!OidIsValid(t->oprcom)
884 || !OidIsValid(t->oprnegate))
887 if (!OidIsValid(t->oprnegate))
889 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
890 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
893 if (!OidIsValid(t->oprcom))
895 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
896 replaces[Anum_pg_operator_oprcom - 1] = 'r';
899 tup = heap_modifytuple(tup,
905 setheapoverride(true);
906 heap_replace(pg_operator_desc, &tup->t_self, tup, NULL);
907 setheapoverride(false);
911 heap_endscan(pg_operator_scan);
913 heap_close(pg_operator_desc);
918 /* if commutator and negator are different, do two updates */
920 if (HeapTupleIsValid(tup) &&
921 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
923 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
924 replaces[Anum_pg_operator_oprcom - 1] = 'r';
925 tup = heap_modifytuple(tup,
931 setheapoverride(true);
932 heap_replace(pg_operator_desc, &tup->t_self, tup, NULL);
933 setheapoverride(false);
935 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
936 replaces[Anum_pg_operator_oprcom - 1] = ' ';
939 heap_endscan(pg_operator_scan);
941 /* check and update the negator, if necessary */
942 opKey[0].sk_argument = ObjectIdGetDatum(negId);
944 pg_operator_scan = heap_beginscan(pg_operator_desc,
946 SnapshotSelf, /* no cache? */
950 tup = heap_getnext(pg_operator_scan, 0);
951 if (HeapTupleIsValid(tup) &&
952 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
954 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
955 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
956 tup = heap_modifytuple(tup,
962 setheapoverride(true);
963 heap_replace(pg_operator_desc, &tup->t_self, tup, NULL);
964 setheapoverride(false);
967 heap_endscan(pg_operator_scan);
969 heap_close(pg_operator_desc);
973 /* ----------------------------------------------------------------
976 * This is now just an interface procedure for OperatorDef ...
978 * "X" indicates an optional argument (i.e. one that can be NULL)
979 * operatorName; -- operator name
980 * leftTypeName; -- X left type name
981 * rightTypeName; -- X right type name
982 * procedureName; -- procedure for operator
983 * precedence; -- operator precedence
984 * isLeftAssociative; -- operator is left associative
985 * commutatorName; -- X commutator operator name
986 * negatorName; -- X negator operator name
987 * restrictionName; -- X restriction sel. procedure
988 * joinName; -- X join sel. procedure
989 * canHash; -- hash join can be used with this operator
990 * leftSortName; -- X left sort operator (for merge join)
991 * rightSortName; -- X right sort operator (for merge join)
994 OperatorCreate(char *operatorName,
999 bool isLeftAssociative,
1000 char *commutatorName,
1002 char *restrictionName,
1006 char *rightSortName)
1008 if (!leftTypeName && !rightTypeName)
1009 elog(ERROR, "OperatorCreate: at least one of leftarg or rightarg must be defined");
1011 if (! (leftTypeName && rightTypeName))
1013 /* If it's not a binary op, these things mustn't be set: */
1015 elog(ERROR, "OperatorCreate: only binary operators can have commutators");
1017 elog(ERROR, "OperatorCreate: only binary operators can have negators");
1018 if (restrictionName || joinName)
1019 elog(ERROR, "OperatorCreate: only binary operators can have selectivity");
1021 elog(ERROR, "OperatorCreate: only binary operators can hash");
1022 if (leftSortName || rightSortName)
1023 elog(ERROR, "OperatorCreate: only binary operators can have sort links");
1027 * Use OperatorDef() to define the specified operator and
1028 * also create shells for the operator's associated operators
1029 * if they don't already exist.
1032 OperatorDef(operatorName,