@@ -746,32 +746,46 @@ public bool Equals(SqlValue other) =>
746746 /// responsibility (SQL's NULL-comparison semantics differ from .NET's
747747 /// IComparable convention, so we throw here rather than pick a side).
748748 /// </summary>
749+ /// <remarks>
750+ /// Dispatches on <see cref="SqlType.Category"/> so the hot path is a
751+ /// jump-table-friendly switch rather than the linear type-test chain it
752+ /// replaced. The single-arm collapse for Integer / DateTime / Money relies
753+ /// on the invariant that each type in those categories stores its ordered
754+ /// value directly in <see cref="primitive"/> — Bit's 0/1 sorts as long the
755+ /// same way <see cref="bool.CompareTo(bool)"/> does, all DateTime variants
756+ /// already used <see cref="primitive"/>, and Money/SmallMoney hold scaled
757+ /// integers there. Approximate is the only category that can't unify
758+ /// (the IEEE 754 bit pattern in <see cref="primitive"/> isn't monotonic
759+ /// across the sign bit and mishandles NaN), so it splits Float vs Real.
760+ /// </remarks>
749761 /// <exception cref="InvalidOperationException">Either operand is NULL.</exception>
750762 /// <exception cref="NotSupportedException">The operands' types differ, or comparison for that type isn't implemented yet.</exception>
751763 public int CompareTo ( SqlValue other ) =>
752- this . IsNull || other . IsNull ? throw new InvalidOperationException ( "CompareTo on NULL is undefined; check IsNull before calling." )
753- : this . Type != other . Type ? throw new NotSupportedException ( $ "Cross-type comparison isn't implemented: { this . Type } vs { other . Type } .")
754- : this . Type == SqlType . Int32 ? this . AsInt32 . CompareTo ( other . AsInt32 )
755- : this . Type == SqlType . BigInt ? this . AsInt64 . CompareTo ( other . AsInt64 )
756- : this . Type == SqlType . SmallInt ? this . AsInt16 . CompareTo ( other . AsInt16 )
757- : this . Type == SqlType . TinyInt ? this . AsByte . CompareTo ( other . AsByte )
758- : this . Type == SqlType . Bit ? this . AsBoolean . CompareTo ( other . AsBoolean )
759- : IsStringTypeRef ( this . Type ) ? this . Type . Collation ! . Compare ( TrimTrailing ( ( string ) this . reference ! ) , TrimTrailing ( ( string ) other . reference ! ) )
760- : this . Type is RowVersionSqlType ? this . primitive . CompareTo ( other . primitive )
761- : this . Type is VarbinarySqlType or BinarySqlType or ImageSqlType ? this . AsBytes . AsSpan ( ) . SequenceCompareTo ( other . AsBytes )
762- : this . Type == SqlType . Date ? this . primitive . CompareTo ( other . primitive )
763- : this . Type == SqlType . DateTime ? this . primitive . CompareTo ( other . primitive )
764- : this . Type == SqlType . SmallDateTime ? this . primitive . CompareTo ( other . primitive )
765- : this . Type is DateTime2SqlType ? this . primitive . CompareTo ( other . primitive )
766- : this . Type is TimeSqlType ? this . primitive . CompareTo ( other . primitive )
767- : this . Type is DateTimeOffsetSqlType ? this . primitive . CompareTo ( other . primitive )
768- : this . Type == SqlType . UniqueIdentifier ? new SqlGuid ( this . AsGuid ) . CompareTo ( new SqlGuid ( other . AsGuid ) )
769- : this . Type == SqlType . HierarchyId ? HierarchyIdSqlType . ComparePaths ( this . AsHierarchyId , other . AsHierarchyId )
770- : this . Type is DecimalSqlType ? this . AsDecimal . CompareTo ( other . AsDecimal )
771- : this . Type == SqlType . Float ? this . AsDouble . CompareTo ( other . AsDouble )
772- : this . Type == SqlType . Real ? this . AsSingle . CompareTo ( other . AsSingle )
773- : this . Type == SqlType . Money || this . Type == SqlType . SmallMoney ? this . primitive . CompareTo ( other . primitive )
774- : throw new NotSupportedException ( $ "Comparison for { this . Type } isn't implemented yet.") ;
764+ this . IsNull || other . IsNull
765+ ? throw new InvalidOperationException ( "CompareTo on NULL is undefined; check IsNull before calling." )
766+ : this . Type != other . Type
767+ ? throw new NotSupportedException ( $ "Cross-type comparison isn't implemented: { this . Type } vs { other . Type } .")
768+ : this . Type . Category switch
769+ {
770+ SqlTypeCategory . Integer or SqlTypeCategory . DateTime or SqlTypeCategory . Money
771+ => this . primitive . CompareTo ( other . primitive ) ,
772+ SqlTypeCategory . Decimal => this . AsDecimal . CompareTo ( other . AsDecimal ) ,
773+ SqlTypeCategory . Approximate => this . Type == SqlType . Float
774+ ? this . AsDouble . CompareTo ( other . AsDouble )
775+ : this . AsSingle . CompareTo ( other . AsSingle ) ,
776+ SqlTypeCategory . String => this . Type . Collation ! . Compare (
777+ TrimTrailing ( ( string ) this . reference ! ) ,
778+ TrimTrailing ( ( string ) other . reference ! ) ) ,
779+ SqlTypeCategory . UniqueIdentifier => new SqlGuid ( this . AsGuid ) . CompareTo ( new SqlGuid ( other . AsGuid ) ) ,
780+ SqlTypeCategory . Other => this . Type switch
781+ {
782+ VarbinarySqlType or BinarySqlType or ImageSqlType => this . AsBytes . AsSpan ( ) . SequenceCompareTo ( other . AsBytes ) ,
783+ RowVersionSqlType => this . primitive . CompareTo ( other . primitive ) ,
784+ HierarchyIdSqlType => HierarchyIdSqlType . ComparePaths ( this . AsHierarchyId , other . AsHierarchyId ) ,
785+ _ => throw new NotSupportedException ( $ "Comparison for { this . Type } isn't implemented yet.") ,
786+ } ,
787+ _ => throw new NotSupportedException ( $ "Comparison for { this . Type } isn't implemented yet.") ,
788+ } ;
775789
776790 public override bool Equals ( object ? obj ) => obj is SqlValue other && this . Equals ( other ) ;
777791
0 commit comments