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.2 1996/10/07 03:27:48 scrappy Exp $
13 * these routines moved here from commands/define.c and somewhat cleaned up.
15 *-------------------------------------------------------------------------
20 #include "access/heapam.h"
21 #include "access/relscan.h"
22 #include "access/skey.h"
23 #include "access/htup.h"
24 #include "utils/rel.h"
25 #include "utils/elog.h"
26 #include "utils/palloc.h"
27 #include "parser/catalog_utils.h"
29 #include "catalog/catname.h"
30 #include "utils/syscache.h"
31 #include "catalog/pg_operator.h"
32 #include "catalog/pg_proc.h"
33 #include "storage/bufmgr.h"
37 static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
38 const char *operatorName,
41 static Oid OperatorGet(char *operatorName,
43 char *rightTypeName );
45 static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
49 static Oid OperatorShellMake(char *operatorName,
51 char *rightTypeName );
53 static void OperatorDef(char *operatorName,
59 bool isLeftAssociative,
62 char *restrictionName,
66 char *rightSortName );
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 oid of operator to fetch
78 * rightObjectId -- right oid of operator to fetch
81 OperatorGetWithOpenRelation(Relation pg_operator_desc,
82 const char *operatorName,
86 HeapScanDesc pg_operator_scan;
90 static ScanKeyData opKey[3] = {
91 { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
92 { 0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure },
93 { 0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure },
96 fmgr_info(NameEqualRegProcedure,
97 &opKey[0].sk_func, &opKey[0].sk_nargs);
98 fmgr_info(ObjectIdEqualRegProcedure,
99 &opKey[1].sk_func, &opKey[1].sk_nargs);
100 fmgr_info(ObjectIdEqualRegProcedure,
101 &opKey[2].sk_func, &opKey[2].sk_nargs);
107 opKey[0].sk_argument = PointerGetDatum(operatorName);
108 opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
109 opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
115 pg_operator_scan = heap_beginscan(pg_operator_desc,
122 * fetch the operator tuple, if it exists, and determine
123 * the proper return oid value.
126 tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
127 operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
130 * close the scan and return the oid.
133 heap_endscan(pg_operator_scan);
139 /* ----------------------------------------------------------------
142 * finds the operator associated with the specified name
143 * and left and right type names.
144 * ----------------------------------------------------------------
147 OperatorGet(char *operatorName,
151 Relation pg_operator_desc;
153 Oid operatorObjectId;
154 Oid leftObjectId = InvalidOid;
155 Oid rightObjectId = InvalidOid;
156 bool leftDefined = false;
157 bool rightDefined = false;
160 * look up the operator types.
162 * Note: types must be defined before operators
166 leftObjectId = TypeGet(leftTypeName, &leftDefined);
168 if (!OidIsValid(leftObjectId) || !leftDefined)
169 elog(WARN, "OperatorGet: left type '%s' nonexistent",leftTypeName);
173 rightObjectId = TypeGet(rightTypeName, &rightDefined);
175 if (!OidIsValid(rightObjectId) || !rightDefined)
176 elog(WARN, "OperatorGet: right type '%s' nonexistent",
180 if (!((OidIsValid(leftObjectId) && leftDefined) ||
181 (OidIsValid(rightObjectId) && rightDefined)))
182 elog(WARN, "OperatorGet: no argument types??");
185 * open the pg_operator relation
188 pg_operator_desc = heap_openr(OperatorRelationName);
191 * get the oid for the operator with the appropriate name
192 * and left/right types.
195 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
201 * close the relation and return the operator oid.
204 heap_close(pg_operator_desc);
210 /* ----------------------------------------------------------------
211 * OperatorShellMakeWithOpenRelation
213 * ----------------------------------------------------------------
216 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
223 Datum values[ Natts_pg_operator ];
224 char nulls[ Natts_pg_operator ];
225 Oid operatorObjectId;
229 * initialize our nulls[] and values[] arrays
232 for (i = 0; i < Natts_pg_operator; ++i) {
234 values[i] = (Datum)NULL; /* redundant, but safe */
238 * initialize values[] with the type name and
242 values[i++] = PointerGetDatum(operatorName);
243 values[i++] = ObjectIdGetDatum(InvalidOid);
244 values[i++] = (Datum) (uint16) 0;
246 values[i++] = (Datum)'b'; /* fill oprkind with a bogus value */
248 values[i++] = (Datum) (bool) 0;
249 values[i++] = (Datum) (bool) 0;
250 values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
251 values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
252 values[i++] = ObjectIdGetDatum(InvalidOid);
253 values[i++] = ObjectIdGetDatum(InvalidOid);
254 values[i++] = ObjectIdGetDatum(InvalidOid);
255 values[i++] = ObjectIdGetDatum(InvalidOid);
256 values[i++] = ObjectIdGetDatum(InvalidOid);
257 values[i++] = ObjectIdGetDatum(InvalidOid);
258 values[i++] = ObjectIdGetDatum(InvalidOid);
259 values[i++] = ObjectIdGetDatum(InvalidOid);
262 * create a new operator tuple
265 tupDesc = pg_operator_desc->rd_att;
267 tup = heap_formtuple(tupDesc,
272 * insert our "shell" operator tuple and
276 heap_insert(pg_operator_desc, tup);
277 operatorObjectId = tup->t_oid;
280 * free the tuple and return the operator oid
289 /* ----------------------------------------------------------------
292 * Specify operator name and left and right type names,
293 * fill an operator struct with this info and NULL's,
294 * call heap_insert and return the Oid
296 * ----------------------------------------------------------------
299 OperatorShellMake(char *operatorName,
303 Relation pg_operator_desc;
304 Oid operatorObjectId;
306 Oid leftObjectId = InvalidOid;
307 Oid rightObjectId = InvalidOid;
308 bool leftDefined = false;
309 bool rightDefined = false;
312 * get the left and right type oid's for this operator
316 leftObjectId = TypeGet(leftTypeName, &leftDefined);
319 rightObjectId = TypeGet(rightTypeName, &rightDefined);
321 if (!((OidIsValid(leftObjectId) && leftDefined) ||
322 (OidIsValid(rightObjectId) && rightDefined)))
323 elog(WARN, "OperatorShellMake: no valid argument types??");
329 pg_operator_desc = heap_openr(OperatorRelationName);
332 * add a "shell" operator tuple to the operator relation
333 * and recover the shell tuple's oid.
337 OperatorShellMakeWithOpenRelation(pg_operator_desc,
342 * close the operator relation and return the oid.
345 heap_close(pg_operator_desc);
351 /* --------------------------------
354 * This routine gets complicated because it allows the user to
355 * specify operators that do not exist. For example, if operator
356 * "op" is being defined, the negator operator "negop" and the
357 * commutator "commop" can also be defined without specifying
358 * any information other than their names. Since in order to
359 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
360 * operators must be placed in the fields of "op", a forward
361 * declaration is done on the commutator and negator operators.
362 * This is called creating a shell, and its main effect is to
363 * create a tuple in the PG_OPERATOR catalog with minimal
364 * information about the operator (just its name and types).
365 * Forward declaration is used only for this purpose, it is
366 * not available to the user as it is for type definition.
370 * check if operator already defined
371 * if so issue error if not definedOk, this is a duplicate
372 * but if definedOk, save the Oid -- filling in a shell
373 * get the attribute types from relation descriptor for pg_operator
374 * assign values to the fields of the operator:
376 * owner id (simply the user id of the caller)
378 * operator "kind" either "b" for binary or "l" for left unary
379 * isLeftAssociative boolean
381 * leftTypeObjectId -- type must already be defined
382 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
383 * resultType -- defer this, since it must be determined from
384 * the pg_procedure catalog
385 * commutatorObjectId -- if this is NULL, enter ObjectId=0
386 * else if this already exists, enter it's ObjectId
387 * else if this does not yet exist, and is not
388 * the same as the main operatorName, then create
389 * a shell and enter the new ObjectId
390 * else if this does not exist but IS the same
391 * name as the main operator, set the ObjectId=0.
392 * Later OperatorCreate will make another call
393 * to OperatorDef which will cause this field
394 * to be filled in (because even though the names
395 * will be switched, they are the same name and
396 * at this point this ObjectId will then be defined)
397 * negatorObjectId -- same as for commutatorObjectId
398 * leftSortObjectId -- same as for commutatorObjectId
399 * rightSortObjectId -- same as for commutatorObjectId
400 * operatorProcedure -- must access the pg_procedure catalog to get the
401 * ObjectId of the procedure that actually does the operator
402 * actions this is required. Do an amgetattr to find out the
403 * return type of the procedure
404 * restrictionProcedure -- must access the pg_procedure catalog to get
405 * the ObjectId but this is optional
406 * joinProcedure -- same as restrictionProcedure
407 * now either insert or replace the operator into the pg_operator catalog
408 * if the operator shell is being filled in
409 * access the catalog in order to get a valid buffer
410 * create a tuple using ModifyHeapTuple
411 * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple
412 * else if a new operator is being created
413 * create a tuple using heap_formtuple
415 * --------------------------------
416 * "X" indicates an optional argument (i.e. one that can be NULL)
417 * operatorName; -- operator name
418 * definedOK; -- operator can already have an oid?
419 * leftTypeName; -- X left type name
420 * rightTypeName; -- X right type name
421 * procedureName; -- procedure oid for operator code
422 * precedence; -- operator precedence
423 * isLeftAssociative; -- operator is left associative?
424 * commutatorName; -- X commutator operator name
425 * negatorName; -- X negator operator name
426 * restrictionName; -- X restriction sel. procedure name
427 * joinName; -- X join sel. procedure name
428 * canHash; -- possible hash operator?
429 * leftSortName; -- X left sort operator
430 * rightSortName; -- X right sort operator
433 OperatorDef(char *operatorName,
439 bool isLeftAssociative,
440 char *commutatorName,
442 char *restrictionName,
449 Relation pg_operator_desc;
451 HeapScanDesc pg_operator_scan;
454 ItemPointerData itemPointerData;
455 char nulls[ Natts_pg_operator ];
456 char replaces[ Natts_pg_operator ];
457 Datum values[ Natts_pg_operator ];
459 Oid operatorObjectId;
460 Oid leftTypeId = InvalidOid;
461 Oid rightTypeId = InvalidOid;
462 Oid commutatorId = InvalidOid;
463 Oid negatorId = InvalidOid;
464 bool leftDefined = false;
465 bool rightDefined = false;
471 static ScanKeyData opKey[3] = {
472 { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
473 { 0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure },
474 { 0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure },
477 fmgr_info(NameEqualRegProcedure,
478 &opKey[0].sk_func, &opKey[0].sk_nargs);
479 fmgr_info(ObjectIdEqualRegProcedure,
480 &opKey[1].sk_func, &opKey[1].sk_nargs);
481 fmgr_info(ObjectIdEqualRegProcedure,
482 &opKey[2].sk_func, &opKey[2].sk_nargs);
484 operatorObjectId = OperatorGet(operatorName,
488 if (OidIsValid(operatorObjectId) && !definedOK)
489 elog(WARN, "OperatorDef: operator \"%-.*s\" already defined",
490 NAMEDATALEN, operatorName);
493 leftTypeId = TypeGet(leftTypeName, &leftDefined);
496 rightTypeId = TypeGet(rightTypeName, &rightDefined);
498 if (!((OidIsValid(leftTypeId && leftDefined)) ||
499 (OidIsValid(rightTypeId && rightDefined))))
500 elog(WARN, "OperatorGet: no argument types??");
502 for (i = 0; i < Natts_pg_operator; ++i) {
503 values[i] = (Datum)NULL;
509 * Look up registered procedures -- find the return type
510 * of procedureName to place in "result" field.
511 * Do this before shells are created so we don't
512 * have to worry about deleting them later.
515 memset(typeId, 0, 8 * sizeof(Oid));
517 typeId[0] = rightTypeId;
520 else if (!rightTypeName) {
521 typeId[0] = leftTypeId;
525 typeId[0] = leftTypeId;
526 typeId[1] = rightTypeId;
529 tup = SearchSysCacheTuple(PRONAME,
530 PointerGetDatum(procedureName),
531 Int32GetDatum(nargs),
532 PointerGetDatum(typeId),
535 if (!PointerIsValid(tup))
536 func_error("OperatorDef", procedureName, nargs, (int*)typeId);
538 values[ Anum_pg_operator_oprcode-1 ] = ObjectIdGetDatum(tup->t_oid);
539 values[ Anum_pg_operator_oprresult-1 ] =
540 ObjectIdGetDatum(((Form_pg_proc)
541 GETSTRUCT(tup))->prorettype);
547 if (restrictionName) { /* optional */
548 memset(typeId, 0, 8 * sizeof(Oid));
549 typeId[0] = OIDOID; /* operator OID */
550 typeId[1] = OIDOID; /* relation OID */
551 typeId[2] = INT2OID; /* attribute number */
552 typeId[3] = 0; /* value - can be any type */
553 typeId[4] = INT4OID; /* flags - left or right selectivity */
554 tup = SearchSysCacheTuple(PRONAME,
555 PointerGetDatum(restrictionName),
557 ObjectIdGetDatum(typeId),
559 if (!HeapTupleIsValid(tup))
560 func_error("OperatorDef", restrictionName, 5, (int*)typeId);
562 values[ Anum_pg_operator_oprrest-1 ] = ObjectIdGetDatum(tup->t_oid);
564 values[ Anum_pg_operator_oprrest-1 ] = ObjectIdGetDatum(InvalidOid);
567 * find join - only valid for binary operators
570 if (joinName) { /* optional */
571 memset(typeId, 0, 8 * sizeof(Oid));
572 typeId[0] = OIDOID; /* operator OID */
573 typeId[1] = OIDOID; /* relation OID 1 */
574 typeId[2] = INT2OID; /* attribute number 1 */
575 typeId[3] = OIDOID; /* relation OID 2 */
576 typeId[4] = INT2OID; /* attribute number 2 */
578 tup = SearchSysCacheTuple(PRONAME,
579 PointerGetDatum(joinName),
581 Int32GetDatum(typeId),
583 if (!HeapTupleIsValid(tup))
584 func_error("OperatorDef", joinName, 5, (int*)typeId);
586 values[Anum_pg_operator_oprjoin-1] = ObjectIdGetDatum(tup->t_oid);
588 values[Anum_pg_operator_oprjoin-1] = ObjectIdGetDatum(InvalidOid);
591 * set up values in the operator tuple
595 values[i++] = PointerGetDatum(operatorName);
596 values[i++] = Int32GetDatum(GetUserId());
597 values[i++] = UInt16GetDatum(precedence);
598 values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
599 values[i++] = Int8GetDatum(isLeftAssociative);
600 values[i++] = Int8GetDatum(canHash);
601 values[i++] = ObjectIdGetDatum(leftTypeId);
602 values[i++] = ObjectIdGetDatum(rightTypeId);
604 ++i; /* Skip "prorettype", this was done above */
607 * Set up the other operators. If they do not currently exist,
608 * set up shells in order to get ObjectId's and call OperatorDef
609 * again later to fill in the shells.
611 name[0] = commutatorName;
612 name[1] = negatorName;
613 name[2] = leftSortName;
614 name[3] = rightSortName;
616 for (j = 0; j < 4; ++j) {
619 /* for the commutator, switch order of arguments */
621 other_oid = OperatorGet(name[j], rightTypeName,leftTypeName);
622 commutatorId = other_oid;
624 other_oid = OperatorGet(name[j], leftTypeName,rightTypeName);
626 negatorId = other_oid;
629 if (OidIsValid(other_oid)) /* already in catalogs */
630 values[i++] = ObjectIdGetDatum(other_oid);
631 else if (strcmp(operatorName, name[j]) != 0) {
632 /* not in catalogs, different from operator */
634 /* for the commutator, switch order of arguments */
636 other_oid = OperatorShellMake(name[j],
640 other_oid = OperatorShellMake(name[j],
645 if (!OidIsValid(other_oid))
647 "OperatorDef: can't create operator '%s'",
649 values[i++] = ObjectIdGetDatum(other_oid);
651 } else /* not in catalogs, same as operator ??? */
652 values[i++] = ObjectIdGetDatum(InvalidOid);
654 } else /* new operator is optional */
655 values[i++] = ObjectIdGetDatum(InvalidOid);
658 /* last three fields were filled in first */
661 * If we are adding to an operator shell, get its t_ctid and a
664 pg_operator_desc = heap_openr(OperatorRelationName);
666 if (operatorObjectId) {
667 opKey[0].sk_argument = PointerGetDatum(operatorName);
668 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
669 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
671 pg_operator_scan = heap_beginscan(pg_operator_desc,
677 tup = heap_getnext(pg_operator_scan, 0, &buffer);
678 if (HeapTupleIsValid(tup)) {
679 tup = heap_modifytuple(tup,
686 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
687 setheapoverride(true);
688 (void) heap_replace(pg_operator_desc, &itemPointerData, tup);
689 setheapoverride(false);
691 elog(WARN, "OperatorDef: no operator %d", other_oid);
693 heap_endscan(pg_operator_scan);
696 tupDesc = pg_operator_desc->rd_att;
697 tup = heap_formtuple(tupDesc, values, nulls);
699 heap_insert(pg_operator_desc, tup);
700 operatorObjectId = tup->t_oid;
703 heap_close(pg_operator_desc);
706 * It's possible that we're creating a skeleton operator here for
707 * the commute or negate attributes of a real operator. If we are,
708 * then we're done. If not, we may need to update the negator and
709 * commutator for this attribute. The reason for this is that the
710 * user may want to create two operators (say < and >=). When he
711 * defines <, if he uses >= as the negator or commutator, he won't
712 * be able to insert it later, since (for some reason) define operator
713 * defines it for him. So what he does is to define > without a
714 * negator or commutator. Then he defines >= with < as the negator
715 * and commutator. As a side effect, this will update the > tuple
716 * if it has no commutator or negator defined.
718 * Alstublieft, Tom Vijlbrief.
721 OperatorUpd(operatorObjectId, commutatorId, negatorId);
724 /* ----------------------------------------------------------------
727 * For a given operator, look up its negator and commutator operators.
728 * If they are defined, but their negator and commutator operators
729 * (respectively) are not, then use the new operator for neg and comm.
730 * This solves a problem for users who need to insert two new operators
731 * which are the negator or commutator of each other.
732 * ----------------------------------------------------------------
735 OperatorUpd(Oid baseId, Oid commId, Oid negId)
738 Relation pg_operator_desc;
739 HeapScanDesc pg_operator_scan;
742 ItemPointerData itemPointerData;
743 char nulls[ Natts_pg_operator ];
744 char replaces[ Natts_pg_operator ];
745 Datum values[ Natts_pg_operator ];
747 static ScanKeyData opKey[1] = {
748 { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure },
751 fmgr_info(ObjectIdEqualRegProcedure,
752 &opKey[0].sk_func, &opKey[0].sk_nargs);
754 for (i = 0; i < Natts_pg_operator; ++i) {
755 values[i] = (Datum)NULL;
760 pg_operator_desc = heap_openr(OperatorRelationName);
762 /* check and update the commutator, if necessary */
763 opKey[0].sk_argument = ObjectIdGetDatum(commId);
765 pg_operator_scan = heap_beginscan(pg_operator_desc,
771 tup = heap_getnext(pg_operator_scan, 0, &buffer);
773 /* if the commutator and negator are the same operator, do one update */
774 if (commId == negId) {
775 if (HeapTupleIsValid(tup)) {
778 t = (OperatorTupleForm) GETSTRUCT(tup);
779 if (!OidIsValid(t->oprcom)
780 || !OidIsValid(t->oprnegate)) {
782 if (!OidIsValid(t->oprnegate)) {
783 values[Anum_pg_operator_oprnegate - 1] =
784 ObjectIdGetDatum(baseId);
785 replaces[ Anum_pg_operator_oprnegate - 1 ] = 'r';
788 if (!OidIsValid(t->oprcom)) {
789 values[Anum_pg_operator_oprcom - 1] =
790 ObjectIdGetDatum(baseId);
791 replaces[ Anum_pg_operator_oprcom - 1 ] = 'r';
794 tup = heap_modifytuple(tup,
801 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
803 setheapoverride(true);
804 (void) heap_replace(pg_operator_desc, &itemPointerData, tup);
805 setheapoverride(false);
809 heap_endscan(pg_operator_scan);
811 heap_close(pg_operator_desc);
813 /* release the buffer properly */
814 if (BufferIsValid(buffer))
815 ReleaseBuffer(buffer);
820 /* if commutator and negator are different, do two updates */
821 if (HeapTupleIsValid(tup) &&
822 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom))) {
823 values[ Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
824 replaces[ Anum_pg_operator_oprcom - 1] = 'r';
825 tup = heap_modifytuple(tup,
832 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
833 setheapoverride(true);
834 (void) heap_replace(pg_operator_desc, &itemPointerData, tup);
835 setheapoverride(false);
837 values[ Anum_pg_operator_oprcom - 1 ] = (Datum)NULL;
838 replaces[ Anum_pg_operator_oprcom - 1 ] = ' ';
840 /* release the buffer properly */
841 if (BufferIsValid(buffer))
842 ReleaseBuffer(buffer);
846 /* check and update the negator, if necessary */
847 opKey[0].sk_argument = ObjectIdGetDatum(negId);
849 pg_operator_scan = heap_beginscan(pg_operator_desc,
855 tup = heap_getnext(pg_operator_scan, 0, &buffer);
856 if (HeapTupleIsValid(tup) &&
857 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate))) {
858 values[Anum_pg_operator_oprnegate-1] = ObjectIdGetDatum(baseId);
859 replaces[ Anum_pg_operator_oprnegate - 1 ] = 'r';
860 tup = heap_modifytuple(tup,
867 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
869 setheapoverride(true);
870 (void) heap_replace(pg_operator_desc, &itemPointerData, tup);
871 setheapoverride(false);
874 /* release the buffer properly */
875 if (BufferIsValid(buffer))
876 ReleaseBuffer(buffer);
878 heap_endscan(pg_operator_scan);
880 heap_close(pg_operator_desc);
884 /* ----------------------------------------------------------------
889 * Since the commutator, negator, leftsortoperator, and rightsortoperator
890 * can be defined implicitly through OperatorCreate, must check before
891 * the main operator is added to see if they already exist. If they
892 * do not already exist, OperatorDef makes a "shell" for each undefined
893 * one, and then OperatorCreate must call OperatorDef again to fill in
894 * each shell. All this is necessary in order to get the right ObjectId's
895 * filled into the right fields.
897 * The "definedOk" flag indicates that OperatorDef can be called on
898 * the operator even though it already has an entry in the PG_OPERATOR
899 * relation. This allows shells to be filled in. The user cannot
900 * forward declare operators, this is strictly an internal capability.
902 * When the shells are filled in by subsequent calls to OperatorDef,
903 * all the fields are the same as the definition of the original operator
904 * except that the target operator name and the original operatorName
905 * are switched. In the case of commutator and negator, special flags
906 * are set to indicate their status, telling the executor(?) that
907 * the operands are to be switched, or the outcome of the procedure
910 * ************************* NOTE NOTE NOTE ******************************
912 * If the execution of this utility is interrupted, the pg_operator
913 * catalog may be left in an inconsistent state. Similarly, if
914 * something is removed from the pg_operator, pg_type, or pg_procedure
915 * catalog while this is executing, the results may be inconsistent.
916 * ----------------------------------------------------------------
918 * "X" indicates an optional argument (i.e. one that can be NULL)
919 * operatorName; -- operator name
920 * leftTypeName; -- X left type name
921 * rightTypeName; -- X right type name
922 * procedureName; -- procedure for operator
923 * precedence; -- operator precedence
924 * isLeftAssociative; -- operator is left associative
925 * commutatorName; -- X commutator operator name
926 * negatorName; -- X negator operator name
927 * restrictionName; -- X restriction sel. procedure
928 * joinName; -- X join sel. procedure name
929 * canHash; -- operator hashes
930 * leftSortName; -- X left sort operator
931 * rightSortName; -- X right sort operator
935 OperatorCreate(char *operatorName,
940 bool isLeftAssociative,
941 char *commutatorName,
943 char *restrictionName,
949 Oid commObjectId, negObjectId;
950 Oid leftSortObjectId, rightSortObjectId;
953 if (!leftTypeName && !rightTypeName)
954 elog(WARN, "OperatorCreate : at least one of leftarg or rightarg must be defined");
957 * get the oid's of the operator's associated operators, if possible.
961 commObjectId = OperatorGet(commutatorName, /* commute type order */
966 negObjectId = OperatorGet(negatorName,
971 leftSortObjectId = OperatorGet(leftSortName,
976 rightSortObjectId = OperatorGet(rightSortName,
981 * Use OperatorDef() to define the specified operator and
982 * also create shells for the operator's associated operators
983 * if they don't already exist.
985 * This operator should not be defined yet.
990 OperatorDef(operatorName,
1006 * Now fill in information in the operator's associated
1009 * These operators should be defined or have shells defined.
1014 if (!OidIsValid(commObjectId) && commutatorName)
1015 OperatorDef(commutatorName,
1017 leftTypeName, /* should eventually */
1018 rightTypeName, /* commute order */
1022 operatorName, /* commutator */
1030 if (negatorName && !OidIsValid(negObjectId))
1031 OperatorDef(negatorName,
1039 operatorName, /* negator */
1046 if (leftSortName && !OidIsValid(leftSortObjectId))
1047 OperatorDef(leftSortName,
1059 operatorName, /* left sort */
1062 if (rightSortName && !OidIsValid(rightSortObjectId))
1063 OperatorDef(rightSortName,
1076 operatorName); /* right sort */