vibesql_types/sql_value/
hash.rs

1//! Hash implementation for SqlValue
2
3use std::hash::{Hash, Hasher};
4
5use crate::sql_value::SqlValue;
6
7/// Hash implementation for SqlValue
8///
9/// Custom implementation to handle floating-point values correctly:
10/// - NaN values are treated as equal (hash to same value)
11/// - Uses to_bits() for floats to ensure consistent hashing
12/// - NULL hashes to a specific value
13impl Hash for SqlValue {
14    fn hash<H: Hasher>(&self, state: &mut H) {
15        use SqlValue::*;
16
17        // Hash discriminant first to distinguish variants
18        std::mem::discriminant(self).hash(state);
19
20        match self {
21            Integer(i) => i.hash(state),
22            Smallint(i) => i.hash(state),
23            Bigint(i) => i.hash(state),
24            Unsigned(u) => u.hash(state),
25            Numeric(f) => {
26                if f.is_nan() {
27                    f64::NAN.to_bits().hash(state);
28                } else {
29                    f.to_bits().hash(state);
30                }
31            }
32            // For floats, use to_bits() to get consistent hash for NaN
33            Float(f) => {
34                if f.is_nan() {
35                    // All NaN values hash the same
36                    f32::NAN.to_bits().hash(state);
37                } else {
38                    f.to_bits().hash(state);
39                }
40            }
41            Real(f) => {
42                if f.is_nan() {
43                    f32::NAN.to_bits().hash(state);
44                } else {
45                    f.to_bits().hash(state);
46                }
47            }
48            Double(f) => {
49                if f.is_nan() {
50                    f64::NAN.to_bits().hash(state);
51                } else {
52                    f.to_bits().hash(state);
53                }
54            }
55
56            Character(s) => s.hash(state),
57            Varchar(s) => s.hash(state),
58            Boolean(b) => b.hash(state),
59            Date(s) => s.hash(state),
60            Time(s) => s.hash(state),
61            Timestamp(s) => s.hash(state),
62            Interval(s) => s.hash(state),
63            Vector(v) => {
64                // Hash each f32 value using to_bits() for consistent NaN handling
65                for f in v.iter() {
66                    if f.is_nan() {
67                        f32::NAN.to_bits().hash(state);
68                    } else {
69                        f.to_bits().hash(state);
70                    }
71                }
72            }
73            Blob(b) => b.hash(state),
74
75            // NULL hashes to nothing (discriminant is enough)
76            Null => {}
77        }
78    }
79}