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.9 1997/07/23 17:14:34 momjian Exp $
13 * these routines moved here from commands/define.c and somewhat cleaned up.
15 *-------------------------------------------------------------------------
19 #include <catalog/pg_proc.h>
20 #include <utils/syscache.h>
21 #include <access/heapam.h>
22 #include <parser/catalog_utils.h>
23 #include <catalog/catname.h>
24 #include <catalog/pg_operator.h>
25 #include <storage/bufmgr.h>
27 #include <miscadmin.h>
29 # include <regex/utils.h>
34 static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
35 const char *operatorName,
38 static Oid OperatorGet(char *operatorName,
40 char *rightTypeName );
42 static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
46 static Oid OperatorShellMake(char *operatorName,
48 char *rightTypeName );
50 static void OperatorDef(char *operatorName,
56 bool isLeftAssociative,
59 char *restrictionName,
63 char *rightSortName );
64 static void OperatorUpd(Oid baseId , Oid commId , Oid negId );
66 /* ----------------------------------------------------------------
67 * OperatorGetWithOpenRelation
69 * preforms a scan on pg_operator for an operator tuple
70 * with given name and left/right type oids.
71 * ----------------------------------------------------------------
72 * pg_operator_desc -- reldesc for pg_operator
73 * operatorName -- name of operator to fetch
74 * leftObjectId -- left oid of operator to fetch
75 * rightObjectId -- right oid of operator to fetch
78 OperatorGetWithOpenRelation(Relation pg_operator_desc,
79 const char *operatorName,
83 HeapScanDesc pg_operator_scan;
87 static ScanKeyData opKey[3] = {
88 { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
89 { 0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure },
90 { 0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure },
93 fmgr_info(NameEqualRegProcedure,
94 &opKey[0].sk_func, &opKey[0].sk_nargs);
95 fmgr_info(ObjectIdEqualRegProcedure,
96 &opKey[1].sk_func, &opKey[1].sk_nargs);
97 fmgr_info(ObjectIdEqualRegProcedure,
98 &opKey[2].sk_func, &opKey[2].sk_nargs);
104 opKey[0].sk_argument = PointerGetDatum(operatorName);
105 opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
106 opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
112 pg_operator_scan = heap_beginscan(pg_operator_desc,
119 * fetch the operator tuple, if it exists, and determine
120 * the proper return oid value.
123 tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
124 operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
127 * close the scan and return the oid.
130 heap_endscan(pg_operator_scan);
136 /* ----------------------------------------------------------------
139 * finds the operator associated with the specified name
140 * and left and right type names.
141 * ----------------------------------------------------------------
144 OperatorGet(char *operatorName,
148 Relation pg_operator_desc;
150 Oid operatorObjectId;
151 Oid leftObjectId = InvalidOid;
152 Oid rightObjectId = InvalidOid;
153 bool leftDefined = false;
154 bool rightDefined = false;
157 * look up the operator types.
159 * Note: types must be defined before operators
163 leftObjectId = TypeGet(leftTypeName, &leftDefined);
165 if (!OidIsValid(leftObjectId) || !leftDefined)
166 elog(WARN, "OperatorGet: left type '%s' nonexistent",leftTypeName);
170 rightObjectId = TypeGet(rightTypeName, &rightDefined);
172 if (!OidIsValid(rightObjectId) || !rightDefined)
173 elog(WARN, "OperatorGet: right type '%s' nonexistent",
177 if (!((OidIsValid(leftObjectId) && leftDefined) ||
178 (OidIsValid(rightObjectId) && rightDefined)))
179 elog(WARN, "OperatorGet: no argument types??");
182 * open the pg_operator relation
185 pg_operator_desc = heap_openr(OperatorRelationName);
188 * get the oid for the operator with the appropriate name
189 * and left/right types.
192 operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
198 * close the relation and return the operator oid.
201 heap_close(pg_operator_desc);
207 /* ----------------------------------------------------------------
208 * OperatorShellMakeWithOpenRelation
210 * ----------------------------------------------------------------
213 OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
220 Datum values[ Natts_pg_operator ];
221 char nulls[ Natts_pg_operator ];
222 Oid operatorObjectId;
226 * initialize our nulls[] and values[] arrays
229 for (i = 0; i < Natts_pg_operator; ++i) {
231 values[i] = (Datum)NULL; /* redundant, but safe */
235 * initialize values[] with the type name and
239 values[i++] = PointerGetDatum(operatorName);
240 values[i++] = Int32GetDatum(GetUserId());
241 values[i++] = (Datum) (uint16) 0;
243 values[i++] = (Datum)'b'; /* fill oprkind with a bogus value */
245 values[i++] = (Datum) (bool) 0;
246 values[i++] = (Datum) (bool) 0;
247 values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
248 values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
249 values[i++] = ObjectIdGetDatum(InvalidOid);
250 values[i++] = ObjectIdGetDatum(InvalidOid);
251 values[i++] = ObjectIdGetDatum(InvalidOid);
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);
259 * create a new operator tuple
262 tupDesc = pg_operator_desc->rd_att;
264 tup = heap_formtuple(tupDesc,
269 * insert our "shell" operator tuple and
273 heap_insert(pg_operator_desc, tup);
274 operatorObjectId = tup->t_oid;
277 * free the tuple and return the operator oid
286 /* ----------------------------------------------------------------
289 * Specify operator name and left and right type names,
290 * fill an operator struct with this info and NULL's,
291 * call heap_insert and return the Oid
293 * ----------------------------------------------------------------
296 OperatorShellMake(char *operatorName,
300 Relation pg_operator_desc;
301 Oid operatorObjectId;
303 Oid leftObjectId = InvalidOid;
304 Oid rightObjectId = InvalidOid;
305 bool leftDefined = false;
306 bool rightDefined = false;
309 * get the left and right type oid's for this operator
313 leftObjectId = TypeGet(leftTypeName, &leftDefined);
316 rightObjectId = TypeGet(rightTypeName, &rightDefined);
318 if (!((OidIsValid(leftObjectId) && leftDefined) ||
319 (OidIsValid(rightObjectId) && rightDefined)))
320 elog(WARN, "OperatorShellMake: no valid argument types??");
326 pg_operator_desc = heap_openr(OperatorRelationName);
329 * add a "shell" operator tuple to the operator relation
330 * and recover the shell tuple's oid.
334 OperatorShellMakeWithOpenRelation(pg_operator_desc,
339 * close the operator relation and return the oid.
342 heap_close(pg_operator_desc);
348 /* --------------------------------
351 * This routine gets complicated because it allows the user to
352 * specify operators that do not exist. For example, if operator
353 * "op" is being defined, the negator operator "negop" and the
354 * commutator "commop" can also be defined without specifying
355 * any information other than their names. Since in order to
356 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
357 * operators must be placed in the fields of "op", a forward
358 * declaration is done on the commutator and negator operators.
359 * This is called creating a shell, and its main effect is to
360 * create a tuple in the PG_OPERATOR catalog with minimal
361 * information about the operator (just its name and types).
362 * Forward declaration is used only for this purpose, it is
363 * not available to the user as it is for type definition.
367 * check if operator already defined
368 * if so issue error if not definedOk, this is a duplicate
369 * but if definedOk, save the Oid -- filling in a shell
370 * get the attribute types from relation descriptor for pg_operator
371 * assign values to the fields of the operator:
373 * owner id (simply the user id of the caller)
375 * operator "kind" either "b" for binary or "l" for left unary
376 * isLeftAssociative boolean
378 * leftTypeObjectId -- type must already be defined
379 * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
380 * resultType -- defer this, since it must be determined from
381 * the pg_procedure catalog
382 * commutatorObjectId -- if this is NULL, enter ObjectId=0
383 * else if this already exists, enter it's ObjectId
384 * else if this does not yet exist, and is not
385 * the same as the main operatorName, then create
386 * a shell and enter the new ObjectId
387 * else if this does not exist but IS the same
388 * name as the main operator, set the ObjectId=0.
389 * Later OperatorCreate will make another call
390 * to OperatorDef which will cause this field
391 * to be filled in (because even though the names
392 * will be switched, they are the same name and
393 * at this point this ObjectId will then be defined)
394 * negatorObjectId -- same as for commutatorObjectId
395 * leftSortObjectId -- same as for commutatorObjectId
396 * rightSortObjectId -- same as for commutatorObjectId
397 * operatorProcedure -- must access the pg_procedure catalog to get the
398 * ObjectId of the procedure that actually does the operator
399 * actions this is required. Do an amgetattr to find out the
400 * return type of the procedure
401 * restrictionProcedure -- must access the pg_procedure catalog to get
402 * the ObjectId but this is optional
403 * joinProcedure -- same as restrictionProcedure
404 * now either insert or replace the operator into the pg_operator catalog
405 * if the operator shell is being filled in
406 * access the catalog in order to get a valid buffer
407 * create a tuple using ModifyHeapTuple
408 * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple
409 * else if a new operator is being created
410 * create a tuple using heap_formtuple
412 * --------------------------------
413 * "X" indicates an optional argument (i.e. one that can be NULL)
414 * operatorName; -- operator name
415 * definedOK; -- operator can already have an oid?
416 * leftTypeName; -- X left type name
417 * rightTypeName; -- X right type name
418 * procedureName; -- procedure oid for operator code
419 * precedence; -- operator precedence
420 * isLeftAssociative; -- operator is left associative?
421 * commutatorName; -- X commutator operator name
422 * negatorName; -- X negator operator name
423 * restrictionName; -- X restriction sel. procedure name
424 * joinName; -- X join sel. procedure name
425 * canHash; -- possible hash operator?
426 * leftSortName; -- X left sort operator
427 * rightSortName; -- X right sort operator
430 OperatorDef(char *operatorName,
436 bool isLeftAssociative,
437 char *commutatorName,
439 char *restrictionName,
446 Relation pg_operator_desc;
448 HeapScanDesc pg_operator_scan;
451 ItemPointerData itemPointerData;
452 char nulls[ Natts_pg_operator ];
453 char replaces[ Natts_pg_operator ];
454 Datum values[ Natts_pg_operator ];
456 Oid operatorObjectId;
457 Oid leftTypeId = InvalidOid;
458 Oid rightTypeId = InvalidOid;
459 Oid commutatorId = InvalidOid;
460 Oid negatorId = InvalidOid;
461 bool leftDefined = false;
462 bool rightDefined = false;
468 static ScanKeyData opKey[3] = {
469 { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
470 { 0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure },
471 { 0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure },
474 fmgr_info(NameEqualRegProcedure,
475 &opKey[0].sk_func, &opKey[0].sk_nargs);
476 fmgr_info(ObjectIdEqualRegProcedure,
477 &opKey[1].sk_func, &opKey[1].sk_nargs);
478 fmgr_info(ObjectIdEqualRegProcedure,
479 &opKey[2].sk_func, &opKey[2].sk_nargs);
481 operatorObjectId = OperatorGet(operatorName,
485 if (OidIsValid(operatorObjectId) && !definedOK)
486 elog(WARN, "OperatorDef: operator \"%-.*s\" already defined",
487 NAMEDATALEN, operatorName);
490 leftTypeId = TypeGet(leftTypeName, &leftDefined);
493 rightTypeId = TypeGet(rightTypeName, &rightDefined);
495 if (!((OidIsValid(leftTypeId && leftDefined)) ||
496 (OidIsValid(rightTypeId && rightDefined))))
497 elog(WARN, "OperatorGet: no argument types??");
499 for (i = 0; i < Natts_pg_operator; ++i) {
500 values[i] = (Datum)NULL;
506 * Look up registered procedures -- find the return type
507 * of procedureName to place in "result" field.
508 * Do this before shells are created so we don't
509 * have to worry about deleting them later.
512 memset(typeId, 0, 8 * sizeof(Oid));
514 typeId[0] = rightTypeId;
517 else if (!rightTypeName) {
518 typeId[0] = leftTypeId;
522 typeId[0] = leftTypeId;
523 typeId[1] = rightTypeId;
526 tup = SearchSysCacheTuple(PRONAME,
527 PointerGetDatum(procedureName),
528 Int32GetDatum(nargs),
529 PointerGetDatum(typeId),
532 if (!PointerIsValid(tup))
533 func_error("OperatorDef", procedureName, nargs, typeId);
535 values[ Anum_pg_operator_oprcode-1 ] = ObjectIdGetDatum(tup->t_oid);
536 values[ Anum_pg_operator_oprresult-1 ] =
537 ObjectIdGetDatum(((Form_pg_proc)
538 GETSTRUCT(tup))->prorettype);
544 if (restrictionName) { /* optional */
545 memset(typeId, 0, 8 * sizeof(Oid));
546 typeId[0] = OIDOID; /* operator OID */
547 typeId[1] = OIDOID; /* relation OID */
548 typeId[2] = INT2OID; /* attribute number */
549 typeId[3] = 0; /* value - can be any type */
550 typeId[4] = INT4OID; /* flags - left or right selectivity */
551 tup = SearchSysCacheTuple(PRONAME,
552 PointerGetDatum(restrictionName),
554 PointerGetDatum(typeId),
556 if (!HeapTupleIsValid(tup))
557 func_error("OperatorDef", restrictionName, 5, typeId);
559 values[ Anum_pg_operator_oprrest-1 ] = ObjectIdGetDatum(tup->t_oid);
561 values[ Anum_pg_operator_oprrest-1 ] = ObjectIdGetDatum(InvalidOid);
564 * find join - only valid for binary operators
567 if (joinName) { /* optional */
568 memset(typeId, 0, 8 * sizeof(Oid));
569 typeId[0] = OIDOID; /* operator OID */
570 typeId[1] = OIDOID; /* relation OID 1 */
571 typeId[2] = INT2OID; /* attribute number 1 */
572 typeId[3] = OIDOID; /* relation OID 2 */
573 typeId[4] = INT2OID; /* attribute number 2 */
575 tup = SearchSysCacheTuple(PRONAME,
576 PointerGetDatum(joinName),
578 PointerGetDatum(typeId),
580 if (!HeapTupleIsValid(tup))
581 func_error("OperatorDef", joinName, 5, typeId);
583 values[Anum_pg_operator_oprjoin-1] = ObjectIdGetDatum(tup->t_oid);
585 values[Anum_pg_operator_oprjoin-1] = ObjectIdGetDatum(InvalidOid);
588 * set up values in the operator tuple
592 values[i++] = PointerGetDatum(operatorName);
593 values[i++] = Int32GetDatum(GetUserId());
594 values[i++] = UInt16GetDatum(precedence);
595 values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
596 values[i++] = Int8GetDatum(isLeftAssociative);
597 values[i++] = Int8GetDatum(canHash);
598 values[i++] = ObjectIdGetDatum(leftTypeId);
599 values[i++] = ObjectIdGetDatum(rightTypeId);
601 ++i; /* Skip "prorettype", this was done above */
604 * Set up the other operators. If they do not currently exist,
605 * set up shells in order to get ObjectId's and call OperatorDef
606 * again later to fill in the shells.
608 name[0] = commutatorName;
609 name[1] = negatorName;
610 name[2] = leftSortName;
611 name[3] = rightSortName;
613 for (j = 0; j < 4; ++j) {
616 /* for the commutator, switch order of arguments */
618 other_oid = OperatorGet(name[j], rightTypeName,leftTypeName);
619 commutatorId = other_oid;
621 other_oid = OperatorGet(name[j], leftTypeName,rightTypeName);
623 negatorId = other_oid;
626 if (OidIsValid(other_oid)) /* already in catalogs */
627 values[i++] = ObjectIdGetDatum(other_oid);
628 else if (strcmp(operatorName, name[j]) != 0) {
629 /* not in catalogs, different from operator */
631 /* for the commutator, switch order of arguments */
633 other_oid = OperatorShellMake(name[j],
637 other_oid = OperatorShellMake(name[j],
642 if (!OidIsValid(other_oid))
644 "OperatorDef: can't create operator '%s'",
646 values[i++] = ObjectIdGetDatum(other_oid);
648 } else /* not in catalogs, same as operator ??? */
649 values[i++] = ObjectIdGetDatum(InvalidOid);
651 } else /* new operator is optional */
652 values[i++] = ObjectIdGetDatum(InvalidOid);
655 /* last three fields were filled in first */
658 * If we are adding to an operator shell, get its t_ctid and a
661 pg_operator_desc = heap_openr(OperatorRelationName);
663 if (operatorObjectId) {
664 opKey[0].sk_argument = PointerGetDatum(operatorName);
665 opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
666 opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
668 pg_operator_scan = heap_beginscan(pg_operator_desc,
674 tup = heap_getnext(pg_operator_scan, 0, &buffer);
675 if (HeapTupleIsValid(tup)) {
676 tup = heap_modifytuple(tup,
683 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
684 setheapoverride(true);
685 (void) heap_replace(pg_operator_desc, &itemPointerData, tup);
686 setheapoverride(false);
688 elog(WARN, "OperatorDef: no operator %d", other_oid);
690 heap_endscan(pg_operator_scan);
693 tupDesc = pg_operator_desc->rd_att;
694 tup = heap_formtuple(tupDesc, values, nulls);
696 heap_insert(pg_operator_desc, tup);
697 operatorObjectId = tup->t_oid;
700 heap_close(pg_operator_desc);
703 * It's possible that we're creating a skeleton operator here for
704 * the commute or negate attributes of a real operator. If we are,
705 * then we're done. If not, we may need to update the negator and
706 * commutator for this attribute. The reason for this is that the
707 * user may want to create two operators (say < and >=). When he
708 * defines <, if he uses >= as the negator or commutator, he won't
709 * be able to insert it later, since (for some reason) define operator
710 * defines it for him. So what he does is to define > without a
711 * negator or commutator. Then he defines >= with < as the negator
712 * and commutator. As a side effect, this will update the > tuple
713 * if it has no commutator or negator defined.
715 * Alstublieft, Tom Vijlbrief.
718 OperatorUpd(operatorObjectId, commutatorId, negatorId);
721 /* ----------------------------------------------------------------
724 * For a given operator, look up its negator and commutator operators.
725 * If they are defined, but their negator and commutator operators
726 * (respectively) are not, then use the new operator for neg and comm.
727 * This solves a problem for users who need to insert two new operators
728 * which are the negator or commutator of each other.
729 * ----------------------------------------------------------------
732 OperatorUpd(Oid baseId, Oid commId, Oid negId)
735 Relation pg_operator_desc;
736 HeapScanDesc pg_operator_scan;
739 ItemPointerData itemPointerData;
740 char nulls[ Natts_pg_operator ];
741 char replaces[ Natts_pg_operator ];
742 Datum values[ Natts_pg_operator ];
744 static ScanKeyData opKey[1] = {
745 { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure },
748 fmgr_info(ObjectIdEqualRegProcedure,
749 &opKey[0].sk_func, &opKey[0].sk_nargs);
751 for (i = 0; i < Natts_pg_operator; ++i) {
752 values[i] = (Datum)NULL;
757 pg_operator_desc = heap_openr(OperatorRelationName);
759 /* check and update the commutator, if necessary */
760 opKey[0].sk_argument = ObjectIdGetDatum(commId);
762 pg_operator_scan = heap_beginscan(pg_operator_desc,
768 tup = heap_getnext(pg_operator_scan, 0, &buffer);
770 /* if the commutator and negator are the same operator, do one update */
771 if (commId == negId) {
772 if (HeapTupleIsValid(tup)) {
775 t = (OperatorTupleForm) GETSTRUCT(tup);
776 if (!OidIsValid(t->oprcom)
777 || !OidIsValid(t->oprnegate)) {
779 if (!OidIsValid(t->oprnegate)) {
780 values[Anum_pg_operator_oprnegate - 1] =
781 ObjectIdGetDatum(baseId);
782 replaces[ Anum_pg_operator_oprnegate - 1 ] = 'r';
785 if (!OidIsValid(t->oprcom)) {
786 values[Anum_pg_operator_oprcom - 1] =
787 ObjectIdGetDatum(baseId);
788 replaces[ Anum_pg_operator_oprcom - 1 ] = 'r';
791 tup = heap_modifytuple(tup,
798 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
800 setheapoverride(true);
801 (void) heap_replace(pg_operator_desc, &itemPointerData, tup);
802 setheapoverride(false);
806 heap_endscan(pg_operator_scan);
808 heap_close(pg_operator_desc);
810 /* release the buffer properly */
811 if (BufferIsValid(buffer))
812 ReleaseBuffer(buffer);
817 /* if commutator and negator are different, do two updates */
818 if (HeapTupleIsValid(tup) &&
819 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom))) {
820 values[ Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
821 replaces[ Anum_pg_operator_oprcom - 1] = 'r';
822 tup = heap_modifytuple(tup,
829 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
830 setheapoverride(true);
831 (void) heap_replace(pg_operator_desc, &itemPointerData, tup);
832 setheapoverride(false);
834 values[ Anum_pg_operator_oprcom - 1 ] = (Datum)NULL;
835 replaces[ Anum_pg_operator_oprcom - 1 ] = ' ';
837 /* release the buffer properly */
838 if (BufferIsValid(buffer))
839 ReleaseBuffer(buffer);
843 /* check and update the negator, if necessary */
844 opKey[0].sk_argument = ObjectIdGetDatum(negId);
846 pg_operator_scan = heap_beginscan(pg_operator_desc,
852 tup = heap_getnext(pg_operator_scan, 0, &buffer);
853 if (HeapTupleIsValid(tup) &&
854 !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate))) {
855 values[Anum_pg_operator_oprnegate-1] = ObjectIdGetDatum(baseId);
856 replaces[ Anum_pg_operator_oprnegate - 1 ] = 'r';
857 tup = heap_modifytuple(tup,
864 ItemPointerCopy(&tup->t_ctid, &itemPointerData);
866 setheapoverride(true);
867 (void) heap_replace(pg_operator_desc, &itemPointerData, tup);
868 setheapoverride(false);
871 /* release the buffer properly */
872 if (BufferIsValid(buffer))
873 ReleaseBuffer(buffer);
875 heap_endscan(pg_operator_scan);
877 heap_close(pg_operator_desc);
881 /* ----------------------------------------------------------------
886 * Since the commutator, negator, leftsortoperator, and rightsortoperator
887 * can be defined implicitly through OperatorCreate, must check before
888 * the main operator is added to see if they already exist. If they
889 * do not already exist, OperatorDef makes a "shell" for each undefined
890 * one, and then OperatorCreate must call OperatorDef again to fill in
891 * each shell. All this is necessary in order to get the right ObjectId's
892 * filled into the right fields.
894 * The "definedOk" flag indicates that OperatorDef can be called on
895 * the operator even though it already has an entry in the PG_OPERATOR
896 * relation. This allows shells to be filled in. The user cannot
897 * forward declare operators, this is strictly an internal capability.
899 * When the shells are filled in by subsequent calls to OperatorDef,
900 * all the fields are the same as the definition of the original operator
901 * except that the target operator name and the original operatorName
902 * are switched. In the case of commutator and negator, special flags
903 * are set to indicate their status, telling the executor(?) that
904 * the operands are to be switched, or the outcome of the procedure
907 * ************************* NOTE NOTE NOTE ******************************
909 * If the execution of this utility is interrupted, the pg_operator
910 * catalog may be left in an inconsistent state. Similarly, if
911 * something is removed from the pg_operator, pg_type, or pg_procedure
912 * catalog while this is executing, the results may be inconsistent.
913 * ----------------------------------------------------------------
915 * "X" indicates an optional argument (i.e. one that can be NULL)
916 * operatorName; -- operator name
917 * leftTypeName; -- X left type name
918 * rightTypeName; -- X right type name
919 * procedureName; -- procedure for operator
920 * precedence; -- operator precedence
921 * isLeftAssociative; -- operator is left associative
922 * commutatorName; -- X commutator operator name
923 * negatorName; -- X negator operator name
924 * restrictionName; -- X restriction sel. procedure
925 * joinName; -- X join sel. procedure name
926 * canHash; -- operator hashes
927 * leftSortName; -- X left sort operator
928 * rightSortName; -- X right sort operator
932 OperatorCreate(char *operatorName,
937 bool isLeftAssociative,
938 char *commutatorName,
940 char *restrictionName,
946 Oid commObjectId, negObjectId;
947 Oid leftSortObjectId, rightSortObjectId;
950 if (!leftTypeName && !rightTypeName)
951 elog(WARN, "OperatorCreate : at least one of leftarg or rightarg must be defined");
954 * get the oid's of the operator's associated operators, if possible.
958 commObjectId = OperatorGet(commutatorName, /* commute type order */
961 else commObjectId = 0;
964 negObjectId = OperatorGet(negatorName,
967 else negObjectId = 0;
970 leftSortObjectId = OperatorGet(leftSortName,
973 else leftSortObjectId = 0;
976 rightSortObjectId = OperatorGet(rightSortName,
979 else rightSortObjectId = 0;
982 * Use OperatorDef() to define the specified operator and
983 * also create shells for the operator's associated operators
984 * if they don't already exist.
986 * This operator should not be defined yet.
991 OperatorDef(operatorName,
1007 * Now fill in information in the operator's associated
1010 * These operators should be defined or have shells defined.
1015 if (!OidIsValid(commObjectId) && commutatorName)
1016 OperatorDef(commutatorName,
1018 leftTypeName, /* should eventually */
1019 rightTypeName, /* commute order */
1023 operatorName, /* commutator */
1031 if (negatorName && !OidIsValid(negObjectId))
1032 OperatorDef(negatorName,
1040 operatorName, /* negator */
1047 if (leftSortName && !OidIsValid(leftSortObjectId))
1048 OperatorDef(leftSortName,
1060 operatorName, /* left sort */
1063 if (rightSortName && !OidIsValid(rightSortObjectId))
1064 OperatorDef(rightSortName,
1077 operatorName); /* right sort */