Skip to main content

clt_database/vdbe/
value.rs

1use crate::turso_assert;
2use crate::{
3    function::MathFunc,
4    numeric::{format_float, format_float_for_quote, NullableInteger, Numeric},
5    translate::collate::CollationSeq,
6    types::{compare_immutable_single, AsValueRef, SeekOp},
7    vdbe::affinity::{real_to_i64, Affinity},
8    LimboError, Result, Value, ValueRef,
9};
10
11// we use math functions from Rust stdlib in order to be as portable as possible for the production version of the tursodb
12#[cfg(not(clt_turso_tests))]
13mod cmath {
14    pub fn exp(x: f64) -> f64 {
15        x.exp()
16    }
17    pub fn log(x: f64) -> f64 {
18        x.ln()
19    }
20    pub fn log10(x: f64) -> f64 {
21        x.log(10.)
22    }
23    pub fn log2(x: f64) -> f64 {
24        x.log(2.)
25    }
26    pub fn pow(x: f64, y: f64) -> f64 {
27        x.powf(y)
28    }
29    pub fn sin(x: f64) -> f64 {
30        x.sin()
31    }
32    pub fn sinh(x: f64) -> f64 {
33        x.sinh()
34    }
35    pub fn asin(x: f64) -> f64 {
36        x.asin()
37    }
38    pub fn asinh(x: f64) -> f64 {
39        x.asinh()
40    }
41    pub fn cos(x: f64) -> f64 {
42        x.cos()
43    }
44    pub fn cosh(x: f64) -> f64 {
45        x.cosh()
46    }
47    pub fn acos(x: f64) -> f64 {
48        x.acos()
49    }
50    pub fn acosh(x: f64) -> f64 {
51        x.acosh()
52    }
53    pub fn tan(x: f64) -> f64 {
54        x.tan()
55    }
56    pub fn tanh(x: f64) -> f64 {
57        x.tanh()
58    }
59    pub fn atan(x: f64) -> f64 {
60        x.atan()
61    }
62    pub fn atanh(x: f64) -> f64 {
63        x.atanh()
64    }
65    pub fn atan2(x: f64, y: f64) -> f64 {
66        x.atan2(y)
67    }
68    pub fn degrees(x: f64) -> f64 {
69        x.to_degrees()
70    }
71    pub fn radians(x: f64) -> f64 {
72        x.to_radians()
73    }
74}
75
76// we use exactly same math function as SQLite in tests in order to avoid mismatch in the differential tests due to floating-point precision issues
77#[cfg(clt_turso_tests)]
78mod cmath {
79    extern "C" {
80        pub fn exp(x: f64) -> f64;
81        pub fn log(x: f64) -> f64;
82        pub fn log10(x: f64) -> f64;
83        pub fn log2(x: f64) -> f64;
84        pub fn pow(x: f64, y: f64) -> f64;
85
86        pub fn sin(x: f64) -> f64;
87        pub fn sinh(x: f64) -> f64;
88        pub fn asin(x: f64) -> f64;
89        pub fn asinh(x: f64) -> f64;
90
91        pub fn cos(x: f64) -> f64;
92        pub fn cosh(x: f64) -> f64;
93        pub fn acos(x: f64) -> f64;
94        pub fn acosh(x: f64) -> f64;
95
96        pub fn tan(x: f64) -> f64;
97        pub fn tanh(x: f64) -> f64;
98        pub fn atan(x: f64) -> f64;
99        pub fn atanh(x: f64) -> f64;
100        pub fn atan2(x: f64, y: f64) -> f64;
101    }
102
103    // SQLite's M_PI constant (same value as SQLite's func.c)
104    #[allow(clippy::excessive_precision)]
105    const M_PI: f64 = 3.141592653589793238462643383279502884;
106
107    pub fn degrees(x: f64) -> f64 {
108        x * 180.0 / M_PI
109    }
110    pub fn radians(x: f64) -> f64 {
111        x * M_PI / 180.0
112    }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq)]
116pub(super) enum ComparisonOp {
117    Eq,
118    Ne,
119    Lt,
120    Le,
121    Gt,
122    Ge,
123}
124
125impl ComparisonOp {
126    pub(super) fn compare<V1: AsValueRef, V2: AsValueRef>(
127        &self,
128        lhs: V1,
129        rhs: V2,
130        collation: CollationSeq,
131    ) -> bool {
132        let order = compare_immutable_single(lhs, rhs, collation);
133        match self {
134            ComparisonOp::Eq => order.is_eq(),
135            ComparisonOp::Ne => order.is_ne(),
136            ComparisonOp::Lt => order.is_lt(),
137            ComparisonOp::Le => order.is_le(),
138            ComparisonOp::Gt => order.is_gt(),
139            ComparisonOp::Ge => order.is_ge(),
140        }
141    }
142
143    pub(super) fn compare_nulls<V1: AsValueRef, V2: AsValueRef>(
144        &self,
145        lhs: V1,
146        rhs: V2,
147        null_eq: bool,
148    ) -> bool {
149        let (lhs, rhs) = (lhs.as_value_ref(), rhs.as_value_ref());
150        turso_assert!(matches!(lhs, ValueRef::Null) || matches!(rhs, ValueRef::Null));
151
152        match self {
153            ComparisonOp::Eq => {
154                let both_null = lhs == rhs;
155                null_eq && both_null
156            }
157            ComparisonOp::Ne => {
158                let at_least_one_null = lhs != rhs;
159                null_eq && at_least_one_null
160            }
161            ComparisonOp::Lt | ComparisonOp::Le | ComparisonOp::Gt | ComparisonOp::Ge => false,
162        }
163    }
164}
165
166impl From<SeekOp> for ComparisonOp {
167    fn from(value: SeekOp) -> Self {
168        match value {
169            SeekOp::GE { eq_only: true } | SeekOp::LE { eq_only: true } => ComparisonOp::Eq,
170            SeekOp::GE { eq_only: false } => ComparisonOp::Ge,
171            SeekOp::GT => ComparisonOp::Gt,
172            SeekOp::LE { eq_only: false } => ComparisonOp::Le,
173            SeekOp::LT => ComparisonOp::Lt,
174        }
175    }
176}
177
178#[inline]
179fn sqlite_text_prefix(s: &str) -> &str {
180    match s.find('\0') {
181        Some(idx) => &s[..idx],
182        None => s,
183    }
184}
185
186enum TrimType {
187    All,
188    Left,
189    Right,
190}
191
192impl Value {
193    pub fn exec_lower(&self) -> Option<Self> {
194        self.cast_text()
195            .map(|s| Value::build_text(s.to_ascii_lowercase()))
196    }
197
198    pub fn exec_length(&self) -> Self {
199        match self {
200            Value::Text(t) => {
201                Value::from_i64(sqlite_text_prefix(t.as_str()).chars().count() as i64)
202            }
203            Value::Numeric(_) => {
204                // For numbers, SQLite returns the length of the string representation
205                Value::from_i64(self.to_string().chars().count() as i64)
206            }
207            Value::Blob(blob) => Value::from_i64(blob.len() as i64),
208            _ => self.to_owned(),
209        }
210    }
211
212    pub fn exec_octet_length(&self) -> Self {
213        match self {
214            Value::Text(s) => Value::from_i64(s.as_str().len() as i64),
215            Value::Blob(blob) => Value::from_i64(blob.len() as i64),
216            Value::Numeric(_) => Value::from_i64(self.to_string().len() as i64),
217            _ => self.to_owned(),
218        }
219    }
220
221    pub fn exec_upper(&self) -> Option<Self> {
222        self.cast_text()
223            .map(|s| Value::build_text(s.to_ascii_uppercase()))
224    }
225
226    pub fn exec_sign(&self) -> Option<Value> {
227        let v = Numeric::from_value_strict(self).map(|value| value.to_f64())?;
228
229        Some(Value::from_i64(if v > 0.0 {
230            1
231        } else if v < 0.0 {
232            -1
233        } else {
234            0
235        }))
236    }
237
238    /// Generates the Soundex code for a given word
239    pub fn exec_soundex(&self) -> Value {
240        let s = match self {
241            Value::Text(s) => s.as_str(),
242            Value::Null => return Value::build_text("?000"),
243            _ => return Value::build_text("?000"),
244        };
245
246        if s.bytes().any(|b| !b.is_ascii_alphabetic()) {
247            return Value::build_text("?000");
248        }
249
250        let mut bytes = s.bytes();
251        let Some(first_char) = bytes.next() else {
252            return Value::build_text("?000");
253        };
254
255        let first_upper = first_char.to_ascii_uppercase();
256        let mut result = String::with_capacity(4);
257        result.push(first_upper as char);
258        let get_code = |b: u8| -> Option<char> {
259            match b.to_ascii_lowercase() {
260                b'b' | b'f' | b'p' | b'v' => Some('1'),
261                b'c' | b'g' | b'j' | b'k' | b'q' | b's' | b'x' | b'z' => Some('2'),
262                b'd' | b't' => Some('3'),
263                b'l' => Some('4'),
264                b'm' | b'n' => Some('5'),
265                b'r' => Some('6'),
266                _ => None, // a, e, i, o, u, y, h, w
267            }
268        };
269
270        let mut prev_code = get_code(first_char);
271
272        for b in bytes {
273            if result.len() >= 4 {
274                break;
275            }
276
277            // H and W are ignored completely in this step for continuity checks
278            let lower = b.to_ascii_lowercase();
279            if lower == b'h' || lower == b'w' {
280                continue;
281            }
282
283            let code = get_code(b);
284            if code.is_some() && code != prev_code {
285                result.push(code.unwrap());
286                prev_code = code;
287            } else if code.is_none() {
288                // Reset previous code for vowels/separators (a,e,i,o,u,y)
289                prev_code = None;
290            }
291        }
292
293        while result.len() < 4 {
294            result.push('0');
295        }
296
297        Value::build_text(result)
298    }
299
300    pub fn exec_abs(&self) -> Result<Self> {
301        Ok(match self {
302            Value::Null => Value::Null,
303            Value::Numeric(Numeric::Integer(v)) => {
304                Value::from_i64(v.checked_abs().ok_or(LimboError::IntegerOverflow)?)
305            }
306            Value::Numeric(Numeric::Float(non_nan)) => Value::from_f64(f64::from(*non_nan).abs()),
307            _ => {
308                let s = match self {
309                    Value::Text(text) => std::borrow::Cow::Borrowed(text.as_str()),
310                    Value::Blob(blob) => String::from_utf8_lossy(blob),
311                    _ => unreachable!(),
312                };
313
314                crate::numeric::str_to_f64(s)
315                    .map(|v| Value::from_f64(f64::from(v).abs()))
316                    .unwrap_or_else(|| Value::from_f64(0.0))
317            }
318        })
319    }
320
321    pub fn exec_random<F>(generate_random_number: F) -> Self
322    where
323        F: Fn() -> i64,
324    {
325        Value::from_i64(generate_random_number())
326    }
327
328    /// SQLite default max blob/string size (1GB)
329    pub const MAX_BLOB_LENGTH: i64 = 1_000_000_000;
330
331    pub fn exec_randomblob<F>(&self, fill_bytes: F) -> Result<Value>
332    where
333        F: Fn(&mut [u8]),
334    {
335        let length = match self {
336            Value::Numeric(Numeric::Integer(i)) => *i,
337            Value::Numeric(Numeric::Float(f)) => f64::from(*f) as i64,
338            Value::Text(t) => t.as_str().parse().unwrap_or(1),
339            _ => 1,
340        }
341        .max(1);
342
343        if length > Self::MAX_BLOB_LENGTH {
344            return Err(LimboError::TooBig);
345        }
346
347        let mut blob: Vec<u8> = vec![0; length as usize];
348        fill_bytes(&mut blob);
349        Ok(Value::Blob(blob))
350    }
351
352    pub fn exec_quote(&self) -> Self {
353        use std::fmt::Write;
354        match self {
355            Value::Null => Value::build_text("NULL"),
356            Value::Numeric(Numeric::Integer(i)) => Value::build_text(i.to_string()),
357            Value::Numeric(Numeric::Float(f)) => {
358                Value::build_text(format_float_for_quote(f64::from(*f)))
359            }
360            Value::Blob(b) => {
361                // SQLite returns X'hexdigits' for blobs
362                let mut quoted = String::with_capacity(3 + b.len() * 2);
363                quoted.push_str("X'");
364                for byte in b.iter() {
365                    write!(&mut quoted, "{byte:02X}").expect("unable to write hex bytes");
366                }
367                quoted.push('\'');
368                Value::build_text(quoted)
369            }
370            Value::Text(s) => {
371                let mut quoted = String::with_capacity(s.as_str().len() + 2);
372                quoted.push('\'');
373                for c in s.as_str().chars() {
374                    if c == '\0' {
375                        break;
376                    } else if c == '\'' {
377                        quoted.push('\'');
378                        quoted.push(c);
379                    } else {
380                        quoted.push(c);
381                    }
382                }
383                quoted.push('\'');
384                Value::build_text(quoted)
385            }
386        }
387    }
388
389    pub fn exec_unistr_quote(&self) -> Self {
390        const HEX: &[u8; 16] = b"0123456789abcdef";
391
392        match self {
393            Value::Text(s) => {
394                let s = s.as_str();
395                let mut end = s.len();
396                let mut has_ctrl = false;
397
398                for (i, &b) in s.as_bytes().iter().enumerate() {
399                    match b {
400                        0 => {
401                            end = i;
402                            break;
403                        }
404                        1..=0x1f => has_ctrl = true,
405                        _ => {}
406                    }
407                }
408
409                if !has_ctrl {
410                    return self.exec_quote();
411                }
412
413                let prefix = &s[..end];
414                let mut extra = 0;
415                for &b in prefix.as_bytes() {
416                    extra += match b {
417                        1..=0x1f => 5, // \u00xx is 6 output bytes, replacing 1 input byte.
418                        b'\\' | b'\'' => 1,
419                        _ => 0,
420                    };
421                }
422
423                let mut out = String::with_capacity(prefix.len() + extra + "unistr('')".len());
424                out.push_str("unistr('");
425                for c in prefix.chars() {
426                    match c {
427                        '\x01'..='\x1f' => {
428                            let b = c as u8;
429                            out.push('\\');
430                            out.push('u');
431                            out.push('0');
432                            out.push('0');
433                            out.push(HEX[(b >> 4) as usize] as char);
434                            out.push(HEX[(b & 0x0f) as usize] as char);
435                        }
436                        '\\' => out.push_str("\\\\"),
437                        '\'' => out.push_str("''"),
438                        _ => out.push(c),
439                    }
440                }
441                out.push_str("')");
442                Value::build_text(out)
443            }
444            _ => self.exec_quote(),
445        }
446    }
447
448    pub fn exec_nullif(&self, second_value: &Self) -> Self {
449        if self != second_value {
450            self.clone()
451        } else {
452            Value::Null
453        }
454    }
455
456    pub fn exec_substring(
457        value: &Value,
458        start_value: &Value,
459        length_value: Option<&Value>,
460    ) -> Value {
461        /// Function is stabilized but not released for version 1.88 \
462        /// https://doc.rust-lang.org/src/core/str/mod.rs.html#453
463        const fn ceil_char_boundary(s: &str, index: usize) -> usize {
464            const fn is_utf8_char_boundary(c: u8) -> bool {
465                // This is bit magic equivalent to: b < 128 || b >= 192
466                (c as i8) >= -0x40
467            }
468
469            if index >= s.len() {
470                s.len()
471            } else {
472                let mut i = index;
473                while i < s.len() {
474                    if is_utf8_char_boundary(s.as_bytes()[i]) {
475                        break;
476                    }
477                    i += 1;
478                }
479
480                //  The character boundary will be within four bytes of the index
481                debug_assert!(i <= index + 3);
482
483                i
484            }
485        }
486
487        // Match SQLite's substr algorithm exactly (func.c substrFunc)
488        // Uses wrapping arithmetic to match C overflow behavior
489        fn calculate_postions(
490            mut p1: i64,
491            len: usize,
492            length_value: Option<&Value>,
493        ) -> (usize, usize) {
494            let len = len as i64;
495            let mut p2 = match length_value {
496                Some(Value::Numeric(Numeric::Integer(length))) => *length,
497                // SQLite uses SQLITE_LIMIT_LENGTH (default 1 billion) when no explicit length.
498                // Using len causes wrong results when p1 is large negative number.
499                _ => Value::MAX_BLOB_LENGTH,
500            };
501
502            // Track if length was explicitly provided
503            let explicit_length = length_value.is_some();
504
505            // Handle negative start position (count from end)
506            if p1 < 0 {
507                p1 = p1.wrapping_add(len);
508                if p1 < 0 {
509                    if p2 < 0 {
510                        p2 = 0;
511                    } else {
512                        p2 += p1;
513                    }
514                    p1 = 0;
515                }
516            } else if p1 > 0 {
517                p1 -= 1; // Convert 1-indexed to 0-indexed
518            } else if p2 > 0 && explicit_length {
519                // SQLite quirk: when p1==0, p2>0, and explicit length, decrement p2
520                // This means substr('x', 0, 3) returns 2 chars, not 3
521                // But substr('x', 0) with no length returns whole string
522                p2 -= 1;
523            }
524
525            // Handle negative length (characters preceding position)
526            if p2 < 0 {
527                if p2 < -p1 {
528                    p2 = p1;
529                } else {
530                    p2 = -p2;
531                }
532                p1 -= p2;
533            }
534
535            // Clamp to valid range
536            let start = p1.max(0).min(len) as usize;
537            let end = p1.saturating_add(p2).max(0).min(len) as usize;
538            (start, end)
539        }
540
541        let start_value = start_value.exec_cast("INT");
542        let length_value = length_value.map(|value| value.exec_cast("INT"));
543
544        // If length is explicitly NULL, return NULL (SQLite behavior)
545        if matches!(length_value, Some(Value::Null)) {
546            return Value::Null;
547        }
548
549        match (value, start_value) {
550            (Value::Blob(b), Value::Numeric(Numeric::Integer(start))) => {
551                let (start, end) = calculate_postions(start, b.len(), length_value.as_ref());
552                Value::from_blob(b[start..end].to_vec())
553            }
554            (value, Value::Numeric(Numeric::Integer(start))) => {
555                if let Some(text) = value.cast_text() {
556                    let s = sqlite_text_prefix(text.as_str());
557                    // Use character count to accurately resolve negative offsets in UTF-8 strings
558                    let char_count = s.chars().count();
559                    let (mut start, mut end) =
560                        calculate_postions(start, char_count, length_value.as_ref());
561
562                    // https://github.com/sqlite/sqlite/blob/a248d84f/src/func.c#L417
563                    let mut start_byte_idx = 0;
564                    end -= start;
565                    while start > 0 {
566                        start_byte_idx = ceil_char_boundary(s, start_byte_idx + 1);
567                        start -= 1;
568                    }
569                    let mut end_byte_idx = start_byte_idx;
570                    while end > 0 {
571                        end_byte_idx = ceil_char_boundary(s, end_byte_idx + 1);
572                        end -= 1;
573                    }
574                    Value::build_text(s[start_byte_idx..end_byte_idx].to_string())
575                } else {
576                    Value::Null
577                }
578            }
579            _ => Value::Null,
580        }
581    }
582
583    pub fn exec_instr(&self, pattern: &Value) -> Value {
584        if self == &Value::Null || pattern == &Value::Null {
585            return Value::Null;
586        }
587
588        if let (Value::Blob(reg), Value::Blob(pattern)) = (self, pattern) {
589            // SQLite returns 1 for empty pattern (found at position 1)
590            if pattern.is_empty() {
591                return Value::from_i64(1);
592            }
593            let result = reg
594                .windows(pattern.len())
595                .position(|window| window == *pattern)
596                .map_or(0, |i| i + 1);
597            return Value::from_i64(result as i64);
598        }
599
600        let reg_str;
601        let reg = match self {
602            Value::Text(s) => s.as_str(),
603            _ => {
604                reg_str = self.to_string();
605                reg_str.as_str()
606            }
607        };
608
609        let pattern_str;
610        let pattern = match pattern {
611            Value::Text(s) => s.as_str(),
612            _ => {
613                pattern_str = pattern.to_string();
614                pattern_str.as_str()
615            }
616        };
617
618        match reg.find(pattern) {
619            Some(byte_pos) => {
620                // Convert byte position to character position (1-indexed)
621                let char_pos = reg[..byte_pos].chars().count() + 1;
622                Value::from_i64(char_pos as i64)
623            }
624            None => Value::from_i64(0),
625        }
626    }
627
628    pub fn exec_typeof(&self) -> Value {
629        match self {
630            Value::Null => Value::build_text("null"),
631            Value::Numeric(Numeric::Integer(_)) => Value::build_text("integer"),
632            Value::Numeric(Numeric::Float(_)) => Value::build_text("real"),
633            Value::Text(_) => Value::build_text("text"),
634            Value::Blob(_) => Value::build_text("blob"),
635        }
636    }
637
638    pub fn exec_hex(&self) -> Value {
639        match self {
640            Value::Text(_) | Value::Numeric(_) => {
641                let text = self.to_string();
642                Value::build_text(hex::encode_upper(text))
643            }
644            Value::Blob(blob_bytes) => Value::build_text(hex::encode_upper(blob_bytes)),
645            Value::Null => Value::build_text(""),
646        }
647    }
648
649    pub fn exec_unhex(&self, ignored_chars: Option<&Value>) -> Value {
650        match self {
651            Value::Null => Value::Null,
652            _ => match ignored_chars {
653                None => match self
654                    .cast_text()
655                    .map(|s| hex::decode(&s[0..s.find('\0').unwrap_or(s.len())]))
656                {
657                    Some(Ok(bytes)) => Value::Blob(bytes),
658                    _ => Value::Null,
659                },
660                Some(ignore) => match ignore {
661                    Value::Text(_) => {
662                        let input = self.to_string();
663                        let ignore = ignore.to_string();
664                        let mut chars = input.chars().peekable();
665                        let mut out = Vec::with_capacity(input.len() / 2);
666
667                        let is_sep = |c: char| ignore.contains(c) && !c.is_ascii_hexdigit();
668
669                        loop {
670                            while let Some(&c) = chars.peek() {
671                                if is_sep(c) {
672                                    chars.next();
673                                } else {
674                                    break;
675                                }
676                            }
677
678                            let Some(c1) = chars.next() else {
679                                return Value::Blob(out);
680                            };
681                            let Some(hi) = c1.to_digit(16) else {
682                                return Value::Null;
683                            };
684
685                            let Some(c2) = chars.next() else {
686                                return Value::Null;
687                            };
688                            let Some(lo) = c2.to_digit(16) else {
689                                return Value::Null;
690                            };
691
692                            out.push(((hi << 4) | lo) as u8);
693                        }
694                    }
695                    _ => Value::Null,
696                },
697            },
698        }
699    }
700
701    pub fn exec_unicode(&self) -> Value {
702        match self {
703            Value::Text(_) | Value::Numeric(_) | Value::Blob(_) => {
704                let text = self.to_string();
705                if let Some(first_char) = text.chars().next() {
706                    if first_char == '\0' {
707                        return Value::Null;
708                    }
709                    Value::from_i64(first_char as u32 as i64)
710                } else {
711                    Value::Null
712                }
713            }
714            _ => Value::Null,
715        }
716    }
717
718    pub fn exec_unistr(&self) -> Result<Value> {
719        let text = match self {
720            Value::Text(t) => std::borrow::Cow::Borrowed(t.as_str()),
721            Value::Numeric(_) | Value::Blob(_) => std::borrow::Cow::Owned(self.to_string()),
722            _ => return Ok(Value::Null),
723        };
724        let bytes = text.as_bytes();
725        let len = bytes.len();
726        let mut out = String::with_capacity(len);
727        let mut i = 0;
728
729        while i < len {
730            if bytes[i] != b'\\' {
731                let start = i;
732                while i < len && bytes[i] != b'\\' {
733                    i += 1;
734                }
735                out.push_str(&text[start..i]);
736                continue;
737            }
738
739            let v = match bytes.get(i + 1) {
740                Some(b'\\') => {
741                    out.push('\\');
742                    i += 2;
743                    continue;
744                }
745                Some(b) if b.is_ascii_hexdigit() => {
746                    let v = parse_n_hex(&bytes[i + 1..], 4)?;
747                    i += 5;
748                    v
749                }
750                Some(b'+') => {
751                    let v = parse_n_hex(&bytes[i + 2..], 6)?;
752                    i += 8;
753                    v
754                }
755                Some(b'u') => {
756                    let v = parse_n_hex(&bytes[i + 2..], 4)?;
757                    i += 6;
758                    v
759                }
760                Some(b'U') => {
761                    let v = parse_n_hex(&bytes[i + 2..], 8)?;
762                    i += 10;
763                    v
764                }
765                _ => return Err(LimboError::ParseError("invalid Unicode escape".to_string())),
766            };
767
768            // Reject surrogates and values above U+10FFFF. SQLite encodes
769            // these as raw bytes, but Value::Text requires valid UTF-8.
770            let ch = char::from_u32(v)
771                .ok_or_else(|| LimboError::ParseError("invalid Unicode escape".to_string()))?;
772            out.push(ch);
773        }
774
775        Ok(Value::build_text(out))
776    }
777
778    pub fn exec_round(&self, precision: Option<&Value>) -> Value {
779        let Some(f) = Numeric::from_value(self).map(|v| v.to_f64()) else {
780            return Value::Null;
781        };
782
783        let precision = match precision.map(|v| Numeric::from_value(v).map(|v| v.to_f64())) {
784            None => 0.0,
785            Some(Some(v)) => v,
786            Some(None) => return Value::Null,
787        };
788
789        if !(-4503599627370496.0..=4503599627370496.0).contains(&f) {
790            return Value::from_f64(f);
791        }
792
793        let precision = if precision < 1.0 { 0.0 } else { precision };
794        let precision = precision.clamp(0.0, 30.0) as usize;
795
796        if precision == 0 {
797            return Value::from_f64(((f + if f < 0.0 { -0.5 } else { 0.5 }) as i64) as f64);
798        }
799
800        let f: f64 = crate::numeric::str_to_f64(format!("{f:.precision$}"))
801            .expect("formatted float should always parse successfully")
802            .into();
803
804        Value::from_f64(f)
805    }
806
807    fn _exec_trim(&self, pattern: Option<&Value>, trim_type: TrimType) -> Value {
808        let text_cow = match self {
809            Value::Text(s) => std::borrow::Cow::Borrowed(s.as_str()),
810            Value::Null => return Value::Null,
811            _ => std::borrow::Cow::Owned(self.to_string()),
812        };
813        let trimmed = match pattern {
814            Some(p) => {
815                if matches!(p, Value::Null) {
816                    return Value::Null;
817                }
818                let pat_cow = match p {
819                    Value::Text(s) => std::borrow::Cow::Borrowed(s.as_str()),
820                    _ => std::borrow::Cow::Owned(p.to_string()),
821                };
822                let p_str = pat_cow.as_ref();
823                match trim_type {
824                    TrimType::All => text_cow.trim_matches(|c| p_str.contains(c)),
825                    TrimType::Left => text_cow.trim_start_matches(|c| p_str.contains(c)),
826                    TrimType::Right => text_cow.trim_end_matches(|c| p_str.contains(c)),
827                }
828            }
829            None => match trim_type {
830                TrimType::All => text_cow.trim_matches(' '),
831                TrimType::Left => text_cow.trim_start_matches(' '),
832                TrimType::Right => text_cow.trim_end_matches(' '),
833            },
834        };
835        Value::build_text(trimmed.to_string())
836    }
837
838    // Implements TRIM pattern matching.
839    pub fn exec_trim(&self, pattern: Option<&Value>) -> Value {
840        self._exec_trim(pattern, TrimType::All)
841    }
842    // Implements RTRIM pattern matching.
843    pub fn exec_rtrim(&self, pattern: Option<&Value>) -> Value {
844        self._exec_trim(pattern, TrimType::Right)
845    }
846
847    // Implements LTRIM pattern matching.
848    pub fn exec_ltrim(&self, pattern: Option<&Value>) -> Value {
849        self._exec_trim(pattern, TrimType::Left)
850    }
851
852    pub fn exec_zeroblob(&self) -> Result<Value> {
853        let length: i64 = match self {
854            Value::Numeric(Numeric::Integer(i)) => *i,
855            Value::Numeric(Numeric::Float(f)) => f64::from(*f) as i64,
856            Value::Text(s) => s.as_str().parse().unwrap_or(0),
857            _ => 0,
858        }
859        .max(0);
860
861        if length > Self::MAX_BLOB_LENGTH {
862            return Err(LimboError::TooBig);
863        }
864
865        Ok(Value::Blob(vec![0; length as usize]))
866    }
867
868    // exec_if returns whether you should jump
869    pub fn exec_if(&self, jump_if_null: bool, not: bool) -> bool {
870        Numeric::from_value(self)
871            .map(|v| v.to_bool())
872            .map(|jump| if not { !jump } else { jump })
873            .unwrap_or(jump_if_null)
874    }
875
876    pub fn exec_cast(&self, datatype: &str) -> Value {
877        if matches!(self, Value::Null) {
878            return Value::Null;
879        }
880        match Affinity::affinity(datatype) {
881            // NONE	Casting a value to a type-name with no affinity causes the value to be converted into a BLOB. Casting to a BLOB consists of first casting the value to TEXT in the encoding of the database connection, then interpreting the resulting byte sequence as a BLOB instead of as TEXT.
882            // Historically called NONE, but it's the same as BLOB
883            Affinity::Blob => {
884                if let Value::Blob(blob) = self {
885                    return Value::Blob(blob.clone());
886                }
887                // Convert to TEXT first, then interpret as BLOB
888                // TODO: handle encoding
889                let text = self.to_string();
890                Value::Blob(text.into_bytes())
891            }
892            // TEXT To cast a BLOB value to TEXT, the sequence of bytes that make up the BLOB is interpreted as text encoded using the database encoding.
893            // Casting an INTEGER or REAL value into TEXT renders the value as if via sqlite3_snprintf() except that the resulting TEXT uses the encoding of the database connection.
894            Affinity::Text => {
895                // Convert everything to text representation
896                // TODO: handle encoding and whatever sqlite3_snprintf does
897                Value::build_text(self.to_string())
898            }
899            Affinity::Real => match self {
900                Value::Blob(b) => {
901                    let text = String::from_utf8_lossy(b);
902                    Value::from_f64(
903                        crate::numeric::str_to_f64(&text)
904                            .map(f64::from)
905                            .unwrap_or(0.0),
906                    )
907                }
908                Value::Text(t) => {
909                    Value::from_f64(crate::numeric::str_to_f64(t).map(f64::from).unwrap_or(0.0))
910                }
911                Value::Numeric(Numeric::Integer(i)) => Value::from_f64(*i as f64),
912                Value::Numeric(Numeric::Float(f)) => Value::Numeric(Numeric::Float(*f)),
913                _ => Value::from_f64(0.0),
914            },
915            Affinity::Integer => match self {
916                Value::Blob(b) => {
917                    // Convert BLOB to TEXT first
918                    let text = String::from_utf8_lossy(b);
919                    Value::from_i64(crate::numeric::str_to_i64(&text).unwrap_or(0))
920                }
921                Value::Text(t) => Value::from_i64(crate::numeric::str_to_i64(t).unwrap_or(0)),
922                Value::Numeric(Numeric::Integer(i)) => Value::from_i64(*i),
923                // A cast of a REAL value into an INTEGER follows SQLite's sqlite3RealToI64:
924                // truncate toward zero and clamp to i64::MIN/MAX if outside the safe range.
925                Value::Numeric(Numeric::Float(f)) => Value::from_i64(real_to_i64(f64::from(*f))),
926                _ => Value::from_i64(0),
927            },
928            Affinity::Numeric => match self {
929                Value::Null => Value::Null,
930                Value::Numeric(Numeric::Integer(v)) => Value::from_i64(*v),
931                Value::Numeric(Numeric::Float(v)) => Value::Numeric(Numeric::Float(*v)),
932                _ => {
933                    let s = match self {
934                        Value::Text(text) => text.as_str().into(),
935                        Value::Blob(blob) => String::from_utf8_lossy(blob.as_slice()),
936                        _ => unreachable!(),
937                    };
938                    crate::util::checked_cast_text_to_numeric(&s, false)
939                        .ok()
940                        .unwrap_or_else(|| Value::from_i64(0))
941                }
942            },
943        }
944    }
945
946    pub fn exec_replace(source: &Value, pattern: &Value, replacement: &Value) -> Value {
947        // The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of
948        // string Y in string X. The BINARY collating sequence is used for comparisons. If Y is an empty string
949        // then return X unchanged. If Z is not initially a string, it is cast to a UTF-8 string prior to processing.
950
951        // If any of the arguments is NULL, the result is NULL.
952        if matches!(source, Value::Null)
953            || matches!(pattern, Value::Null)
954            || matches!(replacement, Value::Null)
955        {
956            return Value::Null;
957        }
958
959        let source = source.exec_cast("TEXT");
960        let pattern = pattern.exec_cast("TEXT");
961        let replacement = replacement.exec_cast("TEXT");
962
963        // If any of the casts failed, panic as text casting is not expected to fail.
964        match (&source, &pattern, &replacement) {
965            (Value::Text(source), Value::Text(pattern), Value::Text(replacement)) => {
966                if pattern.as_str().is_empty() || pattern.as_str().starts_with('\0') {
967                    return Value::Text(source.clone());
968                }
969
970                let result = source
971                    .as_str()
972                    .replace(pattern.as_str(), replacement.as_str());
973                Value::build_text(result)
974            }
975            _ => unreachable!("text cast should never fail"),
976        }
977    }
978
979    pub fn exec_math_unary(&self, function: &MathFunc) -> Value {
980        let v = Numeric::from_value_strict(self);
981
982        // In case of some functions and integer input, return the input as is
983        if let Some(Numeric::Integer(i)) = v {
984            if matches!(
985                function,
986                MathFunc::Ceil | MathFunc::Ceiling | MathFunc::Floor | MathFunc::Trunc
987            ) {
988                return Value::from_i64(i);
989            }
990        }
991
992        let Some(f) = v.map(|v| v.to_f64()) else {
993            return Value::Null;
994        };
995
996        if matches!(function, MathFunc::Ln | MathFunc::Log10 | MathFunc::Log2) && f <= 0.0 {
997            return Value::Null;
998        }
999
1000        #[allow(unused_unsafe)]
1001        let result = match function {
1002            MathFunc::Acos => unsafe { cmath::acos(f) },
1003            MathFunc::Acosh => unsafe { cmath::acosh(f) },
1004            MathFunc::Asin => unsafe { cmath::asin(f) },
1005            MathFunc::Asinh => unsafe { cmath::asinh(f) },
1006            MathFunc::Atan => unsafe { cmath::atan(f) },
1007            MathFunc::Atanh => unsafe { cmath::atanh(f) },
1008            MathFunc::Ceil | MathFunc::Ceiling => libm::ceil(f),
1009            MathFunc::Cos => unsafe { cmath::cos(f) },
1010            MathFunc::Cosh => unsafe { cmath::cosh(f) },
1011            MathFunc::Degrees => cmath::degrees(f),
1012            MathFunc::Exp => unsafe { cmath::exp(f) },
1013            MathFunc::Floor => libm::floor(f),
1014            MathFunc::Ln => unsafe { cmath::log(f) },
1015            MathFunc::Log10 => unsafe { cmath::log10(f) },
1016            MathFunc::Log2 => unsafe { cmath::log2(f) },
1017            MathFunc::Radians => cmath::radians(f),
1018            MathFunc::Sin => unsafe { cmath::sin(f) },
1019            MathFunc::Sinh => unsafe { cmath::sinh(f) },
1020            MathFunc::Sqrt => libm::sqrt(f),
1021            MathFunc::Tan => unsafe { cmath::tan(f) },
1022            MathFunc::Tanh => unsafe { cmath::tanh(f) },
1023            MathFunc::Trunc => libm::trunc(f),
1024            _ => unreachable!("Unexpected mathematical unary function {:?}", function),
1025        };
1026
1027        if result.is_nan() {
1028            Value::Null
1029        } else {
1030            Value::from_f64(result)
1031        }
1032    }
1033
1034    pub fn exec_math_binary(&self, rhs: &Value, function: &MathFunc) -> Value {
1035        let Some(lhs) = Numeric::from_value_strict(self).map(|v| v.to_f64()) else {
1036            return Value::Null;
1037        };
1038
1039        let Some(rhs) = Numeric::from_value_strict(rhs).map(|v| v.to_f64()) else {
1040            return Value::Null;
1041        };
1042
1043        #[allow(unused_unsafe)]
1044        let result = match function {
1045            MathFunc::Atan2 => unsafe { cmath::atan2(lhs, rhs) },
1046            MathFunc::Mod => libm::fmod(lhs, rhs),
1047            MathFunc::Pow | MathFunc::Power => unsafe { cmath::pow(lhs, rhs) },
1048            _ => unreachable!("Unexpected mathematical binary function {:?}", function),
1049        };
1050
1051        if result.is_nan() {
1052            Value::Null
1053        } else {
1054            Value::from_f64(result)
1055        }
1056    }
1057
1058    pub fn exec_math_log(&self, base: Option<&Value>) -> Value {
1059        let Some(f) = Numeric::from_value_strict(self).map(|v| v.to_f64()) else {
1060            return Value::Null;
1061        };
1062
1063        let base = match base.map(|value| Numeric::from_value_strict(value).map(|v| v.to_f64())) {
1064            Some(Some(f)) => f,
1065            Some(None) => return Value::Null,
1066            None => 10.0,
1067        };
1068
1069        if f <= 0.0 || base <= 0.0 || base == 1.0 {
1070            return Value::Null;
1071        }
1072
1073        if base == 2.0 {
1074            return Value::from_f64(libm::log2(f));
1075        } else if base == 10.0 {
1076            return Value::from_f64(libm::log10(f));
1077        };
1078
1079        let log_x = libm::log(f);
1080        let log_base = libm::log(base);
1081
1082        if log_base <= 0.0 {
1083            return Value::Null;
1084        }
1085
1086        let result = log_x / log_base;
1087        Value::from_f64(result)
1088    }
1089
1090    pub fn exec_add(&self, rhs: &Value) -> Value {
1091        (|| Numeric::from_value(self)?.checked_add(Numeric::from_value(rhs)?))().into()
1092    }
1093
1094    pub fn exec_subtract(&self, rhs: &Value) -> Value {
1095        (|| Numeric::from_value(self)?.checked_sub(Numeric::from_value(rhs)?))().into()
1096    }
1097
1098    pub fn exec_multiply(&self, rhs: &Value) -> Value {
1099        (|| Numeric::from_value(self)?.checked_mul(Numeric::from_value(rhs)?))().into()
1100    }
1101
1102    pub fn exec_divide(&self, rhs: &Value) -> Value {
1103        (|| Numeric::from_value(self)?.checked_div(Numeric::from_value(rhs)?))().into()
1104    }
1105
1106    pub fn exec_bit_and(&self, rhs: &Value) -> Value {
1107        (NullableInteger::from(self) & NullableInteger::from(rhs)).into()
1108    }
1109
1110    pub fn exec_bit_or(&self, rhs: &Value) -> Value {
1111        (NullableInteger::from(self) | NullableInteger::from(rhs)).into()
1112    }
1113
1114    pub fn exec_remainder(&self, rhs: &Value) -> Value {
1115        let convert_to_float = matches!(Numeric::from_value(self), Some(Numeric::Float(_)))
1116            || matches!(Numeric::from_value(rhs), Some(Numeric::Float(_)));
1117
1118        match NullableInteger::from(self) % NullableInteger::from(rhs) {
1119            NullableInteger::Null => Value::Null,
1120            NullableInteger::Integer(v) => {
1121                if convert_to_float {
1122                    Value::from_f64(v as f64)
1123                } else {
1124                    Value::from_i64(v)
1125                }
1126            }
1127        }
1128    }
1129
1130    pub fn exec_bit_not(&self) -> Value {
1131        (!NullableInteger::from(self)).into()
1132    }
1133
1134    pub fn exec_shift_left(&self, rhs: &Value) -> Value {
1135        (NullableInteger::from(self) << NullableInteger::from(rhs)).into()
1136    }
1137
1138    pub fn exec_shift_right(&self, rhs: &Value) -> Value {
1139        (NullableInteger::from(self) >> NullableInteger::from(rhs)).into()
1140    }
1141
1142    pub fn exec_boolean_not(&self) -> Value {
1143        match Numeric::from_value(self).map(|v| v.to_bool()) {
1144            None => Value::Null,
1145            Some(v) => Value::from_i64(!v as i64),
1146        }
1147    }
1148
1149    pub fn exec_concat(&self, rhs: &Value) -> Value {
1150        if let (Value::Blob(lhs), Value::Blob(rhs)) = (self, rhs) {
1151            return Value::Blob([lhs.as_slice(), rhs.as_slice()].concat());
1152        }
1153
1154        let Some(lhs) = self.cast_text() else {
1155            return Value::Null;
1156        };
1157
1158        let Some(rhs) = rhs.cast_text() else {
1159            return Value::Null;
1160        };
1161
1162        Value::build_text(lhs + &rhs)
1163    }
1164
1165    pub fn exec_and(&self, rhs: &Value) -> Value {
1166        match (
1167            Numeric::from_value(self).map(|v| v.to_bool()),
1168            Numeric::from_value(rhs).map(|v| v.to_bool()),
1169        ) {
1170            (Some(false), _) | (_, Some(false)) => Value::from_i64(0),
1171            (None, _) | (_, None) => Value::Null,
1172            _ => Value::from_i64(1),
1173        }
1174    }
1175
1176    pub fn exec_or(&self, rhs: &Value) -> Value {
1177        match (
1178            Numeric::from_value(self).map(|v| v.to_bool()),
1179            Numeric::from_value(rhs).map(|v| v.to_bool()),
1180        ) {
1181            (Some(true), _) | (_, Some(true)) => Value::from_i64(1),
1182            (None, _) | (_, None) => Value::Null,
1183            _ => Value::from_i64(0),
1184        }
1185    }
1186
1187    pub fn exec_like(pattern: &str, text: &str, escape: Option<char>) -> Result<bool, LimboError> {
1188        const MAX_LIKE_PATTERN_LENGTH: usize = 50000;
1189        if pattern.len() > MAX_LIKE_PATTERN_LENGTH {
1190            return Err(LimboError::Constraint(
1191                "LIKE or GLOB pattern too complex".to_string(),
1192            ));
1193        }
1194        let pattern = sqlite_text_prefix(pattern);
1195        let text = sqlite_text_prefix(text);
1196
1197        let has_escape = escape.is_some_and(|e| pattern.contains(e));
1198
1199        // 1. Exact match (no wildcards)
1200        if !has_escape && !pattern.contains(['%', '_']) {
1201            return Ok(pattern.eq_ignore_ascii_case(text));
1202        }
1203
1204        // 2. Fast Path: 'abc%' (Prefix)
1205        if !has_escape
1206            && pattern.ends_with('%')
1207            && !pattern[..pattern.len() - 1].contains(['%', '_'])
1208        {
1209            let prefix = &pattern[..pattern.len() - 1];
1210            if text.len() >= prefix.len() && text.is_char_boundary(prefix.len()) {
1211                return Ok(text[..prefix.len()].eq_ignore_ascii_case(prefix));
1212            }
1213            // Fall through to pattern_compare if boundary check fails (multi-byte UTF-8)
1214        }
1215
1216        // 3. Fast Path: '%abc' (Suffix)
1217        if !has_escape && pattern.starts_with('%') && !pattern[1..].contains(['%', '_']) {
1218            let suffix = &pattern[1..];
1219            let start = text.len().wrapping_sub(suffix.len());
1220            if text.len() >= suffix.len() && text.is_char_boundary(start) {
1221                return Ok(text[start..].eq_ignore_ascii_case(suffix));
1222            }
1223            // Fall through to pattern_compare if boundary check fails (multi-byte UTF-8)
1224        }
1225
1226        Ok(pattern_compare(pattern, text, &LIKE_INFO, escape) == CompareResult::Match)
1227    }
1228
1229    pub fn exec_glob(pattern: &str, text: &str) -> Result<bool, LimboError> {
1230        const MAX_GLOB_PATTERN_LENGTH: usize = 50000;
1231        const GLOB_CHARS: [char; 3] = ['*', '?', '['];
1232
1233        if pattern.len() > MAX_GLOB_PATTERN_LENGTH {
1234            return Err(LimboError::Constraint(
1235                "GLOB pattern too complex".to_string(),
1236            ));
1237        }
1238        let pattern = sqlite_text_prefix(pattern);
1239        let text = sqlite_text_prefix(text);
1240
1241        // 1. Exact match (no wildcards)
1242        if !pattern.contains(GLOB_CHARS) {
1243            return Ok(pattern == text);
1244        }
1245
1246        // 2. Fast Path: 'abc*' (Prefix)
1247        if pattern.ends_with('*') && !pattern[..pattern.len() - 1].contains(GLOB_CHARS) {
1248            let prefix = &pattern[..pattern.len() - 1];
1249            if text.len() >= prefix.len() && text.is_char_boundary(prefix.len()) {
1250                return Ok(&text[..prefix.len()] == prefix);
1251            }
1252            // Fall through to pattern_compare if boundary check fails (multi-byte UTF-8)
1253        }
1254
1255        // 3. Fast Path: '*abc' (Suffix)
1256        if pattern.starts_with('*') && !pattern[1..].contains(GLOB_CHARS) {
1257            let suffix = &pattern[1..];
1258            let start = text.len().wrapping_sub(suffix.len());
1259            if text.len() >= suffix.len() && text.is_char_boundary(start) {
1260                return Ok(&text[start..] == suffix);
1261            }
1262            // Fall through to pattern_compare if boundary check fails (multi-byte UTF-8)
1263        }
1264
1265        Ok(pattern_compare(pattern, text, &GLOB_INFO, None) == CompareResult::Match)
1266    }
1267
1268    pub fn exec_min<'a, T: Iterator<Item = &'a Value>>(regs: T) -> Value {
1269        // SQLite: multi-arg min() returns NULL if ANY argument is NULL
1270        let mut result: Option<&Value> = None;
1271        for v in regs {
1272            if matches!(v, Value::Null) {
1273                return Value::Null;
1274            }
1275            result = Some(match result {
1276                None => v,
1277                Some(cur) if v < cur => v,
1278                Some(cur) => cur,
1279            });
1280        }
1281        result.map(|v| v.to_owned()).unwrap_or(Value::Null)
1282    }
1283
1284    pub fn exec_max<'a, T: Iterator<Item = &'a Value>>(regs: T) -> Value {
1285        // SQLite: multi-arg max() returns NULL if ANY argument is NULL
1286        let mut result: Option<&Value> = None;
1287        for v in regs {
1288            if matches!(v, Value::Null) {
1289                return Value::Null;
1290            }
1291            result = Some(match result {
1292                None => v,
1293                Some(cur) if v > cur => v,
1294                Some(cur) => cur,
1295            });
1296        }
1297        result.map(|v| v.to_owned()).unwrap_or(Value::Null)
1298    }
1299
1300    /// Concatenate another value onto this Text value, converting both to strings.
1301    /// Used by GROUP_CONCAT/STRING_AGG to properly handle all value types.
1302    /// Panics if self is not a Text value.
1303    pub fn exec_group_concat(&mut self, other: &Value) {
1304        let Value::Text(text) = self else {
1305            panic!("concat_to_text must be called only on Value::Text");
1306        };
1307        text.value.to_mut().push_str(&other.to_string());
1308    }
1309
1310    pub fn exec_concat_strings<'a, T: Iterator<Item = &'a Self>>(registers: T) -> Self {
1311        let mut result = String::new();
1312        for val in registers {
1313            match val {
1314                Value::Null => continue,
1315                Value::Text(s) => result.push_str(s.as_str()),
1316                Value::Blob(b) => result.push_str(&String::from_utf8_lossy(b)),
1317                Value::Numeric(Numeric::Integer(i)) => result.push_str(&i.to_string()),
1318                Value::Numeric(Numeric::Float(f)) => result.push_str(&format_float(f64::from(*f))),
1319            }
1320        }
1321        Value::build_text(result)
1322    }
1323
1324    pub fn exec_concat_ws<'a, T: ExactSizeIterator<Item = &'a Self>>(mut registers: T) -> Self {
1325        if registers.len() == 0 {
1326            return Value::Null;
1327        }
1328
1329        let separator = match registers
1330            .next()
1331            .expect("registers should have at least one element after length check")
1332        {
1333            Value::Null | Value::Blob(_) => return Value::Null,
1334            v => format!("{v}"),
1335        };
1336
1337        let parts = registers.filter_map(|val| match val {
1338            Value::Text(_) | Value::Numeric(_) => Some(format!("{val}")),
1339            _ => None,
1340        });
1341
1342        let result = parts.collect::<Vec<_>>().join(&separator);
1343        Value::build_text(result)
1344    }
1345
1346    pub fn exec_char<'a, T: Iterator<Item = &'a Self>>(values: T) -> Self {
1347        let result: String = values
1348            .filter_map(|x| match x {
1349                Value::Numeric(Numeric::Integer(i)) => {
1350                    // Convert integer to Unicode codepoint.
1351                    // For invalid codepoints (negative, surrogates, or > U+10FFFF),
1352                    // output U+FFFD (replacement character) to match SQLite behavior.
1353                    if *i >= 0 {
1354                        Some(char::from_u32(*i as u32).unwrap_or('\u{FFFD}'))
1355                    } else {
1356                        Some('\u{FFFD}')
1357                    }
1358                }
1359                // NULL arguments produce NUL characters to match SQLite behavior.
1360                Value::Null => Some('\0'),
1361                _ => None,
1362            })
1363            .collect();
1364        Value::build_text(result)
1365    }
1366}
1367
1368/// Parse exactly `n` hex digits into a u32. Mirrors SQLite's isNHex().
1369fn parse_n_hex(bytes: &[u8], n: usize) -> Result<u32> {
1370    if bytes.len() < n {
1371        return Err(LimboError::ParseError("invalid Unicode escape".to_string()));
1372    }
1373    let mut v: u32 = 0;
1374    for &b in &bytes[..n] {
1375        let digit = match b {
1376            b'0'..=b'9' => b - b'0',
1377            b'a'..=b'f' => b - b'a' + 10,
1378            b'A'..=b'F' => b - b'A' + 10,
1379            _ => return Err(LimboError::ParseError("invalid Unicode escape".to_string())),
1380        };
1381        v = (v << 4) | digit as u32;
1382    }
1383    Ok(v)
1384}
1385
1386/// Result of LIKE pattern comparison.
1387/// `NoWildcardMatch` signals an early abort when a literal after `%` cannot be found,
1388/// allowing the algorithm to skip unnecessary backtracking.
1389#[derive(PartialEq)]
1390enum CompareResult {
1391    Match,
1392    NoMatch,
1393    NoWildcardMatch,
1394}
1395
1396struct PatternInfo {
1397    match_all: char,
1398    match_one: char,
1399    match_set: Option<char>,
1400    no_case: bool,
1401}
1402
1403const LIKE_INFO: PatternInfo = PatternInfo {
1404    match_all: '%',
1405    match_one: '_',
1406    match_set: None,
1407    no_case: true,
1408};
1409
1410const GLOB_INFO: PatternInfo = PatternInfo {
1411    match_all: '*',
1412    match_one: '?',
1413    match_set: Some('['),
1414    no_case: false,
1415};
1416
1417/// LIKE and GLOB pattern matching based on SQLite's patternCompare algorithm (src/func.c).
1418/// Uses recursive descent with early termination via `NoWildcardMatch` to avoid
1419/// exponential backtracking on patterns like `%a%a%a%...%b`.
1420/// Ref: https://github.com/sqlite/sqlite/blob/master/src/func.c#L728
1421fn pattern_compare(
1422    pattern: &str,
1423    text: &str,
1424    info: &PatternInfo,
1425    escape: Option<char>,
1426) -> CompareResult {
1427    let mut p_indices = pattern.char_indices();
1428    let mut t_indices = text.char_indices();
1429
1430    let mut p_curr = p_indices.next();
1431    let mut t_curr = t_indices.next();
1432
1433    // Checkpoints for backtracking
1434    let mut wildcard_p_iter: Option<std::str::CharIndices> = None;
1435    let mut wildcard_t_iter: Option<std::str::CharIndices> = None;
1436
1437    loop {
1438        match (p_curr, t_curr) {
1439            (Some((_, p_char)), Some((_, t_char))) => {
1440                if p_char == info.match_all && Some(p_char) != escape {
1441                    // Consume consecutive match_alls
1442                    let mut next_p = p_indices.clone();
1443                    while let Some((_, c)) = next_p.clone().next() {
1444                        if c == info.match_all && Some(c) != escape {
1445                            next_p.next();
1446                        } else {
1447                            break;
1448                        }
1449                    }
1450
1451                    let mut lookahead_p = next_p.clone();
1452                    if let Some((_, next_char)) = lookahead_p.next() {
1453                        let is_wildcard = (next_char == info.match_all
1454                            && Some(next_char) != escape)
1455                            || (next_char == info.match_one && Some(next_char) != escape)
1456                            || (info.match_set == Some(next_char));
1457
1458                        let is_escaped_next = Some(next_char) == escape;
1459
1460                        if !is_wildcard && !is_escaped_next {
1461                            let mut found = false;
1462
1463                            // Check current text char
1464                            if compare_chars(next_char, t_char, info.no_case) {
1465                                found = true;
1466                            } else {
1467                                // Scan remaining text
1468                                let lookahead_t = t_indices.clone();
1469                                for (_, t_c) in lookahead_t {
1470                                    if compare_chars(next_char, t_c, info.no_case) {
1471                                        found = true;
1472                                        break;
1473                                    }
1474                                }
1475                            }
1476
1477                            if !found {
1478                                return CompareResult::NoWildcardMatch;
1479                            }
1480                        }
1481                    }
1482
1483                    p_indices = next_p;
1484                    wildcard_p_iter = Some(p_indices.clone());
1485                    p_curr = p_indices.next();
1486
1487                    if p_curr.is_none() {
1488                        return CompareResult::Match;
1489                    }
1490
1491                    wildcard_t_iter = Some(t_indices.clone());
1492                    continue;
1493                }
1494
1495                if p_char == info.match_one && Some(p_char) != escape {
1496                    p_curr = p_indices.next();
1497                    t_curr = t_indices.next();
1498                    continue;
1499                }
1500
1501                // Handle Set (GLOB only)
1502                if info.match_set == Some(p_char) {
1503                    let mut seen = false;
1504                    let mut invert = false;
1505                    let c = t_char;
1506
1507                    let mut next_c_opt = p_indices.next();
1508
1509                    if let Some((_, c2)) = next_c_opt {
1510                        if c2 == '^' {
1511                            invert = true;
1512                            next_c_opt = p_indices.next();
1513                        }
1514                    }
1515
1516                    let mut c2_opt = next_c_opt;
1517                    if let Some((_, c2)) = c2_opt {
1518                        if c2 == ']' {
1519                            if c == ']' {
1520                                seen = true;
1521                            }
1522                            c2_opt = p_indices.next();
1523                        }
1524                    }
1525
1526                    let mut prior_c: Option<char> = None;
1527
1528                    while let Some((_, c2)) = c2_opt {
1529                        if c2 == ']' {
1530                            break;
1531                        }
1532
1533                        let mut is_range = false;
1534                        if c2 == '-' && prior_c.is_some() {
1535                            let lookahead = p_indices.clone().next();
1536                            if let Some((_, c3)) = lookahead {
1537                                if c3 != ']' {
1538                                    is_range = true;
1539                                    let start = prior_c.unwrap();
1540                                    let end = c3;
1541                                    if c >= start && c <= end {
1542                                        seen = true;
1543                                    }
1544                                    p_indices.next();
1545                                    prior_c = None;
1546                                }
1547                            }
1548                        }
1549
1550                        if !is_range {
1551                            if c == c2 {
1552                                seen = true;
1553                            }
1554                            prior_c = Some(c2);
1555                        }
1556
1557                        c2_opt = p_indices.next();
1558                    }
1559
1560                    if c2_opt.is_none() || !(seen ^ invert) {
1561                        // Fallthrough to backtracking
1562                    } else {
1563                        p_curr = p_indices.next();
1564                        t_curr = t_indices.next();
1565                        continue;
1566                    }
1567                } else {
1568                    let (expected_char, next_p_iter) = if Some(p_char) == escape {
1569                        if let Some((_, literal)) = p_indices.next() {
1570                            (literal, p_indices.clone())
1571                        } else {
1572                            return CompareResult::NoMatch;
1573                        }
1574                    } else {
1575                        (p_char, p_indices.clone())
1576                    };
1577
1578                    if compare_chars(expected_char, t_char, info.no_case) {
1579                        p_indices = next_p_iter;
1580                        p_curr = p_indices.next();
1581                        t_curr = t_indices.next();
1582                        continue;
1583                    }
1584                }
1585            }
1586            (None, None) => return CompareResult::Match,
1587            (Some((_, p_char)), None) if p_char == info.match_all && Some(p_char) != escape => {
1588                let mut temp = p_indices.clone();
1589                loop {
1590                    match temp.next() {
1591                        Some((_, c)) if c == info.match_all && Some(c) != escape => continue,
1592                        None => return CompareResult::Match,
1593                        _ => break,
1594                    }
1595                }
1596            }
1597            _ => {}
1598        }
1599
1600        // Backtracking
1601        if let (Some(wp), Some(wt)) = (wildcard_p_iter.clone(), wildcard_t_iter.clone()) {
1602            p_indices = wp;
1603            p_curr = p_indices.next();
1604            t_indices = wt.clone();
1605            t_curr = t_indices.next();
1606
1607            if t_curr.is_some() {
1608                wildcard_t_iter = Some(t_indices.clone());
1609                continue;
1610            }
1611        }
1612
1613        return CompareResult::NoMatch;
1614    }
1615}
1616
1617fn compare_chars(p: char, t: char, no_case: bool) -> bool {
1618    if no_case {
1619        p.eq_ignore_ascii_case(&t)
1620    } else {
1621        p == t
1622    }
1623}
1624
1625#[cfg(clt_turso_tests)]
1626mod tests {
1627    use crate::numeric::Numeric;
1628    use crate::types::Value;
1629    use crate::vdbe::Register;
1630
1631    use rand::{Rng, RngCore};
1632
1633    #[test]
1634    fn test_exec_add() {
1635        let inputs = vec![
1636            (Value::from_i64(3), Value::from_i64(1)),
1637            (Value::from_f64(3.0), Value::from_f64(1.0)),
1638            (Value::from_f64(3.0), Value::from_i64(1)),
1639            (Value::from_i64(3), Value::from_f64(1.0)),
1640            (Value::Null, Value::Null),
1641            (Value::Null, Value::from_i64(1)),
1642            (Value::Null, Value::from_f64(1.0)),
1643            (Value::Null, Value::Text("2".into())),
1644            (Value::from_i64(1), Value::Null),
1645            (Value::from_f64(1.0), Value::Null),
1646            (Value::Text("1".into()), Value::Null),
1647            (Value::Text("1".into()), Value::Text("3".into())),
1648            (Value::Text("1.0".into()), Value::Text("3.0".into())),
1649            (Value::Text("1.0".into()), Value::from_f64(3.0)),
1650            (Value::Text("1.0".into()), Value::from_i64(3)),
1651            (Value::from_f64(1.0), Value::Text("3.0".into())),
1652            (Value::from_i64(1), Value::Text("3".into())),
1653        ];
1654
1655        let outputs = [
1656            Value::from_i64(4),
1657            Value::from_f64(4.0),
1658            Value::from_f64(4.0),
1659            Value::from_f64(4.0),
1660            Value::Null,
1661            Value::Null,
1662            Value::Null,
1663            Value::Null,
1664            Value::Null,
1665            Value::Null,
1666            Value::Null,
1667            Value::from_i64(4),
1668            Value::from_f64(4.0),
1669            Value::from_f64(4.0),
1670            Value::from_f64(4.0),
1671            Value::from_f64(4.0),
1672            Value::from_f64(4.0),
1673        ];
1674
1675        assert_eq!(
1676            inputs.len(),
1677            outputs.len(),
1678            "Inputs and Outputs should have same size"
1679        );
1680        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1681            assert_eq!(
1682                lhs.exec_add(rhs),
1683                outputs[i],
1684                "Wrong ADD for lhs: {lhs}, rhs: {rhs}"
1685            );
1686        }
1687    }
1688
1689    #[test]
1690    fn test_exec_subtract() {
1691        let inputs = vec![
1692            (Value::from_i64(3), Value::from_i64(1)),
1693            (Value::from_f64(3.0), Value::from_f64(1.0)),
1694            (Value::from_f64(3.0), Value::from_i64(1)),
1695            (Value::from_i64(3), Value::from_f64(1.0)),
1696            (Value::Null, Value::Null),
1697            (Value::Null, Value::from_i64(1)),
1698            (Value::Null, Value::from_f64(1.0)),
1699            (Value::Null, Value::Text("1".into())),
1700            (Value::from_i64(1), Value::Null),
1701            (Value::from_f64(1.0), Value::Null),
1702            (Value::Text("4".into()), Value::Null),
1703            (Value::Text("1".into()), Value::Text("3".into())),
1704            (Value::Text("1.0".into()), Value::Text("3.0".into())),
1705            (Value::Text("1.0".into()), Value::from_f64(3.0)),
1706            (Value::Text("1.0".into()), Value::from_i64(3)),
1707            (Value::from_f64(1.0), Value::Text("3.0".into())),
1708            (Value::from_i64(1), Value::Text("3".into())),
1709        ];
1710
1711        let outputs = [
1712            Value::from_i64(2),
1713            Value::from_f64(2.0),
1714            Value::from_f64(2.0),
1715            Value::from_f64(2.0),
1716            Value::Null,
1717            Value::Null,
1718            Value::Null,
1719            Value::Null,
1720            Value::Null,
1721            Value::Null,
1722            Value::Null,
1723            Value::from_i64(-2),
1724            Value::from_f64(-2.0),
1725            Value::from_f64(-2.0),
1726            Value::from_f64(-2.0),
1727            Value::from_f64(-2.0),
1728            Value::from_f64(-2.0),
1729        ];
1730
1731        assert_eq!(
1732            inputs.len(),
1733            outputs.len(),
1734            "Inputs and Outputs should have same size"
1735        );
1736        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1737            assert_eq!(
1738                lhs.exec_subtract(rhs),
1739                outputs[i],
1740                "Wrong subtract for lhs: {lhs}, rhs: {rhs}"
1741            );
1742        }
1743    }
1744
1745    #[test]
1746    fn test_exec_multiply() {
1747        let inputs = vec![
1748            (Value::from_i64(3), Value::from_i64(2)),
1749            (Value::from_f64(3.0), Value::from_f64(2.0)),
1750            (Value::from_f64(3.0), Value::from_i64(2)),
1751            (Value::from_i64(3), Value::from_f64(2.0)),
1752            (Value::Null, Value::Null),
1753            (Value::Null, Value::from_i64(1)),
1754            (Value::Null, Value::from_f64(1.0)),
1755            (Value::Null, Value::Text("1".into())),
1756            (Value::from_i64(1), Value::Null),
1757            (Value::from_f64(1.0), Value::Null),
1758            (Value::Text("4".into()), Value::Null),
1759            (Value::Text("2".into()), Value::Text("3".into())),
1760            (Value::Text("2.0".into()), Value::Text("3.0".into())),
1761            (Value::Text("2.0".into()), Value::from_f64(3.0)),
1762            (Value::Text("2.0".into()), Value::from_i64(3)),
1763            (Value::from_f64(2.0), Value::Text("3.0".into())),
1764            (Value::from_i64(2), Value::Text("3.0".into())),
1765        ];
1766
1767        let outputs = [
1768            Value::from_i64(6),
1769            Value::from_f64(6.0),
1770            Value::from_f64(6.0),
1771            Value::from_f64(6.0),
1772            Value::Null,
1773            Value::Null,
1774            Value::Null,
1775            Value::Null,
1776            Value::Null,
1777            Value::Null,
1778            Value::Null,
1779            Value::from_i64(6),
1780            Value::from_f64(6.0),
1781            Value::from_f64(6.0),
1782            Value::from_f64(6.0),
1783            Value::from_f64(6.0),
1784            Value::from_f64(6.0),
1785        ];
1786
1787        assert_eq!(
1788            inputs.len(),
1789            outputs.len(),
1790            "Inputs and Outputs should have same size"
1791        );
1792        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1793            assert_eq!(
1794                lhs.exec_multiply(rhs),
1795                outputs[i],
1796                "Wrong multiply for lhs: {lhs}, rhs: {rhs}"
1797            );
1798        }
1799    }
1800
1801    #[test]
1802    fn test_exec_divide() {
1803        let inputs = vec![
1804            (Value::from_i64(1), Value::from_i64(0)),
1805            (Value::from_f64(1.0), Value::from_f64(0.0)),
1806            (Value::from_i64(i64::MIN), Value::from_i64(-1)),
1807            (Value::from_f64(6.0), Value::from_f64(2.0)),
1808            (Value::from_f64(6.0), Value::from_i64(2)),
1809            (Value::from_i64(6), Value::from_i64(2)),
1810            (Value::Null, Value::from_i64(2)),
1811            (Value::from_i64(2), Value::Null),
1812            (Value::Null, Value::Null),
1813            (Value::Text("6".into()), Value::Text("2".into())),
1814            (Value::Text("6".into()), Value::from_i64(2)),
1815        ];
1816
1817        let outputs = [
1818            Value::Null,
1819            Value::Null,
1820            Value::from_f64(9.223372036854776e18),
1821            Value::from_f64(3.0),
1822            Value::from_f64(3.0),
1823            Value::from_f64(3.0),
1824            Value::Null,
1825            Value::Null,
1826            Value::Null,
1827            Value::from_f64(3.0),
1828            Value::from_f64(3.0),
1829        ];
1830
1831        assert_eq!(
1832            inputs.len(),
1833            outputs.len(),
1834            "Inputs and Outputs should have same size"
1835        );
1836        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1837            assert_eq!(
1838                lhs.exec_divide(rhs),
1839                outputs[i],
1840                "Wrong divide for lhs: {lhs}, rhs: {rhs}"
1841            );
1842        }
1843    }
1844
1845    #[test]
1846    fn test_exec_remainder() {
1847        let inputs = vec![
1848            (Value::Null, Value::Null),
1849            (Value::Null, Value::from_f64(1.0)),
1850            (Value::Null, Value::from_i64(1)),
1851            (Value::Null, Value::Text("1".into())),
1852            (Value::from_f64(1.0), Value::Null),
1853            (Value::from_i64(1), Value::Null),
1854            (Value::from_i64(12), Value::from_i64(0)),
1855            (Value::from_f64(12.0), Value::from_f64(0.0)),
1856            (Value::from_f64(12.0), Value::from_i64(0)),
1857            (Value::from_i64(12), Value::from_f64(0.0)),
1858            (Value::from_i64(i64::MIN), Value::from_i64(-1)),
1859            (Value::from_i64(12), Value::from_i64(3)),
1860            (Value::from_f64(12.0), Value::from_f64(3.0)),
1861            (Value::from_f64(12.0), Value::from_i64(3)),
1862            (Value::from_i64(12), Value::from_f64(3.0)),
1863            (Value::from_i64(12), Value::from_i64(-3)),
1864            (Value::from_f64(12.0), Value::from_f64(-3.0)),
1865            (Value::from_f64(12.0), Value::from_i64(-3)),
1866            (Value::from_i64(12), Value::from_f64(-3.0)),
1867            (Value::Text("12.0".into()), Value::Text("3.0".into())),
1868            (Value::Text("12.0".into()), Value::from_f64(3.0)),
1869            (Value::from_f64(12.0), Value::Text("3.0".into())),
1870        ];
1871        let outputs = vec![
1872            Value::Null,
1873            Value::Null,
1874            Value::Null,
1875            Value::Null,
1876            Value::Null,
1877            Value::Null,
1878            Value::Null,
1879            Value::Null,
1880            Value::Null,
1881            Value::Null,
1882            Value::from_f64(0.0),
1883            Value::from_i64(0),
1884            Value::from_f64(0.0),
1885            Value::from_f64(0.0),
1886            Value::from_f64(0.0),
1887            Value::from_i64(0),
1888            Value::from_f64(0.0),
1889            Value::from_f64(0.0),
1890            Value::from_f64(0.0),
1891            Value::from_f64(0.0),
1892            Value::from_f64(0.0),
1893            Value::from_f64(0.0),
1894        ];
1895
1896        assert_eq!(
1897            inputs.len(),
1898            outputs.len(),
1899            "Inputs and Outputs should have same size"
1900        );
1901
1902        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1903            assert_eq!(
1904                lhs.exec_remainder(rhs),
1905                outputs[i],
1906                "Wrong remainder for lhs: {lhs}, rhs: {rhs}"
1907            );
1908        }
1909    }
1910
1911    #[test]
1912    fn test_exec_and() {
1913        let inputs = vec![
1914            (Value::from_i64(0), Value::Null),
1915            (Value::Null, Value::from_i64(1)),
1916            (Value::Null, Value::Null),
1917            (Value::from_f64(0.0), Value::Null),
1918            (Value::from_i64(1), Value::from_f64(2.2)),
1919            (Value::from_i64(0), Value::Text("string".into())),
1920            (Value::from_i64(0), Value::Text("1".into())),
1921            (Value::from_i64(1), Value::Text("1".into())),
1922        ];
1923        let outputs = [
1924            Value::from_i64(0),
1925            Value::Null,
1926            Value::Null,
1927            Value::from_i64(0),
1928            Value::from_i64(1),
1929            Value::from_i64(0),
1930            Value::from_i64(0),
1931            Value::from_i64(1),
1932        ];
1933
1934        assert_eq!(
1935            inputs.len(),
1936            outputs.len(),
1937            "Inputs and Outputs should have same size"
1938        );
1939        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1940            assert_eq!(
1941                lhs.exec_and(rhs),
1942                outputs[i],
1943                "Wrong AND for lhs: {lhs}, rhs: {rhs}"
1944            );
1945        }
1946    }
1947
1948    #[test]
1949    fn test_exec_or() {
1950        let inputs = vec![
1951            (Value::from_i64(0), Value::Null),
1952            (Value::Null, Value::from_i64(1)),
1953            (Value::Null, Value::Null),
1954            (Value::from_f64(0.0), Value::Null),
1955            (Value::from_i64(1), Value::from_f64(2.2)),
1956            (Value::from_f64(0.0), Value::from_i64(0)),
1957            (Value::from_i64(0), Value::Text("string".into())),
1958            (Value::from_i64(0), Value::Text("1".into())),
1959            (Value::from_i64(0), Value::Text("".into())),
1960        ];
1961        let outputs = [
1962            Value::Null,
1963            Value::from_i64(1),
1964            Value::Null,
1965            Value::Null,
1966            Value::from_i64(1),
1967            Value::from_i64(0),
1968            Value::from_i64(0),
1969            Value::from_i64(1),
1970            Value::from_i64(0),
1971        ];
1972
1973        assert_eq!(
1974            inputs.len(),
1975            outputs.len(),
1976            "Inputs and Outputs should have same size"
1977        );
1978        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1979            assert_eq!(
1980                lhs.exec_or(rhs),
1981                outputs[i],
1982                "Wrong OR for lhs: {lhs}, rhs: {rhs}"
1983            );
1984        }
1985    }
1986
1987    #[test]
1988    fn test_length() {
1989        let input_str = Value::build_text("bob");
1990        let expected_len = Value::from_i64(3);
1991        assert_eq!(input_str.exec_length(), expected_len);
1992
1993        let input_integer = Value::from_i64(123);
1994        let expected_len = Value::from_i64(3);
1995        assert_eq!(input_integer.exec_length(), expected_len);
1996
1997        let input_float = Value::from_f64(123.456);
1998        let expected_len = Value::from_i64(7);
1999        assert_eq!(input_float.exec_length(), expected_len);
2000
2001        let expected_blob = Value::Blob("example".as_bytes().to_vec());
2002        let expected_len = Value::from_i64(7);
2003        assert_eq!(expected_blob.exec_length(), expected_len);
2004    }
2005
2006    #[test]
2007    fn test_quote() {
2008        let input = Value::build_text("abc\0edf");
2009        let expected = Value::build_text("'abc'");
2010        assert_eq!(input.exec_quote(), expected);
2011
2012        let input = Value::from_i64(123);
2013        let expected = Value::build_text("123");
2014        assert_eq!(input.exec_quote(), expected);
2015
2016        let input = Value::from_f64(12.34);
2017        let expected = Value::build_text("12.34");
2018        assert_eq!(input.exec_quote(), expected);
2019
2020        let input = Value::build_text("hello''world");
2021        let expected = Value::build_text("'hello''''world'");
2022        assert_eq!(input.exec_quote(), expected);
2023
2024        let input = Value::from_f64(
2025            crate::numeric::str_to_f64("2.042747795102219097e+05")
2026                .map(f64::from)
2027                .unwrap(),
2028        );
2029        let expected = Value::build_text("2.042747795102219097e+05");
2030        assert_eq!(input.exec_quote(), expected);
2031    }
2032
2033    #[test]
2034    fn test_typeof() {
2035        let input = Value::Null;
2036        let expected: Value = Value::build_text("null");
2037        assert_eq!(input.exec_typeof(), expected);
2038
2039        let input = Value::from_i64(123);
2040        let expected: Value = Value::build_text("integer");
2041        assert_eq!(input.exec_typeof(), expected);
2042
2043        let input = Value::from_f64(123.456);
2044        let expected: Value = Value::build_text("real");
2045        assert_eq!(input.exec_typeof(), expected);
2046
2047        let input = Value::build_text("hello");
2048        let expected: Value = Value::build_text("text");
2049        assert_eq!(input.exec_typeof(), expected);
2050
2051        let input = Value::Blob("limbo".as_bytes().to_vec());
2052        let expected: Value = Value::build_text("blob");
2053        assert_eq!(input.exec_typeof(), expected);
2054    }
2055
2056    #[test]
2057    fn test_unicode() {
2058        assert_eq!(Value::build_text("a").exec_unicode(), Value::from_i64(97));
2059        assert_eq!(
2060            Value::build_text("😊").exec_unicode(),
2061            Value::from_i64(128522)
2062        );
2063        assert_eq!(Value::build_text("").exec_unicode(), Value::Null);
2064        assert_eq!(Value::build_text("\0").exec_unicode(), Value::Null);
2065        assert_eq!(Value::from_i64(23).exec_unicode(), Value::from_i64(50));
2066        assert_eq!(Value::from_i64(0).exec_unicode(), Value::from_i64(48));
2067        assert_eq!(Value::from_f64(0.0).exec_unicode(), Value::from_i64(48));
2068        assert_eq!(Value::from_f64(23.45).exec_unicode(), Value::from_i64(50));
2069        assert_eq!(Value::Null.exec_unicode(), Value::Null);
2070        assert_eq!(
2071            Value::Blob("example".as_bytes().to_vec()).exec_unicode(),
2072            Value::from_i64(101)
2073        );
2074    }
2075
2076    #[test]
2077    fn test_unistr() {
2078        // Each escape form individually
2079        assert_eq!(
2080            Value::build_text(r"\u0041").exec_unistr().unwrap(),
2081            Value::build_text("A")
2082        );
2083        assert_eq!(
2084            Value::build_text(r"\0041").exec_unistr().unwrap(),
2085            Value::build_text("A")
2086        );
2087        assert_eq!(
2088            Value::build_text(r"\+01F600").exec_unistr().unwrap(),
2089            Value::build_text("😀")
2090        );
2091        assert_eq!(
2092            Value::build_text(r"\U0001F600").exec_unistr().unwrap(),
2093            Value::build_text("😀")
2094        );
2095        // Escaped backslash
2096        assert_eq!(
2097            Value::build_text(r"a\\b").exec_unistr().unwrap(),
2098            Value::build_text(r"a\b")
2099        );
2100        // Hex is case-insensitive
2101        assert_eq!(
2102            Value::build_text(r"\u00E4").exec_unistr().unwrap(),
2103            Value::build_text("ä")
2104        );
2105        assert_eq!(
2106            Value::build_text(r"\u00e4").exec_unistr().unwrap(),
2107            Value::build_text("ä")
2108        );
2109        // Multiple escapes in one string
2110        assert_eq!(
2111            Value::build_text(r"\u0048\u0065\u006C\u006C\u006F")
2112                .exec_unistr()
2113                .unwrap(),
2114            Value::build_text("Hello")
2115        );
2116        // Mixed literal and escape forms
2117        assert_eq!(
2118            Value::build_text(r"hi \u0041 \U0001F600")
2119                .exec_unistr()
2120                .unwrap(),
2121            Value::build_text("hi A 😀")
2122        );
2123        // No escapes
2124        assert_eq!(
2125            Value::build_text("hello").exec_unistr().unwrap(),
2126            Value::build_text("hello")
2127        );
2128        // Empty string
2129        assert_eq!(
2130            Value::build_text("").exec_unistr().unwrap(),
2131            Value::build_text("")
2132        );
2133        // NULL input
2134        assert_eq!(Value::Null.exec_unistr().unwrap(), Value::Null);
2135        // NUL codepoint accepted (matches SQLite, which carries NUL via explicit length)
2136        assert_eq!(
2137            Value::build_text(r"\u0000").exec_unistr().unwrap(),
2138            Value::build_text("\0")
2139        );
2140        // Surrogate rejected (Value::Text requires valid UTF-8)
2141        assert!(Value::build_text(r"\uD83D").exec_unistr().is_err());
2142        // Above U+10FFFF rejected
2143        assert!(Value::build_text(r"\U00110000").exec_unistr().is_err());
2144        // Malformed escapes
2145        assert!(Value::build_text(r"\q").exec_unistr().is_err());
2146        assert!(Value::build_text(r"\u00").exec_unistr().is_err());
2147        assert!(Value::build_text("abc\\").exec_unistr().is_err());
2148        // Non-hex in fixed-width span
2149        assert!(Value::build_text(r"\u00GG").exec_unistr().is_err());
2150        assert!(Value::build_text(r"\+01FG00").exec_unistr().is_err());
2151        assert!(Value::build_text(r"\U0001F6GG").exec_unistr().is_err());
2152    }
2153
2154    #[test]
2155    fn test_unistr_quote() {
2156        assert_eq!(Value::Null.exec_unistr_quote(), Value::build_text("NULL"));
2157        assert_eq!(
2158            Value::from_i64(42).exec_unistr_quote(),
2159            Value::build_text("42")
2160        );
2161        assert_eq!(
2162            Value::from_f64(1.5).exec_unistr_quote(),
2163            Value::build_text("1.5")
2164        );
2165        assert_eq!(
2166            Value::Blob(vec![0xDE, 0xAD]).exec_unistr_quote(),
2167            Value::build_text("X'DEAD'")
2168        );
2169        assert_eq!(
2170            Value::build_text("hello").exec_unistr_quote(),
2171            Value::build_text("'hello'")
2172        );
2173        // Backslash is NOT doubled when no control chars are present
2174        assert_eq!(
2175            Value::build_text("a\\b").exec_unistr_quote(),
2176            Value::build_text("'a\\b'")
2177        );
2178        assert_eq!(
2179            Value::build_text("it's").exec_unistr_quote(),
2180            Value::build_text("'it''s'")
2181        );
2182        assert_eq!(
2183            Value::build_text("a\tb").exec_unistr_quote(),
2184            Value::build_text("unistr('a\\u0009b')")
2185        );
2186        assert_eq!(
2187            Value::build_text("a\t\\b").exec_unistr_quote(),
2188            Value::build_text("unistr('a\\u0009\\\\b')")
2189        );
2190        assert_eq!(
2191            Value::build_text("a\tb'c").exec_unistr_quote(),
2192            Value::build_text("unistr('a\\u0009b''c')")
2193        );
2194        assert_eq!(
2195            Value::build_text("\x01abc'\\\t\n\r\x1fXYZ\0\x01tail").exec_unistr_quote(),
2196            Value::build_text(r"unistr('\u0001abc''\\\u0009\u000a\u000d\u001fXYZ')")
2197        );
2198        assert_eq!(
2199            Value::build_text("a\x01b\0c").exec_unistr_quote(),
2200            Value::build_text("unistr('a\\u0001b')")
2201        );
2202        assert_eq!(
2203            Value::build_text("\x01").exec_unistr_quote(),
2204            Value::build_text("unistr('\\u0001')")
2205        );
2206        assert_eq!(
2207            Value::build_text("\x01\x1f").exec_unistr_quote(),
2208            Value::build_text("unistr('\\u0001\\u001f')")
2209        );
2210        assert_eq!(
2211            Value::build_text("\x10").exec_unistr_quote(),
2212            Value::build_text("unistr('\\u0010')")
2213        );
2214        assert_eq!(
2215            Value::build_text("\x1f").exec_unistr_quote(),
2216            Value::build_text("unistr('\\u001f')")
2217        );
2218        // 0x20 is the first char outside the control range
2219        assert_eq!(
2220            Value::build_text(" ").exec_unistr_quote(),
2221            Value::build_text("' '")
2222        );
2223        assert_eq!(
2224            Value::build_text("\0abc").exec_unistr_quote(),
2225            Value::build_text("''")
2226        );
2227        assert_eq!(
2228            Value::build_text("").exec_unistr_quote(),
2229            Value::build_text("''")
2230        );
2231        assert_eq!(
2232            Value::build_text("a\nb").exec_unistr_quote(),
2233            Value::build_text("unistr('a\\u000ab')")
2234        );
2235        assert_eq!(
2236            Value::build_text("a\rb").exec_unistr_quote(),
2237            Value::build_text("unistr('a\\u000db')")
2238        );
2239        assert_eq!(
2240            Value::build_text("a\0\t").exec_unistr_quote(),
2241            Value::build_text("'a'")
2242        );
2243    }
2244
2245    #[test]
2246    fn test_min_max() {
2247        let input_int_vec = [
2248            Register::Value(Value::from_i64(-1)),
2249            Register::Value(Value::from_i64(10)),
2250        ];
2251        assert_eq!(
2252            Value::exec_min(input_int_vec.iter().map(|v| v.get_value())),
2253            Value::from_i64(-1)
2254        );
2255        assert_eq!(
2256            Value::exec_max(input_int_vec.iter().map(|v| v.get_value())),
2257            Value::from_i64(10)
2258        );
2259
2260        let str1 = Register::Value(Value::build_text("A"));
2261        let str2 = Register::Value(Value::build_text("z"));
2262        let input_str_vec = [str2, str1.clone()];
2263        assert_eq!(
2264            Value::exec_min(input_str_vec.iter().map(|v| v.get_value())),
2265            Value::build_text("A")
2266        );
2267        assert_eq!(
2268            Value::exec_max(input_str_vec.iter().map(|v| v.get_value())),
2269            Value::build_text("z")
2270        );
2271
2272        let input_null_vec = [Register::Value(Value::Null), Register::Value(Value::Null)];
2273        assert_eq!(
2274            Value::exec_min(input_null_vec.iter().map(|v| v.get_value())),
2275            Value::Null
2276        );
2277        assert_eq!(
2278            Value::exec_max(input_null_vec.iter().map(|v| v.get_value())),
2279            Value::Null
2280        );
2281
2282        let input_mixed_vec = [Register::Value(Value::from_i64(10)), str1];
2283        assert_eq!(
2284            Value::exec_min(input_mixed_vec.iter().map(|v| v.get_value())),
2285            Value::from_i64(10)
2286        );
2287        assert_eq!(
2288            Value::exec_max(input_mixed_vec.iter().map(|v| v.get_value())),
2289            Value::build_text("A")
2290        );
2291
2292        // SQLite: multi-arg min/max returns NULL if ANY argument is NULL
2293        let input_with_null = [
2294            Register::Value(Value::from_i64(1)),
2295            Register::Value(Value::Null),
2296        ];
2297        assert_eq!(
2298            Value::exec_min(input_with_null.iter().map(|v| v.get_value())),
2299            Value::Null
2300        );
2301        assert_eq!(
2302            Value::exec_max(input_with_null.iter().map(|v| v.get_value())),
2303            Value::Null
2304        );
2305    }
2306
2307    #[test]
2308    fn test_trim() {
2309        let input_str = Value::build_text("     Bob and Alice     ");
2310        let expected_str = Value::build_text("Bob and Alice");
2311        assert_eq!(input_str.exec_trim(None), expected_str);
2312
2313        let input_str = Value::build_text("     Bob and Alice     ");
2314        let pattern_str = Value::build_text("Bob and");
2315        let expected_str = Value::build_text("Alice");
2316        assert_eq!(input_str.exec_trim(Some(&pattern_str)), expected_str);
2317
2318        let input_str = Value::build_text("\ta");
2319        let expected_str = Value::build_text("\ta");
2320        assert_eq!(input_str.exec_trim(None), expected_str);
2321
2322        let input_str = Value::build_text("\na");
2323        let expected_str = Value::build_text("\na");
2324        assert_eq!(input_str.exec_trim(None), expected_str);
2325
2326        // TRIM on Integer should return TEXT (SQLite compatibility)
2327        let input_int = Value::from_i64(12345);
2328        let expected_text = Value::build_text("12345");
2329        assert_eq!(input_int.exec_trim(None), expected_text);
2330
2331        // TRIM on Float should return TEXT (SQLite compatibility)
2332        let input_float = Value::from_f64(123.5);
2333        let expected_text = Value::build_text("123.5");
2334        assert_eq!(input_float.exec_trim(None), expected_text);
2335    }
2336
2337    #[test]
2338    fn test_ltrim() {
2339        let input_str = Value::build_text("     Bob and Alice     ");
2340        let expected_str = Value::build_text("Bob and Alice     ");
2341        assert_eq!(input_str.exec_ltrim(None), expected_str);
2342
2343        let input_str = Value::build_text("     Bob and Alice     ");
2344        let pattern_str = Value::build_text("Bob and");
2345        let expected_str = Value::build_text("Alice     ");
2346        assert_eq!(input_str.exec_ltrim(Some(&pattern_str)), expected_str);
2347    }
2348
2349    #[test]
2350    fn test_rtrim() {
2351        let input_str = Value::build_text("     Bob and Alice     ");
2352        let expected_str = Value::build_text("     Bob and Alice");
2353        assert_eq!(input_str.exec_rtrim(None), expected_str);
2354
2355        let input_str = Value::build_text("     Bob and Alice     ");
2356        let pattern_str = Value::build_text("Bob and");
2357        let expected_str = Value::build_text("     Bob and Alice");
2358        assert_eq!(input_str.exec_rtrim(Some(&pattern_str)), expected_str);
2359
2360        let input_str = Value::build_text("     Bob and Alice     ");
2361        let pattern_str = Value::build_text("and Alice");
2362        let expected_str = Value::build_text("     Bob");
2363        assert_eq!(input_str.exec_rtrim(Some(&pattern_str)), expected_str);
2364    }
2365
2366    #[test]
2367    fn test_soundex() {
2368        let input_str = Value::build_text("Pfister");
2369        let expected_str = Value::build_text("P236");
2370        assert_eq!(input_str.exec_soundex(), expected_str);
2371
2372        let input_str = Value::build_text("husobee");
2373        let expected_str = Value::build_text("H210");
2374        assert_eq!(input_str.exec_soundex(), expected_str);
2375
2376        let input_str = Value::build_text("Tymczak");
2377        let expected_str = Value::build_text("T522");
2378        assert_eq!(input_str.exec_soundex(), expected_str);
2379
2380        let input_str = Value::build_text("Ashcraft");
2381        let expected_str = Value::build_text("A261");
2382        assert_eq!(input_str.exec_soundex(), expected_str);
2383
2384        let input_str = Value::build_text("Robert");
2385        let expected_str = Value::build_text("R163");
2386        assert_eq!(input_str.exec_soundex(), expected_str);
2387
2388        let input_str = Value::build_text("Rupert");
2389        let expected_str = Value::build_text("R163");
2390        assert_eq!(input_str.exec_soundex(), expected_str);
2391
2392        let input_str = Value::build_text("Rubin");
2393        let expected_str = Value::build_text("R150");
2394        assert_eq!(input_str.exec_soundex(), expected_str);
2395
2396        let input_str = Value::build_text("Kant");
2397        let expected_str = Value::build_text("K530");
2398        assert_eq!(input_str.exec_soundex(), expected_str);
2399
2400        let input_str = Value::build_text("Knuth");
2401        let expected_str = Value::build_text("K530");
2402        assert_eq!(input_str.exec_soundex(), expected_str);
2403
2404        let input_str = Value::build_text("x");
2405        let expected_str = Value::build_text("X000");
2406        assert_eq!(input_str.exec_soundex(), expected_str);
2407
2408        let input_str = Value::build_text("闪电五连鞭");
2409        let expected_str = Value::build_text("?000");
2410        assert_eq!(input_str.exec_soundex(), expected_str);
2411    }
2412
2413    #[test]
2414    fn test_upper_case() {
2415        let input_str = Value::build_text("Limbo");
2416        let expected_str = Value::build_text("LIMBO");
2417        assert_eq!(input_str.exec_upper().unwrap(), expected_str);
2418
2419        let input_int = Value::from_i64(10);
2420        assert_eq!(input_int.exec_upper().unwrap(), Value::build_text("10"));
2421        assert_eq!(Value::Null.exec_upper(), None)
2422    }
2423
2424    #[test]
2425    fn test_lower_case() {
2426        let input_str = Value::build_text("Limbo");
2427        let expected_str = Value::build_text("limbo");
2428        assert_eq!(input_str.exec_lower().unwrap(), expected_str);
2429
2430        let input_int = Value::from_i64(10);
2431        assert_eq!(input_int.exec_lower().unwrap(), Value::build_text("10"));
2432        assert_eq!(Value::Null.exec_lower(), None)
2433    }
2434
2435    #[test]
2436    fn test_hex() {
2437        let input_str = Value::build_text("limbo");
2438        let expected_val = Value::build_text("6C696D626F");
2439        assert_eq!(input_str.exec_hex(), expected_val);
2440
2441        let input_int = Value::from_i64(100);
2442        let expected_val = Value::build_text("313030");
2443        assert_eq!(input_int.exec_hex(), expected_val);
2444
2445        let input_float = Value::from_f64(12.34);
2446        let expected_val = Value::build_text("31322E3334");
2447        assert_eq!(input_float.exec_hex(), expected_val);
2448
2449        let input_blob = Value::Blob(vec![0xff]);
2450        let expected_val = Value::build_text("FF");
2451        assert_eq!(input_blob.exec_hex(), expected_val);
2452    }
2453
2454    #[test]
2455    fn test_cast_blob_preserves_blob_bytes() {
2456        let input_blob = Value::Blob(vec![0xd2, 0x64, 0xc0, 0x07, 0xf6, 0x44, 0xe4, 0x59]);
2457        let expected = input_blob.clone();
2458
2459        assert_eq!(input_blob.exec_cast("BLOB"), expected);
2460    }
2461
2462    #[test]
2463    fn test_unhex() {
2464        let input = Value::build_text("6f");
2465        let expected = Value::Blob(vec![0x6f]);
2466        assert_eq!(input.exec_unhex(None), expected);
2467
2468        let input = Value::build_text("6f");
2469        let expected = Value::Blob(vec![0x6f]);
2470        assert_eq!(input.exec_unhex(None), expected);
2471
2472        let input = Value::build_text("611");
2473        let expected = Value::Null;
2474        assert_eq!(input.exec_unhex(None), expected);
2475
2476        let input = Value::build_text("");
2477        let expected = Value::Blob(vec![]);
2478        assert_eq!(input.exec_unhex(None), expected);
2479
2480        let input = Value::build_text("61x");
2481        let expected = Value::Null;
2482        assert_eq!(input.exec_unhex(None), expected);
2483
2484        let input = Value::Null;
2485        let expected = Value::Null;
2486        assert_eq!(input.exec_unhex(None), expected);
2487
2488        let input = Value::build_text("aa-bb");
2489        let expected = Value::Blob(vec![0xaa, 0xbb]);
2490        assert_eq!(input.exec_unhex(Some(&Value::build_text("-"))), expected);
2491
2492        let input = Value::build_text("aa--bb");
2493        let expected = Value::Blob(vec![0xaa, 0xbb]);
2494        assert_eq!(input.exec_unhex(Some(&Value::build_text("-"))), expected);
2495
2496        let input = Value::build_text("aa-bb-cc");
2497        let expected = Value::Blob(vec![0xaa, 0xbb, 0xcc]);
2498        assert_eq!(input.exec_unhex(Some(&Value::build_text("-"))), expected);
2499
2500        let input = Value::build_text("aa bb");
2501        let expected = Value::Blob(vec![0xaa, 0xbb]);
2502        assert_eq!(input.exec_unhex(Some(&Value::build_text(" "))), expected);
2503
2504        let input = Value::build_text("A BCD");
2505        let expected = Value::Null;
2506        assert_eq!(input.exec_unhex(Some(&Value::build_text(" "))), expected);
2507
2508        let input = Value::build_text("yx2xEzyx");
2509        let expected = Value::Null;
2510        assert_eq!(input.exec_unhex(Some(&Value::build_text("xyz"))), expected);
2511
2512        let input = Value::build_text("aa?bb");
2513        let expected = Value::Null;
2514        assert_eq!(input.exec_unhex(Some(&Value::build_text("-"))), expected);
2515
2516        let input = Value::build_text("aabb");
2517        let expected = Value::Null;
2518        assert_eq!(input.exec_unhex(Some(&Value::Null)), expected);
2519    }
2520
2521    #[test]
2522    fn test_abs() {
2523        let int_positive_reg = Value::from_i64(10);
2524        let int_negative_reg = Value::from_i64(-10);
2525        assert_eq!(int_positive_reg.exec_abs().unwrap(), int_positive_reg);
2526        assert_eq!(int_negative_reg.exec_abs().unwrap(), int_positive_reg);
2527
2528        let float_positive_reg = Value::from_i64(10);
2529        let float_negative_reg = Value::from_i64(-10);
2530        assert_eq!(float_positive_reg.exec_abs().unwrap(), float_positive_reg);
2531        assert_eq!(float_negative_reg.exec_abs().unwrap(), float_positive_reg);
2532
2533        assert_eq!(
2534            Value::build_text("a").exec_abs().unwrap(),
2535            Value::from_f64(0.0)
2536        );
2537        assert_eq!(Value::Null.exec_abs().unwrap(), Value::Null);
2538
2539        // ABS(i64::MIN) should return RuntimeError
2540        assert!(Value::from_i64(i64::MIN).exec_abs().is_err());
2541    }
2542
2543    #[test]
2544    fn test_char() {
2545        assert_eq!(
2546            Value::exec_char(
2547                [
2548                    Register::Value(Value::from_i64(108)),
2549                    Register::Value(Value::from_i64(105))
2550                ]
2551                .iter()
2552                .map(|reg| reg.get_value())
2553            ),
2554            Value::build_text("li")
2555        );
2556        assert_eq!(Value::exec_char(std::iter::empty()), Value::build_text(""));
2557        assert_eq!(
2558            Value::exec_char(
2559                [Register::Value(Value::Null)]
2560                    .iter()
2561                    .map(|reg| reg.get_value())
2562            ),
2563            Value::build_text("\0")
2564        );
2565        assert_eq!(
2566            Value::exec_char(
2567                [Register::Value(Value::build_text("a"))]
2568                    .iter()
2569                    .map(|reg| reg.get_value())
2570            ),
2571            Value::build_text("")
2572        );
2573    }
2574
2575    #[test]
2576    fn test_like_with_escape_or_regexmeta_chars() {
2577        assert!(Value::exec_like(r#"\%A"#, r#"\A"#, None).unwrap());
2578        assert!(Value::exec_like("%a%a", "aaaa", None).unwrap());
2579    }
2580
2581    #[test]
2582    fn test_like_without_escape() {
2583        assert!(Value::exec_like("a%", "aaaa", None).unwrap());
2584        assert!(Value::exec_like("%a%a", "aaaa", None).unwrap());
2585        assert!(!Value::exec_like("%a.a", "aaaa", None).unwrap());
2586        assert!(!Value::exec_like("a.a%", "aaaa", None).unwrap());
2587        assert!(!Value::exec_like("%a.ab", "aaaa", None).unwrap());
2588    }
2589
2590    #[test]
2591    fn test_exec_like_with_escape() {
2592        assert!(Value::exec_like("abcX%", "abc%", Some('X')).unwrap());
2593        assert!(!Value::exec_like("abcX%", "abc5", Some('X')).unwrap());
2594        assert!(!Value::exec_like("abcX%", "abc", Some('X')).unwrap());
2595        assert!(!Value::exec_like("abcX%", "abcX%", Some('X')).unwrap());
2596        assert!(!Value::exec_like("abcX%", "abc%%", Some('X')).unwrap());
2597
2598        assert!(Value::exec_like("abcX_", "abc_", Some('X')).unwrap());
2599        assert!(!Value::exec_like("abcX_", "abc5", Some('X')).unwrap());
2600        assert!(!Value::exec_like("abcX_", "abc", Some('X')).unwrap());
2601        assert!(!Value::exec_like("abcX_", "abcX_", Some('X')).unwrap());
2602        assert!(!Value::exec_like("abcX_", "abc__", Some('X')).unwrap());
2603
2604        assert!(Value::exec_like("abcXX", "abcX", Some('X')).unwrap());
2605        assert!(!Value::exec_like("abcXX", "abc5", Some('X')).unwrap());
2606        assert!(!Value::exec_like("abcXX", "abc", Some('X')).unwrap());
2607        assert!(!Value::exec_like("abcXX", "abcXX", Some('X')).unwrap());
2608    }
2609
2610    #[test]
2611    fn test_glob() {
2612        assert!(Value::exec_glob(r#"?*/abc/?*"#, r#"x//a/ab/abc/y"#).unwrap());
2613        assert!(Value::exec_glob(r#"a[1^]"#, r#"a1"#).unwrap());
2614        assert!(Value::exec_glob(r#"a[1^]*"#, r#"a^"#).unwrap());
2615        assert!(!Value::exec_glob(r#"a[a*"#, r#"a["#).unwrap());
2616        assert!(!Value::exec_glob(r#"a[a"#, r#"a[a"#).unwrap());
2617        assert!(Value::exec_glob(r#"a[[]"#, r#"a["#).unwrap());
2618        assert!(Value::exec_glob(r#"abc[^][*?]efg"#, r#"abcdefg"#).unwrap());
2619        assert!(!Value::exec_glob(r#"abc[^][*?]efg"#, r#"abc]efg"#).unwrap());
2620    }
2621
2622    #[test]
2623    fn test_random() {
2624        match Value::exec_random(|| rand::rng().random()) {
2625            Value::Numeric(Numeric::Integer(value)) => {
2626                // Check that the value is within the range of i64
2627                assert!(
2628                    (i64::MIN..=i64::MAX).contains(&value),
2629                    "Random number out of range"
2630                );
2631            }
2632            _ => panic!("exec_random did not return an Integer variant"),
2633        }
2634    }
2635
2636    #[test]
2637    fn test_exec_randomblob() {
2638        struct TestCase {
2639            input: Value,
2640            expected_len: usize,
2641        }
2642
2643        let test_cases = vec![
2644            TestCase {
2645                input: Value::from_i64(5),
2646                expected_len: 5,
2647            },
2648            TestCase {
2649                input: Value::from_i64(0),
2650                expected_len: 1,
2651            },
2652            TestCase {
2653                input: Value::from_i64(-1),
2654                expected_len: 1,
2655            },
2656            TestCase {
2657                input: Value::build_text(""),
2658                expected_len: 1,
2659            },
2660            TestCase {
2661                input: Value::build_text("5"),
2662                expected_len: 5,
2663            },
2664            TestCase {
2665                input: Value::build_text("0"),
2666                expected_len: 1,
2667            },
2668            TestCase {
2669                input: Value::build_text("-1"),
2670                expected_len: 1,
2671            },
2672            TestCase {
2673                input: Value::from_f64(2.9),
2674                expected_len: 2,
2675            },
2676            TestCase {
2677                input: Value::from_f64(-3.15),
2678                expected_len: 1,
2679            },
2680            TestCase {
2681                input: Value::Null,
2682                expected_len: 1,
2683            },
2684        ];
2685
2686        for test_case in &test_cases {
2687            let result = test_case
2688                .input
2689                .exec_randomblob(|dest| {
2690                    rand::rng().fill_bytes(dest);
2691                })
2692                .unwrap();
2693            match result {
2694                Value::Blob(blob) => {
2695                    assert_eq!(blob.len(), test_case.expected_len);
2696                }
2697                _ => panic!("exec_randomblob did not return a Blob variant"),
2698            }
2699        }
2700
2701        // Test TooBig error
2702        let input = Value::from_i64(Value::MAX_BLOB_LENGTH + 1);
2703        assert!(input.exec_randomblob(|_| {}).is_err());
2704    }
2705
2706    #[test]
2707    fn test_exec_round() {
2708        let input_val = Value::from_f64(123.456);
2709        let expected_val = Value::from_f64(123.0);
2710        assert_eq!(input_val.exec_round(None), expected_val);
2711
2712        let input_val = Value::from_f64(123.456);
2713        let precision_val = Value::from_i64(2);
2714        let expected_val = Value::from_f64(123.46);
2715        assert_eq!(input_val.exec_round(Some(&precision_val)), expected_val);
2716
2717        let input_val = Value::from_f64(123.456);
2718        let precision_val = Value::build_text("1");
2719        let expected_val = Value::from_f64(123.5);
2720        assert_eq!(input_val.exec_round(Some(&precision_val)), expected_val);
2721
2722        let input_val = Value::build_text("123.456");
2723        let precision_val = Value::from_i64(2);
2724        let expected_val = Value::from_f64(123.46);
2725        assert_eq!(input_val.exec_round(Some(&precision_val)), expected_val);
2726
2727        let input_val = Value::from_i64(123);
2728        let precision_val = Value::from_i64(1);
2729        let expected_val = Value::from_f64(123.0);
2730        assert_eq!(input_val.exec_round(Some(&precision_val)), expected_val);
2731
2732        let input_val = Value::from_f64(100.123);
2733        let expected_val = Value::from_f64(100.0);
2734        assert_eq!(input_val.exec_round(None), expected_val);
2735
2736        let input_val = Value::from_f64(100.123);
2737        let expected_val = Value::Null;
2738        assert_eq!(input_val.exec_round(Some(&Value::Null)), expected_val);
2739    }
2740
2741    #[test]
2742    fn test_exec_if() {
2743        let reg = Value::from_i64(0);
2744        assert!(!reg.exec_if(false, false));
2745        assert!(reg.exec_if(false, true));
2746
2747        let reg = Value::from_i64(1);
2748        assert!(reg.exec_if(false, false));
2749        assert!(!reg.exec_if(false, true));
2750
2751        let reg = Value::Null;
2752        assert!(!reg.exec_if(false, false));
2753        assert!(!reg.exec_if(false, true));
2754
2755        let reg = Value::Null;
2756        assert!(reg.exec_if(true, false));
2757        assert!(reg.exec_if(true, true));
2758
2759        let reg = Value::Null;
2760        assert!(!reg.exec_if(false, false));
2761        assert!(!reg.exec_if(false, true));
2762    }
2763
2764    #[test]
2765    fn test_nullif() {
2766        assert_eq!(
2767            Value::from_i64(1).exec_nullif(&Value::from_i64(1)),
2768            Value::Null
2769        );
2770        assert_eq!(
2771            Value::from_f64(1.1).exec_nullif(&Value::from_f64(1.1)),
2772            Value::Null
2773        );
2774        assert_eq!(
2775            Value::build_text("limbo").exec_nullif(&Value::build_text("limbo")),
2776            Value::Null
2777        );
2778
2779        assert_eq!(
2780            Value::from_i64(1).exec_nullif(&Value::from_i64(2)),
2781            Value::from_i64(1)
2782        );
2783        assert_eq!(
2784            Value::from_f64(1.1).exec_nullif(&Value::from_f64(1.2)),
2785            Value::from_f64(1.1)
2786        );
2787        assert_eq!(
2788            Value::build_text("limbo").exec_nullif(&Value::build_text("limb")),
2789            Value::build_text("limbo")
2790        );
2791    }
2792
2793    #[test]
2794    fn test_substring() {
2795        let str_value = Value::build_text("limbo");
2796        let start_value = Value::from_i64(1);
2797        let length_value = Value::from_i64(3);
2798        let expected_val = Value::build_text("lim");
2799        assert_eq!(
2800            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2801            expected_val
2802        );
2803
2804        let str_value = Value::build_text("limbo");
2805        let start_value = Value::from_i64(1);
2806        let length_value = Value::from_i64(10);
2807        let expected_val = Value::build_text("limbo");
2808        assert_eq!(
2809            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2810            expected_val
2811        );
2812
2813        let str_value = Value::build_text("limbo");
2814        let start_value = Value::from_i64(10);
2815        let length_value = Value::from_i64(3);
2816        let expected_val = Value::build_text("");
2817        assert_eq!(
2818            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2819            expected_val
2820        );
2821
2822        let str_value = Value::build_text("limbo");
2823        let start_value = Value::from_i64(3);
2824        let length_value = Value::Null;
2825        let expected_val = Value::Null;
2826        assert_eq!(
2827            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2828            expected_val
2829        );
2830
2831        let str_value = Value::build_text("limbo");
2832        let start_value = Value::from_i64(10);
2833        let length_value = Value::Null;
2834        let expected_val = Value::Null;
2835        assert_eq!(
2836            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2837            expected_val
2838        );
2839
2840        let str_value = Value::build_text("limbo");
2841        let start_value = Value::from_i64(-7_096_519_388_852_014_892);
2842        let length_value = Value::from_i64(-4_829_175_794_346_763_833);
2843        let expected_val = Value::build_text("");
2844        assert_eq!(
2845            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2846            expected_val
2847        );
2848    }
2849
2850    #[test]
2851    fn test_exec_instr() {
2852        let input = Value::build_text("limbo");
2853        let pattern = Value::build_text("im");
2854        let expected = Value::from_i64(2);
2855        assert_eq!(input.exec_instr(&pattern), expected);
2856
2857        let input = Value::build_text("limbo");
2858        let pattern = Value::build_text("limbo");
2859        let expected = Value::from_i64(1);
2860        assert_eq!(input.exec_instr(&pattern), expected);
2861
2862        let input = Value::build_text("limbo");
2863        let pattern = Value::build_text("o");
2864        let expected = Value::from_i64(5);
2865        assert_eq!(input.exec_instr(&pattern), expected);
2866
2867        let input = Value::build_text("liiiiimbo");
2868        let pattern = Value::build_text("ii");
2869        let expected = Value::from_i64(2);
2870        assert_eq!(input.exec_instr(&pattern), expected);
2871
2872        let input = Value::build_text("limbo");
2873        let pattern = Value::build_text("limboX");
2874        let expected = Value::from_i64(0);
2875        assert_eq!(input.exec_instr(&pattern), expected);
2876
2877        let input = Value::build_text("limbo");
2878        let pattern = Value::build_text("");
2879        let expected = Value::from_i64(1);
2880        assert_eq!(input.exec_instr(&pattern), expected);
2881
2882        let input = Value::build_text("");
2883        let pattern = Value::build_text("limbo");
2884        let expected = Value::from_i64(0);
2885        assert_eq!(input.exec_instr(&pattern), expected);
2886
2887        let input = Value::build_text("");
2888        let pattern = Value::build_text("");
2889        let expected = Value::from_i64(1);
2890        assert_eq!(input.exec_instr(&pattern), expected);
2891
2892        let input = Value::Null;
2893        let pattern = Value::Null;
2894        let expected = Value::Null;
2895        assert_eq!(input.exec_instr(&pattern), expected);
2896
2897        let input = Value::build_text("limbo");
2898        let pattern = Value::Null;
2899        let expected = Value::Null;
2900        assert_eq!(input.exec_instr(&pattern), expected);
2901
2902        let input = Value::Null;
2903        let pattern = Value::build_text("limbo");
2904        let expected = Value::Null;
2905        assert_eq!(input.exec_instr(&pattern), expected);
2906
2907        let input = Value::from_i64(123);
2908        let pattern = Value::from_i64(2);
2909        let expected = Value::from_i64(2);
2910        assert_eq!(input.exec_instr(&pattern), expected);
2911
2912        let input = Value::from_i64(123);
2913        let pattern = Value::from_i64(5);
2914        let expected = Value::from_i64(0);
2915        assert_eq!(input.exec_instr(&pattern), expected);
2916
2917        let input = Value::from_f64(12.34);
2918        let pattern = Value::from_f64(2.3);
2919        let expected = Value::from_i64(2);
2920        assert_eq!(input.exec_instr(&pattern), expected);
2921
2922        let input = Value::from_f64(12.34);
2923        let pattern = Value::from_f64(5.6);
2924        let expected = Value::from_i64(0);
2925        assert_eq!(input.exec_instr(&pattern), expected);
2926
2927        let input = Value::from_f64(12.34);
2928        let pattern = Value::build_text(".");
2929        let expected = Value::from_i64(3);
2930        assert_eq!(input.exec_instr(&pattern), expected);
2931
2932        let input = Value::Blob(vec![1, 2, 3, 4, 5]);
2933        let pattern = Value::Blob(vec![3, 4]);
2934        let expected = Value::from_i64(3);
2935        assert_eq!(input.exec_instr(&pattern), expected);
2936
2937        let input = Value::Blob(vec![1, 2, 3, 4, 5]);
2938        let pattern = Value::Blob(vec![3, 2]);
2939        let expected = Value::from_i64(0);
2940        assert_eq!(input.exec_instr(&pattern), expected);
2941
2942        let input = Value::Blob(vec![0x61, 0x62, 0x63, 0x64, 0x65]);
2943        let pattern = Value::build_text("cd");
2944        let expected = Value::from_i64(3);
2945        assert_eq!(input.exec_instr(&pattern), expected);
2946
2947        let input = Value::build_text("abcde");
2948        let pattern = Value::Blob(vec![0x63, 0x64]);
2949        let expected = Value::from_i64(3);
2950        assert_eq!(input.exec_instr(&pattern), expected);
2951
2952        let input = Value::build_text("abcde");
2953        let pattern = Value::build_text("");
2954        let expected = Value::from_i64(1);
2955        assert_eq!(input.exec_instr(&pattern), expected);
2956    }
2957
2958    #[test]
2959    fn test_exec_sign() {
2960        let input = Value::from_i64(42);
2961        let expected = Some(Value::from_i64(1));
2962        assert_eq!(input.exec_sign(), expected);
2963
2964        let input = Value::from_i64(-42);
2965        let expected = Some(Value::from_i64(-1));
2966        assert_eq!(input.exec_sign(), expected);
2967
2968        let input = Value::from_i64(0);
2969        let expected = Some(Value::from_i64(0));
2970        assert_eq!(input.exec_sign(), expected);
2971
2972        let input = Value::from_f64(0.0);
2973        let expected = Some(Value::from_i64(0));
2974        assert_eq!(input.exec_sign(), expected);
2975
2976        let input = Value::from_f64(0.1);
2977        let expected = Some(Value::from_i64(1));
2978        assert_eq!(input.exec_sign(), expected);
2979
2980        let input = Value::from_f64(42.0);
2981        let expected = Some(Value::from_i64(1));
2982        assert_eq!(input.exec_sign(), expected);
2983
2984        let input = Value::from_f64(-42.0);
2985        let expected = Some(Value::from_i64(-1));
2986        assert_eq!(input.exec_sign(), expected);
2987
2988        let input = Value::build_text("abc");
2989        let expected = None;
2990        assert_eq!(input.exec_sign(), expected);
2991
2992        let input = Value::build_text("42");
2993        let expected = Some(Value::from_i64(1));
2994        assert_eq!(input.exec_sign(), expected);
2995
2996        let input = Value::build_text("-42");
2997        let expected = Some(Value::from_i64(-1));
2998        assert_eq!(input.exec_sign(), expected);
2999
3000        let input = Value::build_text("0");
3001        let expected = Some(Value::from_i64(0));
3002        assert_eq!(input.exec_sign(), expected);
3003
3004        let input = Value::Blob(b"abc".to_vec());
3005        let expected = None;
3006        assert_eq!(input.exec_sign(), expected);
3007
3008        let input = Value::Blob(b"42".to_vec());
3009        let expected = None;
3010        assert_eq!(input.exec_sign(), expected);
3011
3012        let input = Value::Blob(b"-42".to_vec());
3013        let expected = None;
3014        assert_eq!(input.exec_sign(), expected);
3015
3016        let input = Value::Blob(b"0".to_vec());
3017        let expected = None;
3018        assert_eq!(input.exec_sign(), expected);
3019
3020        let input = Value::Null;
3021        let expected = None;
3022        assert_eq!(input.exec_sign(), expected);
3023    }
3024
3025    #[test]
3026    fn test_exec_zeroblob() {
3027        let input = Value::from_i64(0);
3028        let expected = Value::Blob(vec![]);
3029        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3030
3031        let input = Value::Null;
3032        let expected = Value::Blob(vec![]);
3033        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3034
3035        let input = Value::from_i64(4);
3036        let expected = Value::Blob(vec![0; 4]);
3037        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3038
3039        let input = Value::from_i64(-1);
3040        let expected = Value::Blob(vec![]);
3041        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3042
3043        let input = Value::build_text("5");
3044        let expected = Value::Blob(vec![0; 5]);
3045        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3046
3047        let input = Value::build_text("-5");
3048        let expected = Value::Blob(vec![]);
3049        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3050
3051        let input = Value::build_text("text");
3052        let expected = Value::Blob(vec![]);
3053        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3054
3055        let input = Value::from_f64(2.6);
3056        let expected = Value::Blob(vec![0; 2]);
3057        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3058
3059        let input = Value::Blob(vec![1]);
3060        let expected = Value::Blob(vec![]);
3061        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3062
3063        // Test TooBig error
3064        let input = Value::from_i64(Value::MAX_BLOB_LENGTH + 1);
3065        assert!(input.exec_zeroblob().is_err());
3066    }
3067
3068    #[test]
3069    fn test_replace() {
3070        let input_str = Value::build_text("bob");
3071        let pattern_str = Value::build_text("b");
3072        let replace_str = Value::build_text("a");
3073        let expected_str = Value::build_text("aoa");
3074        assert_eq!(
3075            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3076            expected_str
3077        );
3078
3079        let input_str = Value::build_text("bob");
3080        let pattern_str = Value::build_text("b");
3081        let replace_str = Value::build_text("");
3082        let expected_str = Value::build_text("o");
3083        assert_eq!(
3084            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3085            expected_str
3086        );
3087
3088        let input_str = Value::build_text("bob");
3089        let pattern_str = Value::build_text("b");
3090        let replace_str = Value::build_text("abc");
3091        let expected_str = Value::build_text("abcoabc");
3092        assert_eq!(
3093            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3094            expected_str
3095        );
3096
3097        let input_str = Value::build_text("bob");
3098        let pattern_str = Value::build_text("a");
3099        let replace_str = Value::build_text("b");
3100        let expected_str = Value::build_text("bob");
3101        assert_eq!(
3102            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3103            expected_str
3104        );
3105
3106        let input_str = Value::build_text("bob");
3107        let pattern_str = Value::build_text("");
3108        let replace_str = Value::build_text("a");
3109        let expected_str = Value::build_text("bob");
3110        assert_eq!(
3111            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3112            expected_str
3113        );
3114
3115        let input_str = Value::build_text("bob");
3116        let pattern_str = Value::Null;
3117        let replace_str = Value::build_text("a");
3118        let expected_str = Value::Null;
3119        assert_eq!(
3120            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3121            expected_str
3122        );
3123
3124        let input_str = Value::build_text("bo5");
3125        let pattern_str = Value::from_i64(5);
3126        let replace_str = Value::build_text("a");
3127        let expected_str = Value::build_text("boa");
3128        assert_eq!(
3129            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3130            expected_str
3131        );
3132
3133        let input_str = Value::build_text("bo5.0");
3134        let pattern_str = Value::from_f64(5.0);
3135        let replace_str = Value::build_text("a");
3136        let expected_str = Value::build_text("boa");
3137        assert_eq!(
3138            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3139            expected_str
3140        );
3141
3142        let input_str = Value::build_text("bo5");
3143        let pattern_str = Value::from_f64(5.0);
3144        let replace_str = Value::build_text("a");
3145        let expected_str = Value::build_text("bo5");
3146        assert_eq!(
3147            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3148            expected_str
3149        );
3150
3151        let input_str = Value::build_text("bo5.0");
3152        let pattern_str = Value::from_f64(5.0);
3153        let replace_str = Value::from_f64(6.0);
3154        let expected_str = Value::build_text("bo6.0");
3155        assert_eq!(
3156            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3157            expected_str
3158        );
3159
3160        // todo: change this test to use (0.1 + 0.2) instead of 0.3 when decimals are implemented.
3161        let input_str = Value::build_text("tes3");
3162        let pattern_str = Value::from_i64(3);
3163        let replace_str = Value::from_f64(0.3);
3164        let expected_str = Value::build_text("tes0.3");
3165        assert_eq!(
3166            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3167            expected_str
3168        );
3169    }
3170}