1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_operator relation
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.61 2001/08/10 15:49:39 petere 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 * performs a scan on pg_operator for an operator tuple
73 * with given name and left/right type oids.
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)
80 * ----------------------------------------------------------------
83 OperatorGetWithOpenRelation(Relation pg_operator_desc,
84 const char *operatorName,
89 HeapScanDesc pg_operator_scan;
97 ScanKeyEntryInitialize(&opKey[0], 0x0,
98 Anum_pg_operator_oprname,
100 PointerGetDatum(operatorName));
101 ScanKeyEntryInitialize(&opKey[1], 0x0,
102 Anum_pg_operator_oprleft,
104 ObjectIdGetDatum(leftObjectId));
105 ScanKeyEntryInitialize(&opKey[2], 0x0,
106 Anum_pg_operator_oprright,
108 ObjectIdGetDatum(rightObjectId));
113 pg_operator_scan = heap_beginscan(pg_operator_desc,
115 SnapshotSelf, /* no cache? */
120 * fetch the operator tuple, if it exists, and determine the proper
123 tup = heap_getnext(pg_operator_scan, 0);
125 if (HeapTupleIsValid(tup))
127 regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
129 operatorObjectId = tup->t_data->t_oid;
130 *defined = RegProcedureIsValid(oprcode);
134 operatorObjectId = InvalidOid;
139 * close the scan and return the oid.
141 heap_endscan(pg_operator_scan);
143 return operatorObjectId;
146 /* ----------------------------------------------------------------
149 * finds the operator associated with the specified name
150 * and left and right type names.
151 * ----------------------------------------------------------------
154 OperatorGet(char *operatorName,
159 Relation pg_operator_desc;
161 Oid operatorObjectId;
162 Oid leftObjectId = InvalidOid;
163 Oid rightObjectId = InvalidOid;
164 bool leftDefined = false;
165 bool rightDefined = false;
168 * look up the operator data types.
170 * Note: types must be defined before operators
174 leftObjectId = TypeGet(leftTypeName, &leftDefined);
176 if (!OidIsValid(leftObjectId) || !leftDefined)
177 elog(ERROR, "left type \"%s\" of operator %s does not exist",
178 leftTypeName, operatorName);
183 rightObjectId = TypeGet(rightTypeName, &rightDefined);
185 if (!OidIsValid(rightObjectId) || !rightDefined)
186 elog(ERROR, "right type \"%s\" of operator %s does not exist",
187 rightTypeName, operatorName);
190 if (!((OidIsValid(leftObjectId) && leftDefined) ||
191 (OidIsValid(rightObjectId) && rightDefined)))
192 elog(ERROR, "operator %s must have at least one operand type", operatorName);
195 * open the pg_operator relation
197 pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
200 * get the oid for the operator with the appropriate name and
203 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
210 * close the relation and return the operator oid.
212 heap_close(pg_operator_desc, AccessShareLock);
214 return operatorObjectId;
217 /* ----------------------------------------------------------------
218 * OperatorShellMakeWithOpenRelation
220 * ----------------------------------------------------------------
223 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
230 Datum values[Natts_pg_operator];
231 char nulls[Natts_pg_operator];
232 Oid operatorObjectId;
237 * initialize our *nulls and *values arrays
239 for (i = 0; i < Natts_pg_operator; ++i)
242 values[i] = (Datum) NULL; /* redundant, but safe */
246 * initialize *values with the operator name and input data types.
247 * Note that oprcode is set to InvalidOid, indicating it's a shell.
250 namestrcpy(&oname, operatorName);
251 values[i++] = NameGetDatum(&oname);
252 values[i++] = Int32GetDatum(GetUserId());
253 values[i++] = UInt16GetDatum(0);
254 values[i++] = CharGetDatum('b'); /* assume it's binary */
255 values[i++] = BoolGetDatum(false);
256 values[i++] = BoolGetDatum(false);
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
271 tupDesc = pg_operator_desc->rd_att;
273 tup = heap_formtuple(tupDesc,
278 * insert our "shell" operator tuple and close the relation
280 heap_insert(pg_operator_desc, tup);
281 operatorObjectId = tup->t_data->t_oid;
283 if (RelationGetForm(pg_operator_desc)->relhasindex)
285 Relation idescs[Num_pg_operator_indices];
287 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
288 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
289 CatalogCloseIndices(Num_pg_operator_indices, idescs);
293 * free the tuple and return the operator oid
297 return operatorObjectId;
300 /* ----------------------------------------------------------------
303 * Specify operator name and left and right type names,
304 * fill an operator struct with this info and NULL's,
305 * call heap_insert and return the Oid
307 * ----------------------------------------------------------------
310 OperatorShellMake(char *operatorName,
314 Relation pg_operator_desc;
315 Oid operatorObjectId;
317 Oid leftObjectId = InvalidOid;
318 Oid rightObjectId = InvalidOid;
319 bool leftDefined = false;
320 bool rightDefined = false;
323 * get the left and right type oid's for this operator
326 leftObjectId = TypeGet(leftTypeName, &leftDefined);
329 rightObjectId = TypeGet(rightTypeName, &rightDefined);
331 if (!((OidIsValid(leftObjectId) && leftDefined) ||
332 (OidIsValid(rightObjectId) && rightDefined)))
333 elog(ERROR, "OperatorShellMake: the operand types are not valid");
338 pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
341 * add a "shell" operator tuple to the operator relation and recover
342 * the shell tuple's oid.
344 operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
350 * close the operator relation and return the oid.
352 heap_close(pg_operator_desc, RowExclusiveLock);
354 return operatorObjectId;
357 /* --------------------------------
360 * This routine gets complicated because it allows the user to
361 * specify operators that do not exist. For example, if operator
362 * "op" is being defined, the negator operator "negop" and the
363 * commutator "commop" can also be defined without specifying
364 * any information other than their names. Since in order to
365 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
366 * operators must be placed in the fields of "op", a forward
367 * declaration is done on the commutator and negator operators.
368 * This is called creating a shell, and its main effect is to
369 * create a tuple in the PG_OPERATOR catalog with minimal
370 * information about the operator (just its name and types).
371 * Forward declaration is used only for this purpose, it is
372 * not available to the user as it is for type definition.
376 * check if operator already defined
377 * if so, but oprcode is null, save the Oid -- we are filling in a shell
379 * get the attribute types from relation descriptor for pg_operator
380 * assign values to the fields of the operator:
382 * owner id (simply the user id of the caller)
384 * operator "kind" either "b" for binary or "l" for left unary
385 * isLeftAssociative boolean
387 * leftTypeObjectId -- type must already be defined
388 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
389 * resultType -- defer this, since it must be determined from
390 * the pg_procedure catalog
391 * commutatorObjectId -- if this is NULL, enter ObjectId=0
392 * else if this already exists, enter its ObjectId
393 * else if this does not yet exist, and is not
394 * the same as the main operatorName, then create
395 * a shell and enter the new ObjectId
396 * else if this does not exist but IS the same
397 * name & types as the main operator, set the ObjectId=0.
398 * (We are creating a self-commutating operator.)
399 * The link will be fixed later by OperatorUpd.
400 * negatorObjectId -- same as for commutatorObjectId
401 * leftSortObjectId -- same as for commutatorObjectId
402 * rightSortObjectId -- same as for commutatorObjectId
403 * operatorProcedure -- must access the pg_procedure catalog to get the
404 * ObjectId of the procedure that actually does the operator
405 * actions this is required. Do a lookup to find out the
406 * return type of the procedure
407 * restrictionProcedure -- must access the pg_procedure catalog to get
408 * the ObjectId but this is optional
409 * joinProcedure -- same as restrictionProcedure
410 * now either insert or replace the operator into the pg_operator catalog
411 * if the operator shell is being filled in
412 * access the catalog in order to get a valid buffer
413 * create a tuple using ModifyHeapTuple
414 * get the t_self from the modified tuple and call RelationReplaceHeapTuple
415 * else if a new operator is being created
416 * create a tuple using heap_formtuple
418 * --------------------------------
419 * "X" indicates an optional argument (i.e. one that can be NULL)
420 * operatorName; -- operator name
421 * leftTypeName; -- X left type name
422 * rightTypeName; -- X right type name
423 * procedureName; -- procedure name for operator code
424 * precedence; -- operator precedence
425 * isLeftAssociative; -- operator is left associative?
426 * commutatorName; -- X commutator operator name
427 * negatorName; -- X negator operator name
428 * restrictionName; -- X restriction sel. procedure name
429 * joinName; -- X join sel. procedure name
430 * canHash; -- can hash join be used with operator?
431 * leftSortName; -- X left sort operator (for merge join)
432 * rightSortName; -- X right sort operator (for merge join)
435 OperatorDef(char *operatorName,
440 bool isLeftAssociative,
441 char *commutatorName,
443 char *restrictionName,
451 Relation pg_operator_desc;
452 HeapScanDesc pg_operator_scan;
454 char nulls[Natts_pg_operator];
455 char replaces[Natts_pg_operator];
456 Datum values[Natts_pg_operator];
457 Oid operatorObjectId;
458 bool operatorAlreadyDefined;
459 Oid leftTypeId = InvalidOid;
460 Oid rightTypeId = InvalidOid;
461 Oid commutatorId = InvalidOid;
462 Oid negatorId = InvalidOid;
463 bool leftDefined = false;
464 bool rightDefined = false;
465 bool selfCommutator = false;
467 Oid typeId[FUNC_MAX_ARGS];
471 ScanKeyData opKey[3];
473 operatorObjectId = OperatorGet(operatorName,
476 &operatorAlreadyDefined);
478 if (operatorAlreadyDefined)
479 elog(ERROR, "OperatorDef: operator \"%s\" already defined",
483 * At this point, if operatorObjectId is not InvalidOid then we are
484 * filling in a previously-created shell.
488 * look up the operator data types.
490 * Note: types must be defined before operators
494 leftTypeId = TypeGet(leftTypeName, &leftDefined);
496 if (!OidIsValid(leftTypeId) || !leftDefined)
497 elog(ERROR, "left type \"%s\" does not exist",
503 rightTypeId = TypeGet(rightTypeName, &rightDefined);
505 if (!OidIsValid(rightTypeId) || !rightDefined)
506 elog(ERROR, "right type \"%s\" does not exist",
510 if (!((OidIsValid(leftTypeId) && leftDefined) ||
511 (OidIsValid(rightTypeId) && rightDefined)))
512 elog(ERROR, "operator must have at least one operand type");
514 for (i = 0; i < Natts_pg_operator; ++i)
516 values[i] = (Datum) NULL;
522 * Look up registered procedures -- find the return type of
523 * procedureName to place in "result" field. Do this before shells are
524 * created so we don't have to worry about deleting them later.
526 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
529 typeId[0] = rightTypeId;
532 else if (!rightTypeName)
534 typeId[0] = leftTypeId;
539 typeId[0] = leftTypeId;
540 typeId[1] = rightTypeId;
543 tup = SearchSysCache(PROCNAME,
544 PointerGetDatum(procedureName),
545 Int32GetDatum(nargs),
546 PointerGetDatum(typeId),
548 if (!HeapTupleIsValid(tup))
549 func_error("OperatorDef", procedureName, nargs, typeId, NULL);
551 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
552 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
553 GETSTRUCT(tup))->prorettype);
555 ReleaseSysCache(tup);
558 * find restriction estimator
564 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
565 typeId[0] = 0; /* Query (opaque type) */
566 typeId[1] = OIDOID; /* operator OID */
567 typeId[2] = 0; /* args list (opaque type) */
568 typeId[3] = INT4OID; /* varRelid */
570 restOid = GetSysCacheOid(PROCNAME,
571 PointerGetDatum(restrictionName),
573 PointerGetDatum(typeId),
575 if (!OidIsValid(restOid))
576 func_error("OperatorDef", restrictionName, 4, typeId, NULL);
578 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
581 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
584 * find join estimator
590 MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
591 typeId[0] = 0; /* Query (opaque type) */
592 typeId[1] = OIDOID; /* operator OID */
593 typeId[2] = 0; /* args list (opaque type) */
595 joinOid = GetSysCacheOid(PROCNAME,
596 PointerGetDatum(joinName),
598 PointerGetDatum(typeId),
600 if (!OidIsValid(joinOid))
601 func_error("OperatorDef", joinName, 3, typeId, NULL);
603 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
606 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
609 * set up values in the operator tuple
612 namestrcpy(&oname, operatorName);
613 values[i++] = NameGetDatum(&oname);
614 values[i++] = Int32GetDatum(GetUserId());
615 values[i++] = UInt16GetDatum(precedence);
616 values[i++] = CharGetDatum(leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l');
617 values[i++] = BoolGetDatum(isLeftAssociative);
618 values[i++] = BoolGetDatum(canHash);
619 values[i++] = ObjectIdGetDatum(leftTypeId);
620 values[i++] = ObjectIdGetDatum(rightTypeId);
622 ++i; /* Skip "oprresult", it was filled in
626 * Set up the other operators. If they do not currently exist, create
627 * shells in order to get ObjectId's.
629 name[0] = commutatorName;
630 name[1] = negatorName;
631 name[2] = leftSortName;
632 name[3] = rightSortName;
634 for (j = 0; j < 4; ++j)
638 char *otherLeftTypeName = NULL;
639 char *otherRightTypeName = NULL;
640 Oid otherLeftTypeId = InvalidOid;
641 Oid otherRightTypeId = InvalidOid;
642 Oid other_oid = InvalidOid;
643 bool otherDefined = false;
647 case 0: /* commutator has reversed arg types */
648 otherLeftTypeName = rightTypeName;
649 otherRightTypeName = leftTypeName;
650 otherLeftTypeId = rightTypeId;
651 otherRightTypeId = leftTypeId;
652 other_oid = OperatorGet(name[j],
656 commutatorId = other_oid;
658 case 1: /* negator has same arg types */
659 otherLeftTypeName = leftTypeName;
660 otherRightTypeName = rightTypeName;
661 otherLeftTypeId = leftTypeId;
662 otherRightTypeId = rightTypeId;
663 other_oid = OperatorGet(name[j],
667 negatorId = other_oid;
669 case 2: /* left sort op takes left-side data type */
670 otherLeftTypeName = leftTypeName;
671 otherRightTypeName = leftTypeName;
672 otherLeftTypeId = leftTypeId;
673 otherRightTypeId = leftTypeId;
674 other_oid = OperatorGet(name[j],
679 case 3: /* right sort op takes right-side data
681 otherLeftTypeName = rightTypeName;
682 otherRightTypeName = rightTypeName;
683 otherLeftTypeId = rightTypeId;
684 otherRightTypeId = rightTypeId;
685 other_oid = OperatorGet(name[j],
692 if (OidIsValid(other_oid))
694 /* other op already in catalogs */
695 values[i++] = ObjectIdGetDatum(other_oid);
697 else if (strcmp(operatorName, name[j]) != 0 ||
698 otherLeftTypeId != leftTypeId ||
699 otherRightTypeId != rightTypeId)
701 /* not in catalogs, different from operator */
702 other_oid = OperatorShellMake(name[j],
705 if (!OidIsValid(other_oid))
707 "OperatorDef: can't create operator shell \"%s\"",
709 values[i++] = ObjectIdGetDatum(other_oid);
715 * self-linkage to this operator; will fix below. Note
716 * that only self-linkage for commutation makes sense.
720 "operator cannot be its own negator or sort operator");
721 selfCommutator = true;
722 values[i++] = ObjectIdGetDatum(InvalidOid);
727 /* other operator is omitted */
728 values[i++] = ObjectIdGetDatum(InvalidOid);
732 /* last three fields were filled in above */
734 pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
737 * If we are adding to an operator shell, get its t_self
739 if (operatorObjectId)
741 /* Make sure we can see the shell even if it is new in current cmd */
742 CommandCounterIncrement();
744 ScanKeyEntryInitialize(&opKey[0], 0x0,
745 Anum_pg_operator_oprname,
747 PointerGetDatum(operatorName));
748 ScanKeyEntryInitialize(&opKey[1], 0x0,
749 Anum_pg_operator_oprleft,
751 ObjectIdGetDatum(leftTypeId));
752 ScanKeyEntryInitialize(&opKey[2], 0x0,
753 Anum_pg_operator_oprright,
755 ObjectIdGetDatum(rightTypeId));
757 pg_operator_scan = heap_beginscan(pg_operator_desc,
759 SnapshotSelf, /* no cache? */
763 tup = heap_getnext(pg_operator_scan, 0);
764 if (HeapTupleIsValid(tup))
766 tup = heap_modifytuple(tup,
772 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
775 elog(ERROR, "OperatorDef: operator %u not found", operatorObjectId);
777 heap_endscan(pg_operator_scan);
781 tupDesc = pg_operator_desc->rd_att;
782 tup = heap_formtuple(tupDesc, values, nulls);
784 heap_insert(pg_operator_desc, tup);
785 operatorObjectId = tup->t_data->t_oid;
788 if (RelationGetForm(pg_operator_desc)->relhasindex)
790 Relation idescs[Num_pg_operator_indices];
792 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
793 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
794 CatalogCloseIndices(Num_pg_operator_indices, idescs);
797 heap_close(pg_operator_desc, RowExclusiveLock);
800 * If a commutator and/or negator link is provided, update the other
801 * operator(s) to point at this one, if they don't already have a
802 * link. This supports an alternate style of operator definition
803 * wherein the user first defines one operator without giving negator
804 * or commutator, then defines the other operator of the pair with the
805 * proper commutator or negator attribute. That style doesn't require
806 * creation of a shell, and it's the only style that worked right
807 * before Postgres version 6.5. This code also takes care of the
808 * situation where the new operator is its own commutator.
811 commutatorId = operatorObjectId;
813 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
814 OperatorUpd(operatorObjectId, commutatorId, negatorId);
817 /* ----------------------------------------------------------------
820 * For a given operator, look up its negator and commutator operators.
821 * If they are defined, but their negator and commutator fields
822 * (respectively) are empty, then use the new operator for neg or comm.
823 * This solves a problem for users who need to insert two new operators
824 * which are the negator or commutator of each other.
825 * ----------------------------------------------------------------
828 OperatorUpd(Oid baseId, Oid commId, Oid negId)
831 Relation pg_operator_desc;
832 HeapScanDesc pg_operator_scan;
834 char nulls[Natts_pg_operator];
835 char replaces[Natts_pg_operator];
836 Datum values[Natts_pg_operator];
837 ScanKeyData opKey[1];
839 for (i = 0; i < Natts_pg_operator; ++i)
841 values[i] = (Datum) 0;
846 pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
849 * check and update the commutator & negator, if necessary
851 * First make sure we can see them...
853 CommandCounterIncrement();
855 ScanKeyEntryInitialize(&opKey[0], 0x0,
856 ObjectIdAttributeNumber,
858 ObjectIdGetDatum(commId));
860 pg_operator_scan = heap_beginscan(pg_operator_desc,
862 SnapshotSelf, /* no cache? */
866 tup = heap_getnext(pg_operator_scan, 0);
869 * if the commutator and negator are the same operator, do one update.
870 * XXX this is probably useless code --- I doubt it ever makes sense
871 * for commutator and negator to be the same thing...
875 if (HeapTupleIsValid(tup))
879 t = (Form_pg_operator) GETSTRUCT(tup);
880 if (!OidIsValid(t->oprcom)
881 || !OidIsValid(t->oprnegate))
884 if (!OidIsValid(t->oprnegate))
886 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
887 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
890 if (!OidIsValid(t->oprcom))
892 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
893 replaces[Anum_pg_operator_oprcom - 1] = 'r';
896 tup = heap_modifytuple(tup,
902 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
904 if (RelationGetForm(pg_operator_desc)->relhasindex)
906 Relation idescs[Num_pg_operator_indices];
908 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
909 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
910 CatalogCloseIndices(Num_pg_operator_indices, idescs);
914 heap_endscan(pg_operator_scan);
916 heap_close(pg_operator_desc, RowExclusiveLock);
921 /* if commutator and negator are different, do two updates */
923 if (HeapTupleIsValid(tup) &&
924 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
926 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
927 replaces[Anum_pg_operator_oprcom - 1] = 'r';
928 tup = heap_modifytuple(tup,
934 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
936 if (RelationGetForm(pg_operator_desc)->relhasindex)
938 Relation idescs[Num_pg_operator_indices];
940 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
941 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
942 CatalogCloseIndices(Num_pg_operator_indices, idescs);
945 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
946 replaces[Anum_pg_operator_oprcom - 1] = ' ';
949 heap_endscan(pg_operator_scan);
951 /* check and update the negator, if necessary */
952 opKey[0].sk_argument = ObjectIdGetDatum(negId);
954 pg_operator_scan = heap_beginscan(pg_operator_desc,
956 SnapshotSelf, /* no cache? */
960 tup = heap_getnext(pg_operator_scan, 0);
961 if (HeapTupleIsValid(tup) &&
962 !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
964 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
965 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
966 tup = heap_modifytuple(tup,
972 simple_heap_update(pg_operator_desc, &tup->t_self, tup);
974 if (RelationGetForm(pg_operator_desc)->relhasindex)
976 Relation idescs[Num_pg_operator_indices];
978 CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
979 CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
980 CatalogCloseIndices(Num_pg_operator_indices, idescs);
984 heap_endscan(pg_operator_scan);
986 heap_close(pg_operator_desc, RowExclusiveLock);
990 /* ----------------------------------------------------------------
993 * This is now just an interface procedure for OperatorDef ...
995 * "X" indicates an optional argument (i.e. one that can be NULL)
996 * operatorName; -- operator name
997 * leftTypeName; -- X left type name
998 * rightTypeName; -- X right type name
999 * procedureName; -- procedure for operator
1000 * precedence; -- operator precedence
1001 * isLeftAssociative; -- operator is left associative
1002 * commutatorName; -- X commutator operator name
1003 * negatorName; -- X negator operator name
1004 * restrictionName; -- X restriction sel. procedure
1005 * joinName; -- X join sel. procedure
1006 * canHash; -- hash join can be used with this operator
1007 * leftSortName; -- X left sort operator (for merge join)
1008 * rightSortName; -- X right sort operator (for merge join)
1011 OperatorCreate(char *operatorName,
1013 char *rightTypeName,
1014 char *procedureName,
1016 bool isLeftAssociative,
1017 char *commutatorName,
1019 char *restrictionName,
1023 char *rightSortName)
1025 if (!leftTypeName && !rightTypeName)
1026 elog(ERROR, "at least one of leftarg or rightarg must be specified");
1028 if (!(leftTypeName && rightTypeName))
1030 /* If it's not a binary op, these things mustn't be set: */
1032 elog(ERROR, "only binary operators can have commutators");
1034 elog(ERROR, "only binary operators can have join selectivity");
1036 elog(ERROR, "only binary operators can hash");
1037 if (leftSortName || rightSortName)
1038 elog(ERROR, "only binary operators can have sort links");
1042 * Use OperatorDef() to define the specified operator and also create
1043 * shells for the operator's associated operators if they don't
1046 OperatorDef(operatorName,