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.25 1998/05/09 23:43:00 thomas 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>
39 OperatorGetWithOpenRelation(Relation pg_operator_desc,
40 const char *operatorName,
44 OperatorGet(char *operatorName,
49 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
54 OperatorShellMake(char *operatorName,
59 OperatorDef(char *operatorName,
65 bool isLeftAssociative,
68 char *restrictionName,
73 static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
75 /* ----------------------------------------------------------------
76 * OperatorGetWithOpenRelation
78 * preforms a scan on pg_operator for an operator tuple
79 * with given name and left/right type oids.
80 * ----------------------------------------------------------------
81 * pg_operator_desc -- reldesc for pg_operator
82 * operatorName -- name of operator to fetch
83 * leftObjectId -- left oid of operator to fetch
84 * rightObjectId -- right oid of operator to fetch
87 OperatorGetWithOpenRelation(Relation pg_operator_desc,
88 const char *operatorName,
92 HeapScanDesc pg_operator_scan;
96 static ScanKeyData opKey[3] = {
97 {0, Anum_pg_operator_oprname, F_NAMEEQ},
98 {0, Anum_pg_operator_oprleft, F_OIDEQ},
99 {0, Anum_pg_operator_oprright, F_OIDEQ},
102 fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
103 fmgr_info(F_OIDEQ, &opKey[1].sk_func);
104 fmgr_info(F_OIDEQ, &opKey[2].sk_func);
105 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
106 opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
107 opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
113 opKey[0].sk_argument = PointerGetDatum(operatorName);
114 opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
115 opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
121 pg_operator_scan = heap_beginscan(pg_operator_desc,
128 * fetch the operator tuple, if it exists, and determine
129 * the proper return oid value.
132 tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
133 operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
136 * close the scan and return the oid.
139 heap_endscan(pg_operator_scan);
145 /* ----------------------------------------------------------------
148 * finds the operator associated with the specified name
149 * and left and right type names.
150 * ----------------------------------------------------------------
153 OperatorGet(char *operatorName,
157 Relation pg_operator_desc;
159 Oid operatorObjectId;
160 Oid leftObjectId = InvalidOid;
161 Oid rightObjectId = InvalidOid;
162 bool leftDefined = false;
163 bool rightDefined = false;
166 * look up the operator types.
168 * Note: types must be defined before operators
173 leftObjectId = TypeGet(leftTypeName, &leftDefined);
175 if (!OidIsValid(leftObjectId) || !leftDefined)
176 elog(ERROR, "OperatorGet: left type '%s' nonexistent", leftTypeName);
181 rightObjectId = TypeGet(rightTypeName, &rightDefined);
183 if (!OidIsValid(rightObjectId) || !rightDefined)
184 elog(ERROR, "OperatorGet: right type '%s' nonexistent",
188 if (!((OidIsValid(leftObjectId) && leftDefined) ||
189 (OidIsValid(rightObjectId) && rightDefined)))
190 elog(ERROR, "OperatorGet: no argument types??");
193 * open the pg_operator relation
196 pg_operator_desc = heap_openr(OperatorRelationName);
199 * get the oid for the operator with the appropriate name
200 * and left/right types.
203 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
209 * close the relation and return the operator oid.
212 heap_close(pg_operator_desc);
218 /* ----------------------------------------------------------------
219 * OperatorShellMakeWithOpenRelation
221 * ----------------------------------------------------------------
224 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
231 Datum values[Natts_pg_operator];
232 char nulls[Natts_pg_operator];
233 Oid operatorObjectId;
238 * initialize our nulls[] and values[] arrays
241 for (i = 0; i < Natts_pg_operator; ++i)
244 values[i] = (Datum) NULL; /* redundant, but safe */
248 * initialize values[] with the type name and
252 namestrcpy(&oname, operatorName);
253 values[i++] = NameGetDatum(&oname);
254 values[i++] = Int32GetDatum(GetUserId());
255 values[i++] = (Datum) (uint16) 0;
257 values[i++] = (Datum) 'b'; /* fill oprkind with a bogus value */
259 values[i++] = (Datum) (bool) 0;
260 values[i++] = (Datum) (bool) 0;
261 values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
262 values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
263 values[i++] = ObjectIdGetDatum(InvalidOid);
264 values[i++] = ObjectIdGetDatum(InvalidOid);
265 values[i++] = ObjectIdGetDatum(InvalidOid);
266 values[i++] = ObjectIdGetDatum(InvalidOid);
267 values[i++] = ObjectIdGetDatum(InvalidOid);
268 values[i++] = ObjectIdGetDatum(InvalidOid);
269 values[i++] = ObjectIdGetDatum(InvalidOid);
270 values[i++] = ObjectIdGetDatum(InvalidOid);
273 * create a new operator tuple
276 tupDesc = pg_operator_desc->rd_att;
278 tup = heap_formtuple(tupDesc,
283 * insert our "shell" operator tuple and
287 heap_insert(pg_operator_desc, tup);
288 operatorObjectId = tup->t_oid;
291 * free the tuple and return the operator oid
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
327 leftObjectId = TypeGet(leftTypeName, &leftDefined);
330 rightObjectId = TypeGet(rightTypeName, &rightDefined);
332 if (!((OidIsValid(leftObjectId) && leftDefined) ||
333 (OidIsValid(rightObjectId) && rightDefined)))
334 elog(ERROR, "OperatorShellMake: no valid argument types??");
340 pg_operator_desc = heap_openr(OperatorRelationName);
343 * add a "shell" operator tuple to the operator relation
344 * and recover the shell tuple's oid.
348 OperatorShellMakeWithOpenRelation(pg_operator_desc,
353 * close the operator relation and return the oid.
356 heap_close(pg_operator_desc);
362 /* --------------------------------
365 * This routine gets complicated because it allows the user to
366 * specify operators that do not exist. For example, if operator
367 * "op" is being defined, the negator operator "negop" and the
368 * commutator "commop" can also be defined without specifying
369 * any information other than their names. Since in order to
370 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
371 * operators must be placed in the fields of "op", a forward
372 * declaration is done on the commutator and negator operators.
373 * This is called creating a shell, and its main effect is to
374 * create a tuple in the PG_OPERATOR catalog with minimal
375 * information about the operator (just its name and types).
376 * Forward declaration is used only for this purpose, it is
377 * not available to the user as it is for type definition.
381 * check if operator already defined
382 * if so issue error if not definedOk, this is a duplicate
383 * but if definedOk, save the Oid -- filling in a shell
384 * get the attribute types from relation descriptor for pg_operator
385 * assign values to the fields of the operator:
387 * owner id (simply the user id of the caller)
389 * operator "kind" either "b" for binary or "l" for left unary
390 * isLeftAssociative boolean
392 * leftTypeObjectId -- type must already be defined
393 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
394 * resultType -- defer this, since it must be determined from
395 * the pg_procedure catalog
396 * commutatorObjectId -- if this is NULL, enter ObjectId=0
397 * else if this already exists, enter it's ObjectId
398 * else if this does not yet exist, and is not
399 * the same as the main operatorName, then create
400 * a shell and enter the new ObjectId
401 * else if this does not exist but IS the same
402 * name as the main operator, set the ObjectId=0.
403 * Later OperatorCreate will make another call
404 * to OperatorDef which will cause this field
405 * to be filled in (because even though the names
406 * will be switched, they are the same name and
407 * at this point this ObjectId will then be defined)
408 * negatorObjectId -- same as for commutatorObjectId
409 * leftSortObjectId -- same as for commutatorObjectId
410 * rightSortObjectId -- same as for commutatorObjectId
411 * operatorProcedure -- must access the pg_procedure catalog to get the
412 * ObjectId of the procedure that actually does the operator
413 * actions this is required. Do an amgetattr to find out the
414 * return type of the procedure
415 * restrictionProcedure -- must access the pg_procedure catalog to get
416 * the ObjectId but this is optional
417 * joinProcedure -- same as restrictionProcedure
418 * now either insert or replace the operator into the pg_operator catalog
419 * if the operator shell is being filled in
420 * access the catalog in order to get a valid buffer
421 * create a tuple using ModifyHeapTuple
422 * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple
423 * else if a new operator is being created
424 * create a tuple using heap_formtuple
426 * --------------------------------
427 * "X" indicates an optional argument (i.e. one that can be NULL)
428 * operatorName; -- operator name
429 * definedOK; -- operator can already have an oid?
430 * leftTypeName; -- X left type name
431 * rightTypeName; -- X right type name
432 * procedureName; -- procedure oid for operator code
433 * precedence; -- operator precedence
434 * isLeftAssociative; -- operator is left associative?
435 * commutatorName; -- X commutator operator name
436 * negatorName; -- X negator operator name
437 * restrictionName; -- X restriction sel. procedure name
438 * joinName; -- X join sel. procedure name
439 * canHash; -- possible hash operator?
440 * leftSortName; -- X left sort operator
441 * rightSortName; -- X right sort operator
444 OperatorDef(char *operatorName,
450 bool isLeftAssociative,
451 char *commutatorName,
453 char *restrictionName,
461 Relation pg_operator_desc;
463 HeapScanDesc pg_operator_scan;
466 ItemPointerData itemPointerData;
467 char nulls[Natts_pg_operator];
468 char replaces[Natts_pg_operator];
469 Datum values[Natts_pg_operator];
471 Oid operatorObjectId;
472 Oid leftTypeId = InvalidOid;
473 Oid rightTypeId = InvalidOid;
474 Oid commutatorId = InvalidOid;
475 Oid negatorId = InvalidOid;
476 bool leftDefined = false;
477 bool rightDefined = false;
484 static ScanKeyData opKey[3] = {
485 {0, Anum_pg_operator_oprname, F_NAMEEQ},
486 {0, Anum_pg_operator_oprleft, F_OIDEQ},
487 {0, Anum_pg_operator_oprright, F_OIDEQ},
490 fmgr_info(F_NAMEEQ, &opKey[0].sk_func);
491 fmgr_info(F_OIDEQ, &opKey[1].sk_func);
492 fmgr_info(F_OIDEQ, &opKey[2].sk_func);
493 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
494 opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
495 opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
497 operatorObjectId = OperatorGet(operatorName,
501 if (OidIsValid(operatorObjectId) && !definedOK)
502 elog(ERROR, "OperatorDef: operator \"%s\" already defined",
506 leftTypeId = TypeGet(leftTypeName, &leftDefined);
509 rightTypeId = TypeGet(rightTypeName, &rightDefined);
511 if (!((OidIsValid(leftTypeId && leftDefined)) ||
512 (OidIsValid(rightTypeId && rightDefined))))
513 elog(ERROR, "OperatorGet: no argument types??");
515 for (i = 0; i < Natts_pg_operator; ++i)
517 values[i] = (Datum) NULL;
523 * Look up registered procedures -- find the return type
524 * of procedureName to place in "result" field.
525 * Do this before shells are created so we don't
526 * have to worry about deleting them later.
529 MemSet(typeId, 0, 8 * sizeof(Oid));
532 typeId[0] = rightTypeId;
535 else if (!rightTypeName)
537 typeId[0] = leftTypeId;
542 typeId[0] = leftTypeId;
543 typeId[1] = rightTypeId;
546 tup = SearchSysCacheTuple(PRONAME,
547 PointerGetDatum(procedureName),
548 Int32GetDatum(nargs),
549 PointerGetDatum(typeId),
552 if (!PointerIsValid(tup))
553 func_error("OperatorDef", procedureName, nargs, typeId, NULL);
555 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_oid);
556 values[Anum_pg_operator_oprresult - 1] =
557 ObjectIdGetDatum(((Form_pg_proc)
558 GETSTRUCT(tup))->prorettype);
566 MemSet(typeId, 0, 8 * sizeof(Oid));
567 typeId[0] = OIDOID; /* operator OID */
568 typeId[1] = OIDOID; /* relation OID */
569 typeId[2] = INT2OID; /* attribute number */
570 typeId[3] = 0; /* value - can be any type */
571 typeId[4] = INT4OID; /* flags - left or right selectivity */
572 tup = SearchSysCacheTuple(PRONAME,
573 PointerGetDatum(restrictionName),
575 PointerGetDatum(typeId),
577 if (!HeapTupleIsValid(tup))
578 func_error("OperatorDef", restrictionName, 5, typeId, NULL);
580 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_oid);
583 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
586 * find join - only valid for binary operators
591 MemSet(typeId, 0, 8 * sizeof(Oid));
592 typeId[0] = OIDOID; /* operator OID */
593 typeId[1] = OIDOID; /* relation OID 1 */
594 typeId[2] = INT2OID; /* attribute number 1 */
595 typeId[3] = OIDOID; /* relation OID 2 */
596 typeId[4] = INT2OID; /* attribute number 2 */
598 tup = SearchSysCacheTuple(PRONAME,
599 PointerGetDatum(joinName),
601 PointerGetDatum(typeId),
603 if (!HeapTupleIsValid(tup))
604 func_error("OperatorDef", joinName, 5, typeId, NULL);
606 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_oid);
609 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
612 * set up values in the operator tuple
616 namestrcpy(&oname, operatorName);
617 values[i++] = NameGetDatum(&oname);
618 values[i++] = Int32GetDatum(GetUserId());
619 values[i++] = UInt16GetDatum(precedence);
620 values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
621 values[i++] = Int8GetDatum(isLeftAssociative);
622 values[i++] = Int8GetDatum(canHash);
623 values[i++] = ObjectIdGetDatum(leftTypeId);
624 values[i++] = ObjectIdGetDatum(rightTypeId);
626 ++i; /* Skip "prorettype", this was done above */
629 * Set up the other operators. If they do not currently exist, set up
630 * shells in order to get ObjectId's and call OperatorDef again later
631 * to fill in the shells.
633 name[0] = commutatorName;
634 name[1] = negatorName;
635 name[2] = leftSortName;
636 name[3] = rightSortName;
638 for (j = 0; j < 4; ++j)
643 /* for the commutator, switch order of arguments */
646 other_oid = OperatorGet(name[j], rightTypeName, leftTypeName);
647 commutatorId = other_oid;
651 other_oid = OperatorGet(name[j], leftTypeName, rightTypeName);
653 negatorId = other_oid;
656 if (OidIsValid(other_oid)) /* already in catalogs */
657 values[i++] = ObjectIdGetDatum(other_oid);
658 else if (strcmp(operatorName, name[j]) != 0)
660 /* not in catalogs, different from operator */
662 /* for the commutator, switch order of arguments */
665 other_oid = OperatorShellMake(name[j],
671 other_oid = OperatorShellMake(name[j],
676 if (!OidIsValid(other_oid))
678 "OperatorDef: can't create operator '%s'",
680 values[i++] = ObjectIdGetDatum(other_oid);
684 /* not in catalogs, same as operator ??? */
685 values[i++] = ObjectIdGetDatum(InvalidOid);
689 /* new operator is optional */
690 values[i++] = ObjectIdGetDatum(InvalidOid);
693 /* last three fields were filled in first */
696 * If we are adding to an operator shell, get its t_ctid and a buffer.
698 pg_operator_desc = heap_openr(OperatorRelationName);
700 if (operatorObjectId)
702 opKey[0].sk_argument = PointerGetDatum(operatorName);
703 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
704 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
706 pg_operator_scan = heap_beginscan(pg_operator_desc,
712 tup = heap_getnext(pg_operator_scan, 0, &buffer);
713 if (HeapTupleIsValid(tup))
715 tup = heap_modifytuple(tup,
722 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
723 setheapoverride(true);
724 heap_replace(pg_operator_desc, &itemPointerData, tup);
725 setheapoverride(false);
728 elog(ERROR, "OperatorDef: no operator %d", other_oid);
730 heap_endscan(pg_operator_scan);
735 tupDesc = pg_operator_desc->rd_att;
736 tup = heap_formtuple(tupDesc, values, nulls);
738 heap_insert(pg_operator_desc, tup);
739 operatorObjectId = tup->t_oid;
742 heap_close(pg_operator_desc);
745 * It's possible that we're creating a skeleton operator here for the
746 * commute or negate attributes of a real operator. If we are, then
747 * we're done. If not, we may need to update the negator and
748 * commutator for this attribute. The reason for this is that the
749 * user may want to create two operators (say < and >=). When he
750 * defines <, if he uses >= as the negator or commutator, he won't be
751 * able to insert it later, since (for some reason) define operator
752 * defines it for him. So what he does is to define > without a
753 * negator or commutator. Then he defines >= with < as the negator
754 * and commutator. As a side effect, this will update the > tuple if
755 * it has no commutator or negator defined.
757 * Alstublieft, Tom Vijlbrief.
760 OperatorUpd(operatorObjectId, commutatorId, negatorId);
763 /* ----------------------------------------------------------------
766 * For a given operator, look up its negator and commutator operators.
767 * If they are defined, but their negator and commutator operators
768 * (respectively) are not, then use the new operator for neg and comm.
769 * This solves a problem for users who need to insert two new operators
770 * which are the negator or commutator of each other.
771 * ----------------------------------------------------------------
774 OperatorUpd(Oid baseId, Oid commId, Oid negId)
777 Relation pg_operator_desc;
778 HeapScanDesc pg_operator_scan;
781 ItemPointerData itemPointerData;
782 char nulls[Natts_pg_operator];
783 char replaces[Natts_pg_operator];
784 Datum values[Natts_pg_operator];
786 static ScanKeyData opKey[1] = {
787 {0, ObjectIdAttributeNumber, F_OIDEQ},
790 fmgr_info(F_OIDEQ, &opKey[0].sk_func);
791 opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs;
793 for (i = 0; i < Natts_pg_operator; ++i)
795 values[i] = (Datum) NULL;
800 pg_operator_desc = heap_openr(OperatorRelationName);
802 /* check and update the commutator, if necessary */
803 opKey[0].sk_argument = ObjectIdGetDatum(commId);
805 pg_operator_scan = heap_beginscan(pg_operator_desc,
811 tup = heap_getnext(pg_operator_scan, 0, &buffer);
813 /* if the commutator and negator are the same operator, do one update */
816 if (HeapTupleIsValid(tup))
820 t = (OperatorTupleForm) GETSTRUCT(tup);
821 if (!OidIsValid(t->oprcom)
822 || !OidIsValid(t->oprnegate))
825 if (!OidIsValid(t->oprnegate))
827 values[Anum_pg_operator_oprnegate - 1] =
828 ObjectIdGetDatum(baseId);
829 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
832 if (!OidIsValid(t->oprcom))
834 values[Anum_pg_operator_oprcom - 1] =
835 ObjectIdGetDatum(baseId);
836 replaces[Anum_pg_operator_oprcom - 1] = 'r';
839 tup = heap_modifytuple(tup,
846 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
848 setheapoverride(true);
849 heap_replace(pg_operator_desc, &itemPointerData, tup);
850 setheapoverride(false);
854 heap_endscan(pg_operator_scan);
856 heap_close(pg_operator_desc);
858 /* release the buffer properly */
859 if (BufferIsValid(buffer))
860 ReleaseBuffer(buffer);
865 /* if commutator and negator are different, do two updates */
866 if (HeapTupleIsValid(tup) &&
867 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom)))
869 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
870 replaces[Anum_pg_operator_oprcom - 1] = 'r';
871 tup = heap_modifytuple(tup,
878 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
879 setheapoverride(true);
880 heap_replace(pg_operator_desc, &itemPointerData, tup);
881 setheapoverride(false);
883 values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
884 replaces[Anum_pg_operator_oprcom - 1] = ' ';
886 /* release the buffer properly */
887 if (BufferIsValid(buffer))
888 ReleaseBuffer(buffer);
892 /* check and update the negator, if necessary */
893 opKey[0].sk_argument = ObjectIdGetDatum(negId);
895 pg_operator_scan = heap_beginscan(pg_operator_desc,
901 tup = heap_getnext(pg_operator_scan, 0, &buffer);
902 if (HeapTupleIsValid(tup) &&
903 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate)))
905 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
906 replaces[Anum_pg_operator_oprnegate - 1] = 'r';
907 tup = heap_modifytuple(tup,
914 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
916 setheapoverride(true);
917 heap_replace(pg_operator_desc, &itemPointerData, tup);
918 setheapoverride(false);
921 /* release the buffer properly */
922 if (BufferIsValid(buffer))
923 ReleaseBuffer(buffer);
925 heap_endscan(pg_operator_scan);
927 heap_close(pg_operator_desc);
931 /* ----------------------------------------------------------------
936 * Since the commutator, negator, leftsortoperator, and rightsortoperator
937 * can be defined implicitly through OperatorCreate, must check before
938 * the main operator is added to see if they already exist. If they
939 * do not already exist, OperatorDef makes a "shell" for each undefined
940 * one, and then OperatorCreate must call OperatorDef again to fill in
941 * each shell. All this is necessary in order to get the right ObjectId's
942 * filled into the right fields.
944 * The "definedOk" flag indicates that OperatorDef can be called on
945 * the operator even though it already has an entry in the PG_OPERATOR
946 * relation. This allows shells to be filled in. The user cannot
947 * forward declare operators, this is strictly an internal capability.
949 * When the shells are filled in by subsequent calls to OperatorDef,
950 * all the fields are the same as the definition of the original operator
951 * except that the target operator name and the original operatorName
952 * are switched. In the case of commutator and negator, special flags
953 * are set to indicate their status, telling the executor(?) that
954 * the operands are to be switched, or the outcome of the procedure
957 * ************************* NOTE NOTE NOTE ******************************
959 * If the execution of this utility is interrupted, the pg_operator
960 * catalog may be left in an inconsistent state. Similarly, if
961 * something is removed from the pg_operator, pg_type, or pg_procedure
962 * catalog while this is executing, the results may be inconsistent.
963 * ----------------------------------------------------------------
965 * "X" indicates an optional argument (i.e. one that can be NULL)
966 * operatorName; -- operator name
967 * leftTypeName; -- X left type name
968 * rightTypeName; -- X right type name
969 * procedureName; -- procedure for operator
970 * precedence; -- operator precedence
971 * isLeftAssociative; -- operator is left associative
972 * commutatorName; -- X commutator operator name
973 * negatorName; -- X negator operator name
974 * restrictionName; -- X restriction sel. procedure
975 * joinName; -- X join sel. procedure name
976 * canHash; -- operator hashes
977 * leftSortName; -- X left sort operator
978 * rightSortName; -- X right sort operator
982 OperatorCreate(char *operatorName,
987 bool isLeftAssociative,
988 char *commutatorName,
990 char *restrictionName,
998 Oid leftSortObjectId,
1002 if (!leftTypeName && !rightTypeName)
1003 elog(ERROR, "OperatorCreate : at least one of leftarg or rightarg must be defined");
1006 * get the oid's of the operator's associated operators, if possible.
1010 commObjectId = OperatorGet(commutatorName, /* commute type order */
1017 negObjectId = OperatorGet(negatorName,
1024 leftSortObjectId = OperatorGet(leftSortName,
1028 leftSortObjectId = 0;
1031 rightSortObjectId = OperatorGet(rightSortName,
1035 rightSortObjectId = 0;
1038 * Use OperatorDef() to define the specified operator and
1039 * also create shells for the operator's associated operators
1040 * if they don't already exist.
1042 * This operator should not be defined yet.
1047 OperatorDef(operatorName,
1063 * Now fill in information in the operator's associated
1066 * These operators should be defined or have shells defined.
1071 if (!OidIsValid(commObjectId) && commutatorName)
1072 OperatorDef(commutatorName,
1074 leftTypeName, /* should eventually */
1075 rightTypeName, /* commute order */
1079 operatorName, /* commutator */
1087 if (negatorName && !OidIsValid(negObjectId))
1088 OperatorDef(negatorName,
1096 operatorName, /* negator */
1103 if (leftSortName && !OidIsValid(leftSortObjectId))
1104 OperatorDef(leftSortName,
1116 operatorName, /* left sort */
1119 if (rightSortName && !OidIsValid(rightSortObjectId))
1120 OperatorDef(rightSortName,
1133 operatorName); /* right sort */