@@ -54,8 +54,6 @@ static Oid OperatorShellMake(const char *operatorName,
5454 Oid leftTypeId ,
5555 Oid rightTypeId );
5656
57- static void OperatorUpd (Oid baseId , Oid commId , Oid negId );
58-
5957static Oid get_other_operator (List * otherOp ,
6058 Oid otherLeftTypeId , Oid otherRightTypeId ,
6159 const char * operatorName , Oid operatorNamespace ,
@@ -566,7 +564,7 @@ OperatorCreate(const char *operatorName,
566564 commutatorId = operatorObjectId ;
567565
568566 if (OidIsValid (commutatorId ) || OidIsValid (negatorId ))
569- OperatorUpd (operatorObjectId , commutatorId , negatorId );
567+ OperatorUpd (operatorObjectId , commutatorId , negatorId , false );
570568
571569 return address ;
572570}
@@ -639,125 +637,125 @@ get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
639637 * OperatorUpd
640638 *
641639 * For a given operator, look up its negator and commutator operators.
642- * If they are defined, but their negator and commutator fields
643- * (respectively) are empty, then use the new operator for neg or comm.
644- * This solves a problem for users who need to insert two new operators
645- * which are the negator or commutator of each other.
640+ * When isDelete is false, update their negator and commutator fields to
641+ * point back to the given operator; when isDelete is true, update those
642+ * fields to no longer point back to the given operator.
643+ *
644+ * The !isDelete case solves a problem for users who need to insert two new
645+ * operators that are the negator or commutator of each other, while the
646+ * isDelete case is needed so as not to leave dangling OID links behind
647+ * after dropping an operator.
646648 */
647- static void
648- OperatorUpd (Oid baseId , Oid commId , Oid negId )
649+ void
650+ OperatorUpd (Oid baseId , Oid commId , Oid negId , bool isDelete )
649651{
650- int i ;
651652 Relation pg_operator_desc ;
652653 HeapTuple tup ;
653- bool nulls [Natts_pg_operator ];
654- bool replaces [Natts_pg_operator ];
655- Datum values [Natts_pg_operator ];
656-
657- for (i = 0 ; i < Natts_pg_operator ; ++ i )
658- {
659- values [i ] = (Datum ) 0 ;
660- replaces [i ] = false;
661- nulls [i ] = false;
662- }
663654
664655 /*
665- * check and update the commutator & negator, if necessary
666- *
667- * We need a CommandCounterIncrement here in case of a self-commutator
668- * operator: we'll need to update the tuple that we just inserted .
656+ * If we're making an operator into its own commutator, then we need a
657+ * command-counter increment here, since we've just inserted the tuple
658+ * we're about to update. But when we're dropping an operator, we can
659+ * skip this because we're at the beginning of the command .
669660 */
670- CommandCounterIncrement ();
661+ if (!isDelete )
662+ CommandCounterIncrement ();
671663
664+ /* Open the relation. */
672665 pg_operator_desc = heap_open (OperatorRelationId , RowExclusiveLock );
673666
674- tup = SearchSysCacheCopy1 (OPEROID , ObjectIdGetDatum (commId ));
667+ /* Get a writable copy of the commutator's tuple. */
668+ if (OidIsValid (commId ))
669+ tup = SearchSysCacheCopy1 (OPEROID , ObjectIdGetDatum (commId ));
670+ else
671+ tup = NULL ;
675672
676- /*
677- * if the commutator and negator are the same operator, do one update. XXX
678- * this is probably useless code --- I doubt it ever makes sense for
679- * commutator and negator to be the same thing...
680- */
681- if (commId == negId )
673+ /* Update the commutator's tuple if need be. */
674+ if (HeapTupleIsValid (tup ))
682675 {
683- if (HeapTupleIsValid (tup ))
676+ Form_pg_operator t = (Form_pg_operator ) GETSTRUCT (tup );
677+ bool update_commutator = false;
678+
679+ /*
680+ * Out of due caution, we only change the commutator's oprcom field if
681+ * it has the exact value we expected: InvalidOid when creating an
682+ * operator, or baseId when dropping one.
683+ */
684+ if (isDelete && t -> oprcom == baseId )
684685 {
685- Form_pg_operator t = (Form_pg_operator ) GETSTRUCT (tup );
686-
687- if (!OidIsValid (t -> oprcom ) || !OidIsValid (t -> oprnegate ))
688- {
689- if (!OidIsValid (t -> oprnegate ))
690- {
691- values [Anum_pg_operator_oprnegate - 1 ] = ObjectIdGetDatum (baseId );
692- replaces [Anum_pg_operator_oprnegate - 1 ] = true;
693- }
694-
695- if (!OidIsValid (t -> oprcom ))
696- {
697- values [Anum_pg_operator_oprcom - 1 ] = ObjectIdGetDatum (baseId );
698- replaces [Anum_pg_operator_oprcom - 1 ] = true;
699- }
700-
701- tup = heap_modify_tuple (tup ,
702- RelationGetDescr (pg_operator_desc ),
703- values ,
704- nulls ,
705- replaces );
706-
707- simple_heap_update (pg_operator_desc , & tup -> t_self , tup );
708-
709- CatalogUpdateIndexes (pg_operator_desc , tup );
710- }
686+ t -> oprcom = InvalidOid ;
687+ update_commutator = true;
688+ }
689+ else if (!isDelete && !OidIsValid (t -> oprcom ))
690+ {
691+ t -> oprcom = baseId ;
692+ update_commutator = true;
711693 }
712694
713- heap_close (pg_operator_desc , RowExclusiveLock );
714-
715- return ;
716- }
717-
718- /* if commutator and negator are different, do two updates */
719-
720- if (HeapTupleIsValid (tup ) &&
721- !(OidIsValid (((Form_pg_operator ) GETSTRUCT (tup ))-> oprcom )))
722- {
723- values [Anum_pg_operator_oprcom - 1 ] = ObjectIdGetDatum (baseId );
724- replaces [Anum_pg_operator_oprcom - 1 ] = true;
725-
726- tup = heap_modify_tuple (tup ,
727- RelationGetDescr (pg_operator_desc ),
728- values ,
729- nulls ,
730- replaces );
731-
732- simple_heap_update (pg_operator_desc , & tup -> t_self , tup );
733-
734- CatalogUpdateIndexes (pg_operator_desc , tup );
735-
736- values [Anum_pg_operator_oprcom - 1 ] = (Datum ) NULL ;
737- replaces [Anum_pg_operator_oprcom - 1 ] = false;
695+ /* If any columns were found to need modification, update tuple. */
696+ if (update_commutator )
697+ {
698+ simple_heap_update (pg_operator_desc , & tup -> t_self , tup );
699+ CatalogUpdateIndexes (pg_operator_desc , tup );
700+
701+ /*
702+ * Do CCI to make the updated tuple visible. We must do this in
703+ * case the commutator is also the negator. (Which would be a
704+ * logic error on the operator definer's part, but that's not a
705+ * good reason to fail here.) We would need a CCI anyway in the
706+ * deletion case for a self-commutator with no negator.
707+ */
708+ CommandCounterIncrement ();
709+ }
738710 }
739711
740- /* check and update the negator, if necessary */
741-
742- tup = SearchSysCacheCopy1 (OPEROID , ObjectIdGetDatum (negId ));
712+ /*
713+ * Similarly find and update the negator, if any.
714+ */
715+ if (OidIsValid (negId ))
716+ tup = SearchSysCacheCopy1 (OPEROID , ObjectIdGetDatum (negId ));
717+ else
718+ tup = NULL ;
743719
744- if (HeapTupleIsValid (tup ) &&
745- !(OidIsValid (((Form_pg_operator ) GETSTRUCT (tup ))-> oprnegate )))
720+ if (HeapTupleIsValid (tup ))
746721 {
747- values [ Anum_pg_operator_oprnegate - 1 ] = ObjectIdGetDatum ( baseId );
748- replaces [ Anum_pg_operator_oprnegate - 1 ] = true ;
722+ Form_pg_operator t = ( Form_pg_operator ) GETSTRUCT ( tup );
723+ bool update_negator = false ;
749724
750- tup = heap_modify_tuple (tup ,
751- RelationGetDescr (pg_operator_desc ),
752- values ,
753- nulls ,
754- replaces );
755-
756- simple_heap_update (pg_operator_desc , & tup -> t_self , tup );
725+ /*
726+ * Out of due caution, we only change the negator's oprnegate field if
727+ * it has the exact value we expected: InvalidOid when creating an
728+ * operator, or baseId when dropping one.
729+ */
730+ if (isDelete && t -> oprnegate == baseId )
731+ {
732+ t -> oprnegate = InvalidOid ;
733+ update_negator = true;
734+ }
735+ else if (!isDelete && !OidIsValid (t -> oprnegate ))
736+ {
737+ t -> oprnegate = baseId ;
738+ update_negator = true;
739+ }
757740
758- CatalogUpdateIndexes (pg_operator_desc , tup );
741+ /* If any columns were found to need modification, update tuple. */
742+ if (update_negator )
743+ {
744+ simple_heap_update (pg_operator_desc , & tup -> t_self , tup );
745+ CatalogUpdateIndexes (pg_operator_desc , tup );
746+
747+ /*
748+ * In the deletion case, do CCI to make the updated tuple visible.
749+ * We must do this in case the operator is its own negator. (Which
750+ * would be a logic error on the operator definer's part, but
751+ * that's not a good reason to fail here.)
752+ */
753+ if (isDelete )
754+ CommandCounterIncrement ();
755+ }
759756 }
760757
758+ /* Close relation and release catalog lock. */
761759 heap_close (pg_operator_desc , RowExclusiveLock );
762760}
763761
0 commit comments