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! { function, MathFunc::Ceil | MathFunc::Ceiling | MathFunc::Floor | MathFunc::Trunc }
985            {
986                return Value::from_i64(i);
987            }
988        }
989
990        let Some(f) = v.map(|v| v.to_f64()) else {
991            return Value::Null;
992        };
993
994        if matches! { function, MathFunc::Ln | MathFunc::Log10 | MathFunc::Log2 } && f <= 0.0 {
995            return Value::Null;
996        }
997
998        #[allow(unused_unsafe)]
999        let result = match function {
1000            MathFunc::Acos => unsafe { cmath::acos(f) },
1001            MathFunc::Acosh => unsafe { cmath::acosh(f) },
1002            MathFunc::Asin => unsafe { cmath::asin(f) },
1003            MathFunc::Asinh => unsafe { cmath::asinh(f) },
1004            MathFunc::Atan => unsafe { cmath::atan(f) },
1005            MathFunc::Atanh => unsafe { cmath::atanh(f) },
1006            MathFunc::Ceil | MathFunc::Ceiling => libm::ceil(f),
1007            MathFunc::Cos => unsafe { cmath::cos(f) },
1008            MathFunc::Cosh => unsafe { cmath::cosh(f) },
1009            MathFunc::Degrees => cmath::degrees(f),
1010            MathFunc::Exp => unsafe { cmath::exp(f) },
1011            MathFunc::Floor => libm::floor(f),
1012            MathFunc::Ln => unsafe { cmath::log(f) },
1013            MathFunc::Log10 => unsafe { cmath::log10(f) },
1014            MathFunc::Log2 => unsafe { cmath::log2(f) },
1015            MathFunc::Radians => cmath::radians(f),
1016            MathFunc::Sin => unsafe { cmath::sin(f) },
1017            MathFunc::Sinh => unsafe { cmath::sinh(f) },
1018            MathFunc::Sqrt => libm::sqrt(f),
1019            MathFunc::Tan => unsafe { cmath::tan(f) },
1020            MathFunc::Tanh => unsafe { cmath::tanh(f) },
1021            MathFunc::Trunc => libm::trunc(f),
1022            _ => unreachable!("Unexpected mathematical unary function {:?}", function),
1023        };
1024
1025        if result.is_nan() {
1026            Value::Null
1027        } else {
1028            Value::from_f64(result)
1029        }
1030    }
1031
1032    pub fn exec_math_binary(&self, rhs: &Value, function: &MathFunc) -> Value {
1033        let Some(lhs) = Numeric::from_value_strict(self).map(|v| v.to_f64()) else {
1034            return Value::Null;
1035        };
1036
1037        let Some(rhs) = Numeric::from_value_strict(rhs).map(|v| v.to_f64()) else {
1038            return Value::Null;
1039        };
1040
1041        #[allow(unused_unsafe)]
1042        let result = match function {
1043            MathFunc::Atan2 => unsafe { cmath::atan2(lhs, rhs) },
1044            MathFunc::Mod => libm::fmod(lhs, rhs),
1045            MathFunc::Pow | MathFunc::Power => unsafe { cmath::pow(lhs, rhs) },
1046            _ => unreachable!("Unexpected mathematical binary function {:?}", function),
1047        };
1048
1049        if result.is_nan() {
1050            Value::Null
1051        } else {
1052            Value::from_f64(result)
1053        }
1054    }
1055
1056    pub fn exec_math_log(&self, base: Option<&Value>) -> Value {
1057        let Some(f) = Numeric::from_value_strict(self).map(|v| v.to_f64()) else {
1058            return Value::Null;
1059        };
1060
1061        let base = match base.map(|value| Numeric::from_value_strict(value).map(|v| v.to_f64())) {
1062            Some(Some(f)) => f,
1063            Some(None) => return Value::Null,
1064            None => 10.0,
1065        };
1066
1067        if f <= 0.0 || base <= 0.0 || base == 1.0 {
1068            return Value::Null;
1069        }
1070
1071        if base == 2.0 {
1072            return Value::from_f64(libm::log2(f));
1073        } else if base == 10.0 {
1074            return Value::from_f64(libm::log10(f));
1075        };
1076
1077        let log_x = libm::log(f);
1078        let log_base = libm::log(base);
1079
1080        if log_base <= 0.0 {
1081            return Value::Null;
1082        }
1083
1084        let result = log_x / log_base;
1085        Value::from_f64(result)
1086    }
1087
1088    pub fn exec_add(&self, rhs: &Value) -> Value {
1089        (|| Numeric::from_value(self)?.checked_add(Numeric::from_value(rhs)?))().into()
1090    }
1091
1092    pub fn exec_subtract(&self, rhs: &Value) -> Value {
1093        (|| Numeric::from_value(self)?.checked_sub(Numeric::from_value(rhs)?))().into()
1094    }
1095
1096    pub fn exec_multiply(&self, rhs: &Value) -> Value {
1097        (|| Numeric::from_value(self)?.checked_mul(Numeric::from_value(rhs)?))().into()
1098    }
1099
1100    pub fn exec_divide(&self, rhs: &Value) -> Value {
1101        (|| Numeric::from_value(self)?.checked_div(Numeric::from_value(rhs)?))().into()
1102    }
1103
1104    pub fn exec_bit_and(&self, rhs: &Value) -> Value {
1105        (NullableInteger::from(self) & NullableInteger::from(rhs)).into()
1106    }
1107
1108    pub fn exec_bit_or(&self, rhs: &Value) -> Value {
1109        (NullableInteger::from(self) | NullableInteger::from(rhs)).into()
1110    }
1111
1112    pub fn exec_remainder(&self, rhs: &Value) -> Value {
1113        let convert_to_float = matches!(Numeric::from_value(self), Some(Numeric::Float(_)))
1114            || matches!(Numeric::from_value(rhs), Some(Numeric::Float(_)));
1115
1116        match NullableInteger::from(self) % NullableInteger::from(rhs) {
1117            NullableInteger::Null => Value::Null,
1118            NullableInteger::Integer(v) => {
1119                if convert_to_float {
1120                    Value::from_f64(v as f64)
1121                } else {
1122                    Value::from_i64(v)
1123                }
1124            }
1125        }
1126    }
1127
1128    pub fn exec_bit_not(&self) -> Value {
1129        (!NullableInteger::from(self)).into()
1130    }
1131
1132    pub fn exec_shift_left(&self, rhs: &Value) -> Value {
1133        (NullableInteger::from(self) << NullableInteger::from(rhs)).into()
1134    }
1135
1136    pub fn exec_shift_right(&self, rhs: &Value) -> Value {
1137        (NullableInteger::from(self) >> NullableInteger::from(rhs)).into()
1138    }
1139
1140    pub fn exec_boolean_not(&self) -> Value {
1141        match Numeric::from_value(self).map(|v| v.to_bool()) {
1142            None => Value::Null,
1143            Some(v) => Value::from_i64(!v as i64),
1144        }
1145    }
1146
1147    pub fn exec_concat(&self, rhs: &Value) -> Value {
1148        if let (Value::Blob(lhs), Value::Blob(rhs)) = (self, rhs) {
1149            return Value::Blob([lhs.as_slice(), rhs.as_slice()].concat());
1150        }
1151
1152        let Some(lhs) = self.cast_text() else {
1153            return Value::Null;
1154        };
1155
1156        let Some(rhs) = rhs.cast_text() else {
1157            return Value::Null;
1158        };
1159
1160        Value::build_text(lhs + &rhs)
1161    }
1162
1163    pub fn exec_and(&self, rhs: &Value) -> Value {
1164        match (
1165            Numeric::from_value(self).map(|v| v.to_bool()),
1166            Numeric::from_value(rhs).map(|v| v.to_bool()),
1167        ) {
1168            (Some(false), _) | (_, Some(false)) => Value::from_i64(0),
1169            (None, _) | (_, None) => Value::Null,
1170            _ => Value::from_i64(1),
1171        }
1172    }
1173
1174    pub fn exec_or(&self, rhs: &Value) -> Value {
1175        match (
1176            Numeric::from_value(self).map(|v| v.to_bool()),
1177            Numeric::from_value(rhs).map(|v| v.to_bool()),
1178        ) {
1179            (Some(true), _) | (_, Some(true)) => Value::from_i64(1),
1180            (None, _) | (_, None) => Value::Null,
1181            _ => Value::from_i64(0),
1182        }
1183    }
1184
1185    pub fn exec_like(pattern: &str, text: &str, escape: Option<char>) -> Result<bool, LimboError> {
1186        const MAX_LIKE_PATTERN_LENGTH: usize = 50000;
1187        if pattern.len() > MAX_LIKE_PATTERN_LENGTH {
1188            return Err(LimboError::Constraint(
1189                "LIKE or GLOB pattern too complex".to_string(),
1190            ));
1191        }
1192        let pattern = sqlite_text_prefix(pattern);
1193        let text = sqlite_text_prefix(text);
1194
1195        let has_escape = escape.is_some_and(|e| pattern.contains(e));
1196
1197        // 1. Exact match (no wildcards)
1198        if !has_escape && !pattern.contains(['%', '_']) {
1199            return Ok(pattern.eq_ignore_ascii_case(text));
1200        }
1201
1202        // 2. Fast Path: 'abc%' (Prefix)
1203        if !has_escape
1204            && pattern.ends_with('%')
1205            && !pattern[..pattern.len() - 1].contains(['%', '_'])
1206        {
1207            let prefix = &pattern[..pattern.len() - 1];
1208            if text.len() >= prefix.len() && text.is_char_boundary(prefix.len()) {
1209                return Ok(text[..prefix.len()].eq_ignore_ascii_case(prefix));
1210            }
1211            // Fall through to pattern_compare if boundary check fails (multi-byte UTF-8)
1212        }
1213
1214        // 3. Fast Path: '%abc' (Suffix)
1215        if !has_escape && pattern.starts_with('%') && !pattern[1..].contains(['%', '_']) {
1216            let suffix = &pattern[1..];
1217            let start = text.len().wrapping_sub(suffix.len());
1218            if text.len() >= suffix.len() && text.is_char_boundary(start) {
1219                return Ok(text[start..].eq_ignore_ascii_case(suffix));
1220            }
1221            // Fall through to pattern_compare if boundary check fails (multi-byte UTF-8)
1222        }
1223
1224        Ok(pattern_compare(pattern, text, &LIKE_INFO, escape) == CompareResult::Match)
1225    }
1226
1227    pub fn exec_glob(pattern: &str, text: &str) -> Result<bool, LimboError> {
1228        const MAX_GLOB_PATTERN_LENGTH: usize = 50000;
1229        const GLOB_CHARS: [char; 3] = ['*', '?', '['];
1230
1231        if pattern.len() > MAX_GLOB_PATTERN_LENGTH {
1232            return Err(LimboError::Constraint(
1233                "GLOB pattern too complex".to_string(),
1234            ));
1235        }
1236        let pattern = sqlite_text_prefix(pattern);
1237        let text = sqlite_text_prefix(text);
1238
1239        // 1. Exact match (no wildcards)
1240        if !pattern.contains(GLOB_CHARS) {
1241            return Ok(pattern == text);
1242        }
1243
1244        // 2. Fast Path: 'abc*' (Prefix)
1245        if pattern.ends_with('*') && !pattern[..pattern.len() - 1].contains(GLOB_CHARS) {
1246            let prefix = &pattern[..pattern.len() - 1];
1247            if text.len() >= prefix.len() && text.is_char_boundary(prefix.len()) {
1248                return Ok(&text[..prefix.len()] == prefix);
1249            }
1250            // Fall through to pattern_compare if boundary check fails (multi-byte UTF-8)
1251        }
1252
1253        // 3. Fast Path: '*abc' (Suffix)
1254        if pattern.starts_with('*') && !pattern[1..].contains(GLOB_CHARS) {
1255            let suffix = &pattern[1..];
1256            let start = text.len().wrapping_sub(suffix.len());
1257            if text.len() >= suffix.len() && text.is_char_boundary(start) {
1258                return Ok(&text[start..] == suffix);
1259            }
1260            // Fall through to pattern_compare if boundary check fails (multi-byte UTF-8)
1261        }
1262
1263        Ok(pattern_compare(pattern, text, &GLOB_INFO, None) == CompareResult::Match)
1264    }
1265
1266    pub fn exec_min<'a, T: Iterator<Item = &'a Value>>(regs: T) -> Value {
1267        // SQLite: multi-arg min() returns NULL if ANY argument is NULL
1268        let mut result: Option<&Value> = None;
1269        for v in regs {
1270            if matches!(v, Value::Null) {
1271                return Value::Null;
1272            }
1273            result = Some(match result {
1274                None => v,
1275                Some(cur) if v < cur => v,
1276                Some(cur) => cur,
1277            });
1278        }
1279        result.map(|v| v.to_owned()).unwrap_or(Value::Null)
1280    }
1281
1282    pub fn exec_max<'a, T: Iterator<Item = &'a Value>>(regs: T) -> Value {
1283        // SQLite: multi-arg max() returns NULL if ANY argument is NULL
1284        let mut result: Option<&Value> = None;
1285        for v in regs {
1286            if matches!(v, Value::Null) {
1287                return Value::Null;
1288            }
1289            result = Some(match result {
1290                None => v,
1291                Some(cur) if v > cur => v,
1292                Some(cur) => cur,
1293            });
1294        }
1295        result.map(|v| v.to_owned()).unwrap_or(Value::Null)
1296    }
1297
1298    /// Concatenate another value onto this Text value, converting both to strings.
1299    /// Used by GROUP_CONCAT/STRING_AGG to properly handle all value types.
1300    /// Panics if self is not a Text value.
1301    pub fn exec_group_concat(&mut self, other: &Value) {
1302        let Value::Text(text) = self else {
1303            panic!("concat_to_text must be called only on Value::Text");
1304        };
1305        text.value.to_mut().push_str(&other.to_string());
1306    }
1307
1308    pub fn exec_concat_strings<'a, T: Iterator<Item = &'a Self>>(registers: T) -> Self {
1309        let mut result = String::new();
1310        for val in registers {
1311            match val {
1312                Value::Null => continue,
1313                Value::Text(s) => result.push_str(s.as_str()),
1314                Value::Blob(b) => result.push_str(&String::from_utf8_lossy(b)),
1315                Value::Numeric(Numeric::Integer(i)) => result.push_str(&i.to_string()),
1316                Value::Numeric(Numeric::Float(f)) => result.push_str(&format_float(f64::from(*f))),
1317            }
1318        }
1319        Value::build_text(result)
1320    }
1321
1322    pub fn exec_concat_ws<'a, T: ExactSizeIterator<Item = &'a Self>>(mut registers: T) -> Self {
1323        if registers.len() == 0 {
1324            return Value::Null;
1325        }
1326
1327        let separator = match registers
1328            .next()
1329            .expect("registers should have at least one element after length check")
1330        {
1331            Value::Null | Value::Blob(_) => return Value::Null,
1332            v => format!("{v}"),
1333        };
1334
1335        let parts = registers.filter_map(|val| match val {
1336            Value::Text(_) | Value::Numeric(_) => Some(format!("{val}")),
1337            _ => None,
1338        });
1339
1340        let result = parts.collect::<Vec<_>>().join(&separator);
1341        Value::build_text(result)
1342    }
1343
1344    pub fn exec_char<'a, T: Iterator<Item = &'a Self>>(values: T) -> Self {
1345        let result: String = values
1346            .filter_map(|x| match x {
1347                Value::Numeric(Numeric::Integer(i)) => {
1348                    // Convert integer to Unicode codepoint.
1349                    // For invalid codepoints (negative, surrogates, or > U+10FFFF),
1350                    // output U+FFFD (replacement character) to match SQLite behavior.
1351                    if *i >= 0 {
1352                        Some(char::from_u32(*i as u32).unwrap_or('\u{FFFD}'))
1353                    } else {
1354                        Some('\u{FFFD}')
1355                    }
1356                }
1357                // NULL arguments produce NUL characters to match SQLite behavior.
1358                Value::Null => Some('\0'),
1359                _ => None,
1360            })
1361            .collect();
1362        Value::build_text(result)
1363    }
1364}
1365
1366/// Parse exactly `n` hex digits into a u32. Mirrors SQLite's isNHex().
1367fn parse_n_hex(bytes: &[u8], n: usize) -> Result<u32> {
1368    if bytes.len() < n {
1369        return Err(LimboError::ParseError("invalid Unicode escape".to_string()));
1370    }
1371    let mut v: u32 = 0;
1372    for &b in &bytes[..n] {
1373        let digit = match b {
1374            b'0'..=b'9' => b - b'0',
1375            b'a'..=b'f' => b - b'a' + 10,
1376            b'A'..=b'F' => b - b'A' + 10,
1377            _ => return Err(LimboError::ParseError("invalid Unicode escape".to_string())),
1378        };
1379        v = (v << 4) | digit as u32;
1380    }
1381    Ok(v)
1382}
1383
1384/// Result of LIKE pattern comparison.
1385/// `NoWildcardMatch` signals an early abort when a literal after `%` cannot be found,
1386/// allowing the algorithm to skip unnecessary backtracking.
1387#[derive(PartialEq)]
1388enum CompareResult {
1389    Match,
1390    NoMatch,
1391    NoWildcardMatch,
1392}
1393
1394struct PatternInfo {
1395    match_all: char,
1396    match_one: char,
1397    match_set: Option<char>,
1398    no_case: bool,
1399}
1400
1401const LIKE_INFO: PatternInfo = PatternInfo {
1402    match_all: '%',
1403    match_one: '_',
1404    match_set: None,
1405    no_case: true,
1406};
1407
1408const GLOB_INFO: PatternInfo = PatternInfo {
1409    match_all: '*',
1410    match_one: '?',
1411    match_set: Some('['),
1412    no_case: false,
1413};
1414
1415/// LIKE and GLOB pattern matching based on SQLite's patternCompare algorithm (src/func.c).
1416/// Uses recursive descent with early termination via `NoWildcardMatch` to avoid
1417/// exponential backtracking on patterns like `%a%a%a%...%b`.
1418/// Ref: https://github.com/sqlite/sqlite/blob/master/src/func.c#L728
1419fn pattern_compare(
1420    pattern: &str,
1421    text: &str,
1422    info: &PatternInfo,
1423    escape: Option<char>,
1424) -> CompareResult {
1425    let mut p_indices = pattern.char_indices();
1426    let mut t_indices = text.char_indices();
1427
1428    let mut p_curr = p_indices.next();
1429    let mut t_curr = t_indices.next();
1430
1431    // Checkpoints for backtracking
1432    let mut wildcard_p_iter: Option<std::str::CharIndices> = None;
1433    let mut wildcard_t_iter: Option<std::str::CharIndices> = None;
1434
1435    loop {
1436        match (p_curr, t_curr) {
1437            (Some((_, p_char)), Some((_, t_char))) => {
1438                if p_char == info.match_all && Some(p_char) != escape {
1439                    // Consume consecutive match_alls
1440                    let mut next_p = p_indices.clone();
1441                    while let Some((_, c)) = next_p.clone().next() {
1442                        if c == info.match_all && Some(c) != escape {
1443                            next_p.next();
1444                        } else {
1445                            break;
1446                        }
1447                    }
1448
1449                    let mut lookahead_p = next_p.clone();
1450                    if let Some((_, next_char)) = lookahead_p.next() {
1451                        let is_wildcard = (next_char == info.match_all
1452                            && Some(next_char) != escape)
1453                            || (next_char == info.match_one && Some(next_char) != escape)
1454                            || (info.match_set == Some(next_char));
1455
1456                        let is_escaped_next = Some(next_char) == escape;
1457
1458                        if !is_wildcard && !is_escaped_next {
1459                            let mut found = false;
1460
1461                            // Check current text char
1462                            if compare_chars(next_char, t_char, info.no_case) {
1463                                found = true;
1464                            } else {
1465                                // Scan remaining text
1466                                let lookahead_t = t_indices.clone();
1467                                for (_, t_c) in lookahead_t {
1468                                    if compare_chars(next_char, t_c, info.no_case) {
1469                                        found = true;
1470                                        break;
1471                                    }
1472                                }
1473                            }
1474
1475                            if !found {
1476                                return CompareResult::NoWildcardMatch;
1477                            }
1478                        }
1479                    }
1480
1481                    p_indices = next_p;
1482                    wildcard_p_iter = Some(p_indices.clone());
1483                    p_curr = p_indices.next();
1484
1485                    if p_curr.is_none() {
1486                        return CompareResult::Match;
1487                    }
1488
1489                    wildcard_t_iter = Some(t_indices.clone());
1490                    continue;
1491                }
1492
1493                if p_char == info.match_one && Some(p_char) != escape {
1494                    p_curr = p_indices.next();
1495                    t_curr = t_indices.next();
1496                    continue;
1497                }
1498
1499                // Handle Set (GLOB only)
1500                if info.match_set == Some(p_char) {
1501                    let mut seen = false;
1502                    let mut invert = false;
1503                    let c = t_char;
1504
1505                    let mut next_c_opt = p_indices.next();
1506
1507                    if let Some((_, c2)) = next_c_opt {
1508                        if c2 == '^' {
1509                            invert = true;
1510                            next_c_opt = p_indices.next();
1511                        }
1512                    }
1513
1514                    let mut c2_opt = next_c_opt;
1515                    if let Some((_, c2)) = c2_opt {
1516                        if c2 == ']' {
1517                            if c == ']' {
1518                                seen = true;
1519                            }
1520                            c2_opt = p_indices.next();
1521                        }
1522                    }
1523
1524                    let mut prior_c: Option<char> = None;
1525
1526                    while let Some((_, c2)) = c2_opt {
1527                        if c2 == ']' {
1528                            break;
1529                        }
1530
1531                        let mut is_range = false;
1532                        if c2 == '-' && prior_c.is_some() {
1533                            let lookahead = p_indices.clone().next();
1534                            if let Some((_, c3)) = lookahead {
1535                                if c3 != ']' {
1536                                    is_range = true;
1537                                    let start = prior_c.unwrap();
1538                                    let end = c3;
1539                                    if c >= start && c <= end {
1540                                        seen = true;
1541                                    }
1542                                    p_indices.next();
1543                                    prior_c = None;
1544                                }
1545                            }
1546                        }
1547
1548                        if !is_range {
1549                            if c == c2 {
1550                                seen = true;
1551                            }
1552                            prior_c = Some(c2);
1553                        }
1554
1555                        c2_opt = p_indices.next();
1556                    }
1557
1558                    if c2_opt.is_none() || !(seen ^ invert) {
1559                        // Fallthrough to backtracking
1560                    } else {
1561                        p_curr = p_indices.next();
1562                        t_curr = t_indices.next();
1563                        continue;
1564                    }
1565                } else {
1566                    let (expected_char, next_p_iter) = if Some(p_char) == escape {
1567                        if let Some((_, literal)) = p_indices.next() {
1568                            (literal, p_indices.clone())
1569                        } else {
1570                            return CompareResult::NoMatch;
1571                        }
1572                    } else {
1573                        (p_char, p_indices.clone())
1574                    };
1575
1576                    if compare_chars(expected_char, t_char, info.no_case) {
1577                        p_indices = next_p_iter;
1578                        p_curr = p_indices.next();
1579                        t_curr = t_indices.next();
1580                        continue;
1581                    }
1582                }
1583            }
1584            (None, None) => return CompareResult::Match,
1585            (Some((_, p_char)), None) if p_char == info.match_all && Some(p_char) != escape => {
1586                let mut temp = p_indices.clone();
1587                loop {
1588                    match temp.next() {
1589                        Some((_, c)) if c == info.match_all && Some(c) != escape => continue,
1590                        None => return CompareResult::Match,
1591                        _ => break,
1592                    }
1593                }
1594            }
1595            _ => {}
1596        }
1597
1598        // Backtracking
1599        if let (Some(wp), Some(wt)) = (wildcard_p_iter.clone(), wildcard_t_iter.clone()) {
1600            p_indices = wp;
1601            p_curr = p_indices.next();
1602            t_indices = wt.clone();
1603            t_curr = t_indices.next();
1604
1605            if t_curr.is_some() {
1606                wildcard_t_iter = Some(t_indices.clone());
1607                continue;
1608            }
1609        }
1610
1611        return CompareResult::NoMatch;
1612    }
1613}
1614
1615fn compare_chars(p: char, t: char, no_case: bool) -> bool {
1616    if no_case {
1617        p.eq_ignore_ascii_case(&t)
1618    } else {
1619        p == t
1620    }
1621}
1622
1623#[cfg(clt_turso_tests)]
1624mod tests {
1625    use crate::numeric::Numeric;
1626    use crate::types::Value;
1627    use crate::vdbe::Register;
1628
1629    use rand::{Rng, RngCore};
1630
1631    #[test]
1632    fn test_exec_add() {
1633        let inputs = vec![
1634            (Value::from_i64(3), Value::from_i64(1)),
1635            (Value::from_f64(3.0), Value::from_f64(1.0)),
1636            (Value::from_f64(3.0), Value::from_i64(1)),
1637            (Value::from_i64(3), Value::from_f64(1.0)),
1638            (Value::Null, Value::Null),
1639            (Value::Null, Value::from_i64(1)),
1640            (Value::Null, Value::from_f64(1.0)),
1641            (Value::Null, Value::Text("2".into())),
1642            (Value::from_i64(1), Value::Null),
1643            (Value::from_f64(1.0), Value::Null),
1644            (Value::Text("1".into()), Value::Null),
1645            (Value::Text("1".into()), Value::Text("3".into())),
1646            (Value::Text("1.0".into()), Value::Text("3.0".into())),
1647            (Value::Text("1.0".into()), Value::from_f64(3.0)),
1648            (Value::Text("1.0".into()), Value::from_i64(3)),
1649            (Value::from_f64(1.0), Value::Text("3.0".into())),
1650            (Value::from_i64(1), Value::Text("3".into())),
1651        ];
1652
1653        let outputs = [
1654            Value::from_i64(4),
1655            Value::from_f64(4.0),
1656            Value::from_f64(4.0),
1657            Value::from_f64(4.0),
1658            Value::Null,
1659            Value::Null,
1660            Value::Null,
1661            Value::Null,
1662            Value::Null,
1663            Value::Null,
1664            Value::Null,
1665            Value::from_i64(4),
1666            Value::from_f64(4.0),
1667            Value::from_f64(4.0),
1668            Value::from_f64(4.0),
1669            Value::from_f64(4.0),
1670            Value::from_f64(4.0),
1671        ];
1672
1673        assert_eq!(
1674            inputs.len(),
1675            outputs.len(),
1676            "Inputs and Outputs should have same size"
1677        );
1678        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1679            assert_eq!(
1680                lhs.exec_add(rhs),
1681                outputs[i],
1682                "Wrong ADD for lhs: {lhs}, rhs: {rhs}"
1683            );
1684        }
1685    }
1686
1687    #[test]
1688    fn test_exec_subtract() {
1689        let inputs = vec![
1690            (Value::from_i64(3), Value::from_i64(1)),
1691            (Value::from_f64(3.0), Value::from_f64(1.0)),
1692            (Value::from_f64(3.0), Value::from_i64(1)),
1693            (Value::from_i64(3), Value::from_f64(1.0)),
1694            (Value::Null, Value::Null),
1695            (Value::Null, Value::from_i64(1)),
1696            (Value::Null, Value::from_f64(1.0)),
1697            (Value::Null, Value::Text("1".into())),
1698            (Value::from_i64(1), Value::Null),
1699            (Value::from_f64(1.0), Value::Null),
1700            (Value::Text("4".into()), Value::Null),
1701            (Value::Text("1".into()), Value::Text("3".into())),
1702            (Value::Text("1.0".into()), Value::Text("3.0".into())),
1703            (Value::Text("1.0".into()), Value::from_f64(3.0)),
1704            (Value::Text("1.0".into()), Value::from_i64(3)),
1705            (Value::from_f64(1.0), Value::Text("3.0".into())),
1706            (Value::from_i64(1), Value::Text("3".into())),
1707        ];
1708
1709        let outputs = [
1710            Value::from_i64(2),
1711            Value::from_f64(2.0),
1712            Value::from_f64(2.0),
1713            Value::from_f64(2.0),
1714            Value::Null,
1715            Value::Null,
1716            Value::Null,
1717            Value::Null,
1718            Value::Null,
1719            Value::Null,
1720            Value::Null,
1721            Value::from_i64(-2),
1722            Value::from_f64(-2.0),
1723            Value::from_f64(-2.0),
1724            Value::from_f64(-2.0),
1725            Value::from_f64(-2.0),
1726            Value::from_f64(-2.0),
1727        ];
1728
1729        assert_eq!(
1730            inputs.len(),
1731            outputs.len(),
1732            "Inputs and Outputs should have same size"
1733        );
1734        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1735            assert_eq!(
1736                lhs.exec_subtract(rhs),
1737                outputs[i],
1738                "Wrong subtract for lhs: {lhs}, rhs: {rhs}"
1739            );
1740        }
1741    }
1742
1743    #[test]
1744    fn test_exec_multiply() {
1745        let inputs = vec![
1746            (Value::from_i64(3), Value::from_i64(2)),
1747            (Value::from_f64(3.0), Value::from_f64(2.0)),
1748            (Value::from_f64(3.0), Value::from_i64(2)),
1749            (Value::from_i64(3), Value::from_f64(2.0)),
1750            (Value::Null, Value::Null),
1751            (Value::Null, Value::from_i64(1)),
1752            (Value::Null, Value::from_f64(1.0)),
1753            (Value::Null, Value::Text("1".into())),
1754            (Value::from_i64(1), Value::Null),
1755            (Value::from_f64(1.0), Value::Null),
1756            (Value::Text("4".into()), Value::Null),
1757            (Value::Text("2".into()), Value::Text("3".into())),
1758            (Value::Text("2.0".into()), Value::Text("3.0".into())),
1759            (Value::Text("2.0".into()), Value::from_f64(3.0)),
1760            (Value::Text("2.0".into()), Value::from_i64(3)),
1761            (Value::from_f64(2.0), Value::Text("3.0".into())),
1762            (Value::from_i64(2), Value::Text("3.0".into())),
1763        ];
1764
1765        let outputs = [
1766            Value::from_i64(6),
1767            Value::from_f64(6.0),
1768            Value::from_f64(6.0),
1769            Value::from_f64(6.0),
1770            Value::Null,
1771            Value::Null,
1772            Value::Null,
1773            Value::Null,
1774            Value::Null,
1775            Value::Null,
1776            Value::Null,
1777            Value::from_i64(6),
1778            Value::from_f64(6.0),
1779            Value::from_f64(6.0),
1780            Value::from_f64(6.0),
1781            Value::from_f64(6.0),
1782            Value::from_f64(6.0),
1783        ];
1784
1785        assert_eq!(
1786            inputs.len(),
1787            outputs.len(),
1788            "Inputs and Outputs should have same size"
1789        );
1790        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1791            assert_eq!(
1792                lhs.exec_multiply(rhs),
1793                outputs[i],
1794                "Wrong multiply for lhs: {lhs}, rhs: {rhs}"
1795            );
1796        }
1797    }
1798
1799    #[test]
1800    fn test_exec_divide() {
1801        let inputs = vec![
1802            (Value::from_i64(1), Value::from_i64(0)),
1803            (Value::from_f64(1.0), Value::from_f64(0.0)),
1804            (Value::from_i64(i64::MIN), Value::from_i64(-1)),
1805            (Value::from_f64(6.0), Value::from_f64(2.0)),
1806            (Value::from_f64(6.0), Value::from_i64(2)),
1807            (Value::from_i64(6), Value::from_i64(2)),
1808            (Value::Null, Value::from_i64(2)),
1809            (Value::from_i64(2), Value::Null),
1810            (Value::Null, Value::Null),
1811            (Value::Text("6".into()), Value::Text("2".into())),
1812            (Value::Text("6".into()), Value::from_i64(2)),
1813        ];
1814
1815        let outputs = [
1816            Value::Null,
1817            Value::Null,
1818            Value::from_f64(9.223372036854776e18),
1819            Value::from_f64(3.0),
1820            Value::from_f64(3.0),
1821            Value::from_f64(3.0),
1822            Value::Null,
1823            Value::Null,
1824            Value::Null,
1825            Value::from_f64(3.0),
1826            Value::from_f64(3.0),
1827        ];
1828
1829        assert_eq!(
1830            inputs.len(),
1831            outputs.len(),
1832            "Inputs and Outputs should have same size"
1833        );
1834        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1835            assert_eq!(
1836                lhs.exec_divide(rhs),
1837                outputs[i],
1838                "Wrong divide for lhs: {lhs}, rhs: {rhs}"
1839            );
1840        }
1841    }
1842
1843    #[test]
1844    fn test_exec_remainder() {
1845        let inputs = vec![
1846            (Value::Null, Value::Null),
1847            (Value::Null, Value::from_f64(1.0)),
1848            (Value::Null, Value::from_i64(1)),
1849            (Value::Null, Value::Text("1".into())),
1850            (Value::from_f64(1.0), Value::Null),
1851            (Value::from_i64(1), Value::Null),
1852            (Value::from_i64(12), Value::from_i64(0)),
1853            (Value::from_f64(12.0), Value::from_f64(0.0)),
1854            (Value::from_f64(12.0), Value::from_i64(0)),
1855            (Value::from_i64(12), Value::from_f64(0.0)),
1856            (Value::from_i64(i64::MIN), Value::from_i64(-1)),
1857            (Value::from_i64(12), Value::from_i64(3)),
1858            (Value::from_f64(12.0), Value::from_f64(3.0)),
1859            (Value::from_f64(12.0), Value::from_i64(3)),
1860            (Value::from_i64(12), Value::from_f64(3.0)),
1861            (Value::from_i64(12), Value::from_i64(-3)),
1862            (Value::from_f64(12.0), Value::from_f64(-3.0)),
1863            (Value::from_f64(12.0), Value::from_i64(-3)),
1864            (Value::from_i64(12), Value::from_f64(-3.0)),
1865            (Value::Text("12.0".into()), Value::Text("3.0".into())),
1866            (Value::Text("12.0".into()), Value::from_f64(3.0)),
1867            (Value::from_f64(12.0), Value::Text("3.0".into())),
1868        ];
1869        let outputs = vec![
1870            Value::Null,
1871            Value::Null,
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::from_f64(0.0),
1881            Value::from_i64(0),
1882            Value::from_f64(0.0),
1883            Value::from_f64(0.0),
1884            Value::from_f64(0.0),
1885            Value::from_i64(0),
1886            Value::from_f64(0.0),
1887            Value::from_f64(0.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        ];
1893
1894        assert_eq!(
1895            inputs.len(),
1896            outputs.len(),
1897            "Inputs and Outputs should have same size"
1898        );
1899
1900        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1901            assert_eq!(
1902                lhs.exec_remainder(rhs),
1903                outputs[i],
1904                "Wrong remainder for lhs: {lhs}, rhs: {rhs}"
1905            );
1906        }
1907    }
1908
1909    #[test]
1910    fn test_exec_and() {
1911        let inputs = vec![
1912            (Value::from_i64(0), Value::Null),
1913            (Value::Null, Value::from_i64(1)),
1914            (Value::Null, Value::Null),
1915            (Value::from_f64(0.0), Value::Null),
1916            (Value::from_i64(1), Value::from_f64(2.2)),
1917            (Value::from_i64(0), Value::Text("string".into())),
1918            (Value::from_i64(0), Value::Text("1".into())),
1919            (Value::from_i64(1), Value::Text("1".into())),
1920        ];
1921        let outputs = [
1922            Value::from_i64(0),
1923            Value::Null,
1924            Value::Null,
1925            Value::from_i64(0),
1926            Value::from_i64(1),
1927            Value::from_i64(0),
1928            Value::from_i64(0),
1929            Value::from_i64(1),
1930        ];
1931
1932        assert_eq!(
1933            inputs.len(),
1934            outputs.len(),
1935            "Inputs and Outputs should have same size"
1936        );
1937        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1938            assert_eq!(
1939                lhs.exec_and(rhs),
1940                outputs[i],
1941                "Wrong AND for lhs: {lhs}, rhs: {rhs}"
1942            );
1943        }
1944    }
1945
1946    #[test]
1947    fn test_exec_or() {
1948        let inputs = vec![
1949            (Value::from_i64(0), Value::Null),
1950            (Value::Null, Value::from_i64(1)),
1951            (Value::Null, Value::Null),
1952            (Value::from_f64(0.0), Value::Null),
1953            (Value::from_i64(1), Value::from_f64(2.2)),
1954            (Value::from_f64(0.0), Value::from_i64(0)),
1955            (Value::from_i64(0), Value::Text("string".into())),
1956            (Value::from_i64(0), Value::Text("1".into())),
1957            (Value::from_i64(0), Value::Text("".into())),
1958        ];
1959        let outputs = [
1960            Value::Null,
1961            Value::from_i64(1),
1962            Value::Null,
1963            Value::Null,
1964            Value::from_i64(1),
1965            Value::from_i64(0),
1966            Value::from_i64(0),
1967            Value::from_i64(1),
1968            Value::from_i64(0),
1969        ];
1970
1971        assert_eq!(
1972            inputs.len(),
1973            outputs.len(),
1974            "Inputs and Outputs should have same size"
1975        );
1976        for (i, (lhs, rhs)) in inputs.iter().enumerate() {
1977            assert_eq!(
1978                lhs.exec_or(rhs),
1979                outputs[i],
1980                "Wrong OR for lhs: {lhs}, rhs: {rhs}"
1981            );
1982        }
1983    }
1984
1985    #[test]
1986    fn test_length() {
1987        let input_str = Value::build_text("bob");
1988        let expected_len = Value::from_i64(3);
1989        assert_eq!(input_str.exec_length(), expected_len);
1990
1991        let input_integer = Value::from_i64(123);
1992        let expected_len = Value::from_i64(3);
1993        assert_eq!(input_integer.exec_length(), expected_len);
1994
1995        let input_float = Value::from_f64(123.456);
1996        let expected_len = Value::from_i64(7);
1997        assert_eq!(input_float.exec_length(), expected_len);
1998
1999        let expected_blob = Value::Blob("example".as_bytes().to_vec());
2000        let expected_len = Value::from_i64(7);
2001        assert_eq!(expected_blob.exec_length(), expected_len);
2002    }
2003
2004    #[test]
2005    fn test_quote() {
2006        let input = Value::build_text("abc\0edf");
2007        let expected = Value::build_text("'abc'");
2008        assert_eq!(input.exec_quote(), expected);
2009
2010        let input = Value::from_i64(123);
2011        let expected = Value::build_text("123");
2012        assert_eq!(input.exec_quote(), expected);
2013
2014        let input = Value::from_f64(12.34);
2015        let expected = Value::build_text("12.34");
2016        assert_eq!(input.exec_quote(), expected);
2017
2018        let input = Value::build_text("hello''world");
2019        let expected = Value::build_text("'hello''''world'");
2020        assert_eq!(input.exec_quote(), expected);
2021
2022        let input = Value::from_f64(
2023            crate::numeric::str_to_f64("2.042747795102219097e+05")
2024                .map(f64::from)
2025                .unwrap(),
2026        );
2027        let expected = Value::build_text("2.042747795102219097e+05");
2028        assert_eq!(input.exec_quote(), expected);
2029    }
2030
2031    #[test]
2032    fn test_typeof() {
2033        let input = Value::Null;
2034        let expected: Value = Value::build_text("null");
2035        assert_eq!(input.exec_typeof(), expected);
2036
2037        let input = Value::from_i64(123);
2038        let expected: Value = Value::build_text("integer");
2039        assert_eq!(input.exec_typeof(), expected);
2040
2041        let input = Value::from_f64(123.456);
2042        let expected: Value = Value::build_text("real");
2043        assert_eq!(input.exec_typeof(), expected);
2044
2045        let input = Value::build_text("hello");
2046        let expected: Value = Value::build_text("text");
2047        assert_eq!(input.exec_typeof(), expected);
2048
2049        let input = Value::Blob("limbo".as_bytes().to_vec());
2050        let expected: Value = Value::build_text("blob");
2051        assert_eq!(input.exec_typeof(), expected);
2052    }
2053
2054    #[test]
2055    fn test_unicode() {
2056        assert_eq!(Value::build_text("a").exec_unicode(), Value::from_i64(97));
2057        assert_eq!(
2058            Value::build_text("😊").exec_unicode(),
2059            Value::from_i64(128522)
2060        );
2061        assert_eq!(Value::build_text("").exec_unicode(), Value::Null);
2062        assert_eq!(Value::build_text("\0").exec_unicode(), Value::Null);
2063        assert_eq!(Value::from_i64(23).exec_unicode(), Value::from_i64(50));
2064        assert_eq!(Value::from_i64(0).exec_unicode(), Value::from_i64(48));
2065        assert_eq!(Value::from_f64(0.0).exec_unicode(), Value::from_i64(48));
2066        assert_eq!(Value::from_f64(23.45).exec_unicode(), Value::from_i64(50));
2067        assert_eq!(Value::Null.exec_unicode(), Value::Null);
2068        assert_eq!(
2069            Value::Blob("example".as_bytes().to_vec()).exec_unicode(),
2070            Value::from_i64(101)
2071        );
2072    }
2073
2074    #[test]
2075    fn test_unistr() {
2076        // Each escape form individually
2077        assert_eq!(
2078            Value::build_text(r"\u0041").exec_unistr().unwrap(),
2079            Value::build_text("A")
2080        );
2081        assert_eq!(
2082            Value::build_text(r"\0041").exec_unistr().unwrap(),
2083            Value::build_text("A")
2084        );
2085        assert_eq!(
2086            Value::build_text(r"\+01F600").exec_unistr().unwrap(),
2087            Value::build_text("😀")
2088        );
2089        assert_eq!(
2090            Value::build_text(r"\U0001F600").exec_unistr().unwrap(),
2091            Value::build_text("😀")
2092        );
2093        // Escaped backslash
2094        assert_eq!(
2095            Value::build_text(r"a\\b").exec_unistr().unwrap(),
2096            Value::build_text(r"a\b")
2097        );
2098        // Hex is case-insensitive
2099        assert_eq!(
2100            Value::build_text(r"\u00E4").exec_unistr().unwrap(),
2101            Value::build_text("ä")
2102        );
2103        assert_eq!(
2104            Value::build_text(r"\u00e4").exec_unistr().unwrap(),
2105            Value::build_text("ä")
2106        );
2107        // Multiple escapes in one string
2108        assert_eq!(
2109            Value::build_text(r"\u0048\u0065\u006C\u006C\u006F")
2110                .exec_unistr()
2111                .unwrap(),
2112            Value::build_text("Hello")
2113        );
2114        // Mixed literal and escape forms
2115        assert_eq!(
2116            Value::build_text(r"hi \u0041 \U0001F600")
2117                .exec_unistr()
2118                .unwrap(),
2119            Value::build_text("hi A 😀")
2120        );
2121        // No escapes
2122        assert_eq!(
2123            Value::build_text("hello").exec_unistr().unwrap(),
2124            Value::build_text("hello")
2125        );
2126        // Empty string
2127        assert_eq!(
2128            Value::build_text("").exec_unistr().unwrap(),
2129            Value::build_text("")
2130        );
2131        // NULL input
2132        assert_eq!(Value::Null.exec_unistr().unwrap(), Value::Null);
2133        // NUL codepoint accepted (matches SQLite, which carries NUL via explicit length)
2134        assert_eq!(
2135            Value::build_text(r"\u0000").exec_unistr().unwrap(),
2136            Value::build_text("\0")
2137        );
2138        // Surrogate rejected (Value::Text requires valid UTF-8)
2139        assert!(Value::build_text(r"\uD83D").exec_unistr().is_err());
2140        // Above U+10FFFF rejected
2141        assert!(Value::build_text(r"\U00110000").exec_unistr().is_err());
2142        // Malformed escapes
2143        assert!(Value::build_text(r"\q").exec_unistr().is_err());
2144        assert!(Value::build_text(r"\u00").exec_unistr().is_err());
2145        assert!(Value::build_text("abc\\").exec_unistr().is_err());
2146        // Non-hex in fixed-width span
2147        assert!(Value::build_text(r"\u00GG").exec_unistr().is_err());
2148        assert!(Value::build_text(r"\+01FG00").exec_unistr().is_err());
2149        assert!(Value::build_text(r"\U0001F6GG").exec_unistr().is_err());
2150    }
2151
2152    #[test]
2153    fn test_unistr_quote() {
2154        assert_eq!(Value::Null.exec_unistr_quote(), Value::build_text("NULL"));
2155        assert_eq!(
2156            Value::from_i64(42).exec_unistr_quote(),
2157            Value::build_text("42")
2158        );
2159        assert_eq!(
2160            Value::from_f64(1.5).exec_unistr_quote(),
2161            Value::build_text("1.5")
2162        );
2163        assert_eq!(
2164            Value::Blob(vec![0xDE, 0xAD]).exec_unistr_quote(),
2165            Value::build_text("X'DEAD'")
2166        );
2167        assert_eq!(
2168            Value::build_text("hello").exec_unistr_quote(),
2169            Value::build_text("'hello'")
2170        );
2171        // Backslash is NOT doubled when no control chars are present
2172        assert_eq!(
2173            Value::build_text("a\\b").exec_unistr_quote(),
2174            Value::build_text("'a\\b'")
2175        );
2176        assert_eq!(
2177            Value::build_text("it's").exec_unistr_quote(),
2178            Value::build_text("'it''s'")
2179        );
2180        assert_eq!(
2181            Value::build_text("a\tb").exec_unistr_quote(),
2182            Value::build_text("unistr('a\\u0009b')")
2183        );
2184        assert_eq!(
2185            Value::build_text("a\t\\b").exec_unistr_quote(),
2186            Value::build_text("unistr('a\\u0009\\\\b')")
2187        );
2188        assert_eq!(
2189            Value::build_text("a\tb'c").exec_unistr_quote(),
2190            Value::build_text("unistr('a\\u0009b''c')")
2191        );
2192        assert_eq!(
2193            Value::build_text("\x01abc'\\\t\n\r\x1fXYZ\0\x01tail").exec_unistr_quote(),
2194            Value::build_text(r"unistr('\u0001abc''\\\u0009\u000a\u000d\u001fXYZ')")
2195        );
2196        assert_eq!(
2197            Value::build_text("a\x01b\0c").exec_unistr_quote(),
2198            Value::build_text("unistr('a\\u0001b')")
2199        );
2200        assert_eq!(
2201            Value::build_text("\x01").exec_unistr_quote(),
2202            Value::build_text("unistr('\\u0001')")
2203        );
2204        assert_eq!(
2205            Value::build_text("\x01\x1f").exec_unistr_quote(),
2206            Value::build_text("unistr('\\u0001\\u001f')")
2207        );
2208        assert_eq!(
2209            Value::build_text("\x10").exec_unistr_quote(),
2210            Value::build_text("unistr('\\u0010')")
2211        );
2212        assert_eq!(
2213            Value::build_text("\x1f").exec_unistr_quote(),
2214            Value::build_text("unistr('\\u001f')")
2215        );
2216        // 0x20 is the first char outside the control range
2217        assert_eq!(
2218            Value::build_text(" ").exec_unistr_quote(),
2219            Value::build_text("' '")
2220        );
2221        assert_eq!(
2222            Value::build_text("\0abc").exec_unistr_quote(),
2223            Value::build_text("''")
2224        );
2225        assert_eq!(
2226            Value::build_text("").exec_unistr_quote(),
2227            Value::build_text("''")
2228        );
2229        assert_eq!(
2230            Value::build_text("a\nb").exec_unistr_quote(),
2231            Value::build_text("unistr('a\\u000ab')")
2232        );
2233        assert_eq!(
2234            Value::build_text("a\rb").exec_unistr_quote(),
2235            Value::build_text("unistr('a\\u000db')")
2236        );
2237        assert_eq!(
2238            Value::build_text("a\0\t").exec_unistr_quote(),
2239            Value::build_text("'a'")
2240        );
2241    }
2242
2243    #[test]
2244    fn test_min_max() {
2245        let input_int_vec = [
2246            Register::Value(Value::from_i64(-1)),
2247            Register::Value(Value::from_i64(10)),
2248        ];
2249        assert_eq!(
2250            Value::exec_min(input_int_vec.iter().map(|v| v.get_value())),
2251            Value::from_i64(-1)
2252        );
2253        assert_eq!(
2254            Value::exec_max(input_int_vec.iter().map(|v| v.get_value())),
2255            Value::from_i64(10)
2256        );
2257
2258        let str1 = Register::Value(Value::build_text("A"));
2259        let str2 = Register::Value(Value::build_text("z"));
2260        let input_str_vec = [str2, str1.clone()];
2261        assert_eq!(
2262            Value::exec_min(input_str_vec.iter().map(|v| v.get_value())),
2263            Value::build_text("A")
2264        );
2265        assert_eq!(
2266            Value::exec_max(input_str_vec.iter().map(|v| v.get_value())),
2267            Value::build_text("z")
2268        );
2269
2270        let input_null_vec = [Register::Value(Value::Null), Register::Value(Value::Null)];
2271        assert_eq!(
2272            Value::exec_min(input_null_vec.iter().map(|v| v.get_value())),
2273            Value::Null
2274        );
2275        assert_eq!(
2276            Value::exec_max(input_null_vec.iter().map(|v| v.get_value())),
2277            Value::Null
2278        );
2279
2280        let input_mixed_vec = [Register::Value(Value::from_i64(10)), str1];
2281        assert_eq!(
2282            Value::exec_min(input_mixed_vec.iter().map(|v| v.get_value())),
2283            Value::from_i64(10)
2284        );
2285        assert_eq!(
2286            Value::exec_max(input_mixed_vec.iter().map(|v| v.get_value())),
2287            Value::build_text("A")
2288        );
2289
2290        // SQLite: multi-arg min/max returns NULL if ANY argument is NULL
2291        let input_with_null = [
2292            Register::Value(Value::from_i64(1)),
2293            Register::Value(Value::Null),
2294        ];
2295        assert_eq!(
2296            Value::exec_min(input_with_null.iter().map(|v| v.get_value())),
2297            Value::Null
2298        );
2299        assert_eq!(
2300            Value::exec_max(input_with_null.iter().map(|v| v.get_value())),
2301            Value::Null
2302        );
2303    }
2304
2305    #[test]
2306    fn test_trim() {
2307        let input_str = Value::build_text("     Bob and Alice     ");
2308        let expected_str = Value::build_text("Bob and Alice");
2309        assert_eq!(input_str.exec_trim(None), expected_str);
2310
2311        let input_str = Value::build_text("     Bob and Alice     ");
2312        let pattern_str = Value::build_text("Bob and");
2313        let expected_str = Value::build_text("Alice");
2314        assert_eq!(input_str.exec_trim(Some(&pattern_str)), expected_str);
2315
2316        let input_str = Value::build_text("\ta");
2317        let expected_str = Value::build_text("\ta");
2318        assert_eq!(input_str.exec_trim(None), expected_str);
2319
2320        let input_str = Value::build_text("\na");
2321        let expected_str = Value::build_text("\na");
2322        assert_eq!(input_str.exec_trim(None), expected_str);
2323
2324        // TRIM on Integer should return TEXT (SQLite compatibility)
2325        let input_int = Value::from_i64(12345);
2326        let expected_text = Value::build_text("12345");
2327        assert_eq!(input_int.exec_trim(None), expected_text);
2328
2329        // TRIM on Float should return TEXT (SQLite compatibility)
2330        let input_float = Value::from_f64(123.5);
2331        let expected_text = Value::build_text("123.5");
2332        assert_eq!(input_float.exec_trim(None), expected_text);
2333    }
2334
2335    #[test]
2336    fn test_ltrim() {
2337        let input_str = Value::build_text("     Bob and Alice     ");
2338        let expected_str = Value::build_text("Bob and Alice     ");
2339        assert_eq!(input_str.exec_ltrim(None), expected_str);
2340
2341        let input_str = Value::build_text("     Bob and Alice     ");
2342        let pattern_str = Value::build_text("Bob and");
2343        let expected_str = Value::build_text("Alice     ");
2344        assert_eq!(input_str.exec_ltrim(Some(&pattern_str)), expected_str);
2345    }
2346
2347    #[test]
2348    fn test_rtrim() {
2349        let input_str = Value::build_text("     Bob and Alice     ");
2350        let expected_str = Value::build_text("     Bob and Alice");
2351        assert_eq!(input_str.exec_rtrim(None), expected_str);
2352
2353        let input_str = Value::build_text("     Bob and Alice     ");
2354        let pattern_str = Value::build_text("Bob and");
2355        let expected_str = Value::build_text("     Bob and Alice");
2356        assert_eq!(input_str.exec_rtrim(Some(&pattern_str)), expected_str);
2357
2358        let input_str = Value::build_text("     Bob and Alice     ");
2359        let pattern_str = Value::build_text("and Alice");
2360        let expected_str = Value::build_text("     Bob");
2361        assert_eq!(input_str.exec_rtrim(Some(&pattern_str)), expected_str);
2362    }
2363
2364    #[test]
2365    fn test_soundex() {
2366        let input_str = Value::build_text("Pfister");
2367        let expected_str = Value::build_text("P236");
2368        assert_eq!(input_str.exec_soundex(), expected_str);
2369
2370        let input_str = Value::build_text("husobee");
2371        let expected_str = Value::build_text("H210");
2372        assert_eq!(input_str.exec_soundex(), expected_str);
2373
2374        let input_str = Value::build_text("Tymczak");
2375        let expected_str = Value::build_text("T522");
2376        assert_eq!(input_str.exec_soundex(), expected_str);
2377
2378        let input_str = Value::build_text("Ashcraft");
2379        let expected_str = Value::build_text("A261");
2380        assert_eq!(input_str.exec_soundex(), expected_str);
2381
2382        let input_str = Value::build_text("Robert");
2383        let expected_str = Value::build_text("R163");
2384        assert_eq!(input_str.exec_soundex(), expected_str);
2385
2386        let input_str = Value::build_text("Rupert");
2387        let expected_str = Value::build_text("R163");
2388        assert_eq!(input_str.exec_soundex(), expected_str);
2389
2390        let input_str = Value::build_text("Rubin");
2391        let expected_str = Value::build_text("R150");
2392        assert_eq!(input_str.exec_soundex(), expected_str);
2393
2394        let input_str = Value::build_text("Kant");
2395        let expected_str = Value::build_text("K530");
2396        assert_eq!(input_str.exec_soundex(), expected_str);
2397
2398        let input_str = Value::build_text("Knuth");
2399        let expected_str = Value::build_text("K530");
2400        assert_eq!(input_str.exec_soundex(), expected_str);
2401
2402        let input_str = Value::build_text("x");
2403        let expected_str = Value::build_text("X000");
2404        assert_eq!(input_str.exec_soundex(), expected_str);
2405
2406        let input_str = Value::build_text("闪电五连鞭");
2407        let expected_str = Value::build_text("?000");
2408        assert_eq!(input_str.exec_soundex(), expected_str);
2409    }
2410
2411    #[test]
2412    fn test_upper_case() {
2413        let input_str = Value::build_text("Limbo");
2414        let expected_str = Value::build_text("LIMBO");
2415        assert_eq!(input_str.exec_upper().unwrap(), expected_str);
2416
2417        let input_int = Value::from_i64(10);
2418        assert_eq!(input_int.exec_upper().unwrap(), Value::build_text("10"));
2419        assert_eq!(Value::Null.exec_upper(), None)
2420    }
2421
2422    #[test]
2423    fn test_lower_case() {
2424        let input_str = Value::build_text("Limbo");
2425        let expected_str = Value::build_text("limbo");
2426        assert_eq!(input_str.exec_lower().unwrap(), expected_str);
2427
2428        let input_int = Value::from_i64(10);
2429        assert_eq!(input_int.exec_lower().unwrap(), Value::build_text("10"));
2430        assert_eq!(Value::Null.exec_lower(), None)
2431    }
2432
2433    #[test]
2434    fn test_hex() {
2435        let input_str = Value::build_text("limbo");
2436        let expected_val = Value::build_text("6C696D626F");
2437        assert_eq!(input_str.exec_hex(), expected_val);
2438
2439        let input_int = Value::from_i64(100);
2440        let expected_val = Value::build_text("313030");
2441        assert_eq!(input_int.exec_hex(), expected_val);
2442
2443        let input_float = Value::from_f64(12.34);
2444        let expected_val = Value::build_text("31322E3334");
2445        assert_eq!(input_float.exec_hex(), expected_val);
2446
2447        let input_blob = Value::Blob(vec![0xff]);
2448        let expected_val = Value::build_text("FF");
2449        assert_eq!(input_blob.exec_hex(), expected_val);
2450    }
2451
2452    #[test]
2453    fn test_cast_blob_preserves_blob_bytes() {
2454        let input_blob = Value::Blob(vec![0xd2, 0x64, 0xc0, 0x07, 0xf6, 0x44, 0xe4, 0x59]);
2455        let expected = input_blob.clone();
2456
2457        assert_eq!(input_blob.exec_cast("BLOB"), expected);
2458    }
2459
2460    #[test]
2461    fn test_unhex() {
2462        let input = Value::build_text("6f");
2463        let expected = Value::Blob(vec![0x6f]);
2464        assert_eq!(input.exec_unhex(None), expected);
2465
2466        let input = Value::build_text("6f");
2467        let expected = Value::Blob(vec![0x6f]);
2468        assert_eq!(input.exec_unhex(None), expected);
2469
2470        let input = Value::build_text("611");
2471        let expected = Value::Null;
2472        assert_eq!(input.exec_unhex(None), expected);
2473
2474        let input = Value::build_text("");
2475        let expected = Value::Blob(vec![]);
2476        assert_eq!(input.exec_unhex(None), expected);
2477
2478        let input = Value::build_text("61x");
2479        let expected = Value::Null;
2480        assert_eq!(input.exec_unhex(None), expected);
2481
2482        let input = Value::Null;
2483        let expected = Value::Null;
2484        assert_eq!(input.exec_unhex(None), expected);
2485
2486        let input = Value::build_text("aa-bb");
2487        let expected = Value::Blob(vec![0xaa, 0xbb]);
2488        assert_eq!(input.exec_unhex(Some(&Value::build_text("-"))), expected);
2489
2490        let input = Value::build_text("aa--bb");
2491        let expected = Value::Blob(vec![0xaa, 0xbb]);
2492        assert_eq!(input.exec_unhex(Some(&Value::build_text("-"))), expected);
2493
2494        let input = Value::build_text("aa-bb-cc");
2495        let expected = Value::Blob(vec![0xaa, 0xbb, 0xcc]);
2496        assert_eq!(input.exec_unhex(Some(&Value::build_text("-"))), expected);
2497
2498        let input = Value::build_text("aa bb");
2499        let expected = Value::Blob(vec![0xaa, 0xbb]);
2500        assert_eq!(input.exec_unhex(Some(&Value::build_text(" "))), expected);
2501
2502        let input = Value::build_text("A BCD");
2503        let expected = Value::Null;
2504        assert_eq!(input.exec_unhex(Some(&Value::build_text(" "))), expected);
2505
2506        let input = Value::build_text("yx2xEzyx");
2507        let expected = Value::Null;
2508        assert_eq!(input.exec_unhex(Some(&Value::build_text("xyz"))), expected);
2509
2510        let input = Value::build_text("aa?bb");
2511        let expected = Value::Null;
2512        assert_eq!(input.exec_unhex(Some(&Value::build_text("-"))), expected);
2513
2514        let input = Value::build_text("aabb");
2515        let expected = Value::Null;
2516        assert_eq!(input.exec_unhex(Some(&Value::Null)), expected);
2517    }
2518
2519    #[test]
2520    fn test_abs() {
2521        let int_positive_reg = Value::from_i64(10);
2522        let int_negative_reg = Value::from_i64(-10);
2523        assert_eq!(int_positive_reg.exec_abs().unwrap(), int_positive_reg);
2524        assert_eq!(int_negative_reg.exec_abs().unwrap(), int_positive_reg);
2525
2526        let float_positive_reg = Value::from_i64(10);
2527        let float_negative_reg = Value::from_i64(-10);
2528        assert_eq!(float_positive_reg.exec_abs().unwrap(), float_positive_reg);
2529        assert_eq!(float_negative_reg.exec_abs().unwrap(), float_positive_reg);
2530
2531        assert_eq!(
2532            Value::build_text("a").exec_abs().unwrap(),
2533            Value::from_f64(0.0)
2534        );
2535        assert_eq!(Value::Null.exec_abs().unwrap(), Value::Null);
2536
2537        // ABS(i64::MIN) should return RuntimeError
2538        assert!(Value::from_i64(i64::MIN).exec_abs().is_err());
2539    }
2540
2541    #[test]
2542    fn test_char() {
2543        assert_eq!(
2544            Value::exec_char(
2545                [
2546                    Register::Value(Value::from_i64(108)),
2547                    Register::Value(Value::from_i64(105))
2548                ]
2549                .iter()
2550                .map(|reg| reg.get_value())
2551            ),
2552            Value::build_text("li")
2553        );
2554        assert_eq!(Value::exec_char(std::iter::empty()), Value::build_text(""));
2555        assert_eq!(
2556            Value::exec_char(
2557                [Register::Value(Value::Null)]
2558                    .iter()
2559                    .map(|reg| reg.get_value())
2560            ),
2561            Value::build_text("\0")
2562        );
2563        assert_eq!(
2564            Value::exec_char(
2565                [Register::Value(Value::build_text("a"))]
2566                    .iter()
2567                    .map(|reg| reg.get_value())
2568            ),
2569            Value::build_text("")
2570        );
2571    }
2572
2573    #[test]
2574    fn test_like_with_escape_or_regexmeta_chars() {
2575        assert!(Value::exec_like(r#"\%A"#, r#"\A"#, None).unwrap());
2576        assert!(Value::exec_like("%a%a", "aaaa", None).unwrap());
2577    }
2578
2579    #[test]
2580    fn test_like_without_escape() {
2581        assert!(Value::exec_like("a%", "aaaa", None).unwrap());
2582        assert!(Value::exec_like("%a%a", "aaaa", None).unwrap());
2583        assert!(!Value::exec_like("%a.a", "aaaa", None).unwrap());
2584        assert!(!Value::exec_like("a.a%", "aaaa", None).unwrap());
2585        assert!(!Value::exec_like("%a.ab", "aaaa", None).unwrap());
2586    }
2587
2588    #[test]
2589    fn test_exec_like_with_escape() {
2590        assert!(Value::exec_like("abcX%", "abc%", Some('X')).unwrap());
2591        assert!(!Value::exec_like("abcX%", "abc5", Some('X')).unwrap());
2592        assert!(!Value::exec_like("abcX%", "abc", Some('X')).unwrap());
2593        assert!(!Value::exec_like("abcX%", "abcX%", Some('X')).unwrap());
2594        assert!(!Value::exec_like("abcX%", "abc%%", Some('X')).unwrap());
2595
2596        assert!(Value::exec_like("abcX_", "abc_", Some('X')).unwrap());
2597        assert!(!Value::exec_like("abcX_", "abc5", Some('X')).unwrap());
2598        assert!(!Value::exec_like("abcX_", "abc", Some('X')).unwrap());
2599        assert!(!Value::exec_like("abcX_", "abcX_", Some('X')).unwrap());
2600        assert!(!Value::exec_like("abcX_", "abc__", Some('X')).unwrap());
2601
2602        assert!(Value::exec_like("abcXX", "abcX", Some('X')).unwrap());
2603        assert!(!Value::exec_like("abcXX", "abc5", Some('X')).unwrap());
2604        assert!(!Value::exec_like("abcXX", "abc", Some('X')).unwrap());
2605        assert!(!Value::exec_like("abcXX", "abcXX", Some('X')).unwrap());
2606    }
2607
2608    #[test]
2609    fn test_glob() {
2610        assert!(Value::exec_glob(r#"?*/abc/?*"#, r#"x//a/ab/abc/y"#).unwrap());
2611        assert!(Value::exec_glob(r#"a[1^]"#, r#"a1"#).unwrap());
2612        assert!(Value::exec_glob(r#"a[1^]*"#, r#"a^"#).unwrap());
2613        assert!(!Value::exec_glob(r#"a[a*"#, r#"a["#).unwrap());
2614        assert!(!Value::exec_glob(r#"a[a"#, r#"a[a"#).unwrap());
2615        assert!(Value::exec_glob(r#"a[[]"#, r#"a["#).unwrap());
2616        assert!(Value::exec_glob(r#"abc[^][*?]efg"#, r#"abcdefg"#).unwrap());
2617        assert!(!Value::exec_glob(r#"abc[^][*?]efg"#, r#"abc]efg"#).unwrap());
2618    }
2619
2620    #[test]
2621    fn test_random() {
2622        match Value::exec_random(|| rand::rng().random()) {
2623            Value::Numeric(Numeric::Integer(value)) => {
2624                // Check that the value is within the range of i64
2625                assert!(
2626                    (i64::MIN..=i64::MAX).contains(&value),
2627                    "Random number out of range"
2628                );
2629            }
2630            _ => panic!("exec_random did not return an Integer variant"),
2631        }
2632    }
2633
2634    #[test]
2635    fn test_exec_randomblob() {
2636        struct TestCase {
2637            input: Value,
2638            expected_len: usize,
2639        }
2640
2641        let test_cases = vec![
2642            TestCase {
2643                input: Value::from_i64(5),
2644                expected_len: 5,
2645            },
2646            TestCase {
2647                input: Value::from_i64(0),
2648                expected_len: 1,
2649            },
2650            TestCase {
2651                input: Value::from_i64(-1),
2652                expected_len: 1,
2653            },
2654            TestCase {
2655                input: Value::build_text(""),
2656                expected_len: 1,
2657            },
2658            TestCase {
2659                input: Value::build_text("5"),
2660                expected_len: 5,
2661            },
2662            TestCase {
2663                input: Value::build_text("0"),
2664                expected_len: 1,
2665            },
2666            TestCase {
2667                input: Value::build_text("-1"),
2668                expected_len: 1,
2669            },
2670            TestCase {
2671                input: Value::from_f64(2.9),
2672                expected_len: 2,
2673            },
2674            TestCase {
2675                input: Value::from_f64(-3.15),
2676                expected_len: 1,
2677            },
2678            TestCase {
2679                input: Value::Null,
2680                expected_len: 1,
2681            },
2682        ];
2683
2684        for test_case in &test_cases {
2685            let result = test_case
2686                .input
2687                .exec_randomblob(|dest| {
2688                    rand::rng().fill_bytes(dest);
2689                })
2690                .unwrap();
2691            match result {
2692                Value::Blob(blob) => {
2693                    assert_eq!(blob.len(), test_case.expected_len);
2694                }
2695                _ => panic!("exec_randomblob did not return a Blob variant"),
2696            }
2697        }
2698
2699        // Test TooBig error
2700        let input = Value::from_i64(Value::MAX_BLOB_LENGTH + 1);
2701        assert!(input.exec_randomblob(|_| {}).is_err());
2702    }
2703
2704    #[test]
2705    fn test_exec_round() {
2706        let input_val = Value::from_f64(123.456);
2707        let expected_val = Value::from_f64(123.0);
2708        assert_eq!(input_val.exec_round(None), expected_val);
2709
2710        let input_val = Value::from_f64(123.456);
2711        let precision_val = Value::from_i64(2);
2712        let expected_val = Value::from_f64(123.46);
2713        assert_eq!(input_val.exec_round(Some(&precision_val)), expected_val);
2714
2715        let input_val = Value::from_f64(123.456);
2716        let precision_val = Value::build_text("1");
2717        let expected_val = Value::from_f64(123.5);
2718        assert_eq!(input_val.exec_round(Some(&precision_val)), expected_val);
2719
2720        let input_val = Value::build_text("123.456");
2721        let precision_val = Value::from_i64(2);
2722        let expected_val = Value::from_f64(123.46);
2723        assert_eq!(input_val.exec_round(Some(&precision_val)), expected_val);
2724
2725        let input_val = Value::from_i64(123);
2726        let precision_val = Value::from_i64(1);
2727        let expected_val = Value::from_f64(123.0);
2728        assert_eq!(input_val.exec_round(Some(&precision_val)), expected_val);
2729
2730        let input_val = Value::from_f64(100.123);
2731        let expected_val = Value::from_f64(100.0);
2732        assert_eq!(input_val.exec_round(None), expected_val);
2733
2734        let input_val = Value::from_f64(100.123);
2735        let expected_val = Value::Null;
2736        assert_eq!(input_val.exec_round(Some(&Value::Null)), expected_val);
2737    }
2738
2739    #[test]
2740    fn test_exec_if() {
2741        let reg = Value::from_i64(0);
2742        assert!(!reg.exec_if(false, false));
2743        assert!(reg.exec_if(false, true));
2744
2745        let reg = Value::from_i64(1);
2746        assert!(reg.exec_if(false, false));
2747        assert!(!reg.exec_if(false, true));
2748
2749        let reg = Value::Null;
2750        assert!(!reg.exec_if(false, false));
2751        assert!(!reg.exec_if(false, true));
2752
2753        let reg = Value::Null;
2754        assert!(reg.exec_if(true, false));
2755        assert!(reg.exec_if(true, true));
2756
2757        let reg = Value::Null;
2758        assert!(!reg.exec_if(false, false));
2759        assert!(!reg.exec_if(false, true));
2760    }
2761
2762    #[test]
2763    fn test_nullif() {
2764        assert_eq!(
2765            Value::from_i64(1).exec_nullif(&Value::from_i64(1)),
2766            Value::Null
2767        );
2768        assert_eq!(
2769            Value::from_f64(1.1).exec_nullif(&Value::from_f64(1.1)),
2770            Value::Null
2771        );
2772        assert_eq!(
2773            Value::build_text("limbo").exec_nullif(&Value::build_text("limbo")),
2774            Value::Null
2775        );
2776
2777        assert_eq!(
2778            Value::from_i64(1).exec_nullif(&Value::from_i64(2)),
2779            Value::from_i64(1)
2780        );
2781        assert_eq!(
2782            Value::from_f64(1.1).exec_nullif(&Value::from_f64(1.2)),
2783            Value::from_f64(1.1)
2784        );
2785        assert_eq!(
2786            Value::build_text("limbo").exec_nullif(&Value::build_text("limb")),
2787            Value::build_text("limbo")
2788        );
2789    }
2790
2791    #[test]
2792    fn test_substring() {
2793        let str_value = Value::build_text("limbo");
2794        let start_value = Value::from_i64(1);
2795        let length_value = Value::from_i64(3);
2796        let expected_val = Value::build_text("lim");
2797        assert_eq!(
2798            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2799            expected_val
2800        );
2801
2802        let str_value = Value::build_text("limbo");
2803        let start_value = Value::from_i64(1);
2804        let length_value = Value::from_i64(10);
2805        let expected_val = Value::build_text("limbo");
2806        assert_eq!(
2807            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2808            expected_val
2809        );
2810
2811        let str_value = Value::build_text("limbo");
2812        let start_value = Value::from_i64(10);
2813        let length_value = Value::from_i64(3);
2814        let expected_val = Value::build_text("");
2815        assert_eq!(
2816            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2817            expected_val
2818        );
2819
2820        let str_value = Value::build_text("limbo");
2821        let start_value = Value::from_i64(3);
2822        let length_value = Value::Null;
2823        let expected_val = Value::Null;
2824        assert_eq!(
2825            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2826            expected_val
2827        );
2828
2829        let str_value = Value::build_text("limbo");
2830        let start_value = Value::from_i64(10);
2831        let length_value = Value::Null;
2832        let expected_val = Value::Null;
2833        assert_eq!(
2834            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2835            expected_val
2836        );
2837
2838        let str_value = Value::build_text("limbo");
2839        let start_value = Value::from_i64(-7_096_519_388_852_014_892);
2840        let length_value = Value::from_i64(-4_829_175_794_346_763_833);
2841        let expected_val = Value::build_text("");
2842        assert_eq!(
2843            Value::exec_substring(&str_value, &start_value, Some(&length_value)),
2844            expected_val
2845        );
2846    }
2847
2848    #[test]
2849    fn test_exec_instr() {
2850        let input = Value::build_text("limbo");
2851        let pattern = Value::build_text("im");
2852        let expected = Value::from_i64(2);
2853        assert_eq!(input.exec_instr(&pattern), expected);
2854
2855        let input = Value::build_text("limbo");
2856        let pattern = Value::build_text("limbo");
2857        let expected = Value::from_i64(1);
2858        assert_eq!(input.exec_instr(&pattern), expected);
2859
2860        let input = Value::build_text("limbo");
2861        let pattern = Value::build_text("o");
2862        let expected = Value::from_i64(5);
2863        assert_eq!(input.exec_instr(&pattern), expected);
2864
2865        let input = Value::build_text("liiiiimbo");
2866        let pattern = Value::build_text("ii");
2867        let expected = Value::from_i64(2);
2868        assert_eq!(input.exec_instr(&pattern), expected);
2869
2870        let input = Value::build_text("limbo");
2871        let pattern = Value::build_text("limboX");
2872        let expected = Value::from_i64(0);
2873        assert_eq!(input.exec_instr(&pattern), expected);
2874
2875        let input = Value::build_text("limbo");
2876        let pattern = Value::build_text("");
2877        let expected = Value::from_i64(1);
2878        assert_eq!(input.exec_instr(&pattern), expected);
2879
2880        let input = Value::build_text("");
2881        let pattern = Value::build_text("limbo");
2882        let expected = Value::from_i64(0);
2883        assert_eq!(input.exec_instr(&pattern), expected);
2884
2885        let input = Value::build_text("");
2886        let pattern = Value::build_text("");
2887        let expected = Value::from_i64(1);
2888        assert_eq!(input.exec_instr(&pattern), expected);
2889
2890        let input = Value::Null;
2891        let pattern = Value::Null;
2892        let expected = Value::Null;
2893        assert_eq!(input.exec_instr(&pattern), expected);
2894
2895        let input = Value::build_text("limbo");
2896        let pattern = Value::Null;
2897        let expected = Value::Null;
2898        assert_eq!(input.exec_instr(&pattern), expected);
2899
2900        let input = Value::Null;
2901        let pattern = Value::build_text("limbo");
2902        let expected = Value::Null;
2903        assert_eq!(input.exec_instr(&pattern), expected);
2904
2905        let input = Value::from_i64(123);
2906        let pattern = Value::from_i64(2);
2907        let expected = Value::from_i64(2);
2908        assert_eq!(input.exec_instr(&pattern), expected);
2909
2910        let input = Value::from_i64(123);
2911        let pattern = Value::from_i64(5);
2912        let expected = Value::from_i64(0);
2913        assert_eq!(input.exec_instr(&pattern), expected);
2914
2915        let input = Value::from_f64(12.34);
2916        let pattern = Value::from_f64(2.3);
2917        let expected = Value::from_i64(2);
2918        assert_eq!(input.exec_instr(&pattern), expected);
2919
2920        let input = Value::from_f64(12.34);
2921        let pattern = Value::from_f64(5.6);
2922        let expected = Value::from_i64(0);
2923        assert_eq!(input.exec_instr(&pattern), expected);
2924
2925        let input = Value::from_f64(12.34);
2926        let pattern = Value::build_text(".");
2927        let expected = Value::from_i64(3);
2928        assert_eq!(input.exec_instr(&pattern), expected);
2929
2930        let input = Value::Blob(vec![1, 2, 3, 4, 5]);
2931        let pattern = Value::Blob(vec![3, 4]);
2932        let expected = Value::from_i64(3);
2933        assert_eq!(input.exec_instr(&pattern), expected);
2934
2935        let input = Value::Blob(vec![1, 2, 3, 4, 5]);
2936        let pattern = Value::Blob(vec![3, 2]);
2937        let expected = Value::from_i64(0);
2938        assert_eq!(input.exec_instr(&pattern), expected);
2939
2940        let input = Value::Blob(vec![0x61, 0x62, 0x63, 0x64, 0x65]);
2941        let pattern = Value::build_text("cd");
2942        let expected = Value::from_i64(3);
2943        assert_eq!(input.exec_instr(&pattern), expected);
2944
2945        let input = Value::build_text("abcde");
2946        let pattern = Value::Blob(vec![0x63, 0x64]);
2947        let expected = Value::from_i64(3);
2948        assert_eq!(input.exec_instr(&pattern), expected);
2949
2950        let input = Value::build_text("abcde");
2951        let pattern = Value::build_text("");
2952        let expected = Value::from_i64(1);
2953        assert_eq!(input.exec_instr(&pattern), expected);
2954    }
2955
2956    #[test]
2957    fn test_exec_sign() {
2958        let input = Value::from_i64(42);
2959        let expected = Some(Value::from_i64(1));
2960        assert_eq!(input.exec_sign(), expected);
2961
2962        let input = Value::from_i64(-42);
2963        let expected = Some(Value::from_i64(-1));
2964        assert_eq!(input.exec_sign(), expected);
2965
2966        let input = Value::from_i64(0);
2967        let expected = Some(Value::from_i64(0));
2968        assert_eq!(input.exec_sign(), expected);
2969
2970        let input = Value::from_f64(0.0);
2971        let expected = Some(Value::from_i64(0));
2972        assert_eq!(input.exec_sign(), expected);
2973
2974        let input = Value::from_f64(0.1);
2975        let expected = Some(Value::from_i64(1));
2976        assert_eq!(input.exec_sign(), expected);
2977
2978        let input = Value::from_f64(42.0);
2979        let expected = Some(Value::from_i64(1));
2980        assert_eq!(input.exec_sign(), expected);
2981
2982        let input = Value::from_f64(-42.0);
2983        let expected = Some(Value::from_i64(-1));
2984        assert_eq!(input.exec_sign(), expected);
2985
2986        let input = Value::build_text("abc");
2987        let expected = None;
2988        assert_eq!(input.exec_sign(), expected);
2989
2990        let input = Value::build_text("42");
2991        let expected = Some(Value::from_i64(1));
2992        assert_eq!(input.exec_sign(), expected);
2993
2994        let input = Value::build_text("-42");
2995        let expected = Some(Value::from_i64(-1));
2996        assert_eq!(input.exec_sign(), expected);
2997
2998        let input = Value::build_text("0");
2999        let expected = Some(Value::from_i64(0));
3000        assert_eq!(input.exec_sign(), expected);
3001
3002        let input = Value::Blob(b"abc".to_vec());
3003        let expected = None;
3004        assert_eq!(input.exec_sign(), expected);
3005
3006        let input = Value::Blob(b"42".to_vec());
3007        let expected = None;
3008        assert_eq!(input.exec_sign(), expected);
3009
3010        let input = Value::Blob(b"-42".to_vec());
3011        let expected = None;
3012        assert_eq!(input.exec_sign(), expected);
3013
3014        let input = Value::Blob(b"0".to_vec());
3015        let expected = None;
3016        assert_eq!(input.exec_sign(), expected);
3017
3018        let input = Value::Null;
3019        let expected = None;
3020        assert_eq!(input.exec_sign(), expected);
3021    }
3022
3023    #[test]
3024    fn test_exec_zeroblob() {
3025        let input = Value::from_i64(0);
3026        let expected = Value::Blob(vec![]);
3027        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3028
3029        let input = Value::Null;
3030        let expected = Value::Blob(vec![]);
3031        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3032
3033        let input = Value::from_i64(4);
3034        let expected = Value::Blob(vec![0; 4]);
3035        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3036
3037        let input = Value::from_i64(-1);
3038        let expected = Value::Blob(vec![]);
3039        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3040
3041        let input = Value::build_text("5");
3042        let expected = Value::Blob(vec![0; 5]);
3043        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3044
3045        let input = Value::build_text("-5");
3046        let expected = Value::Blob(vec![]);
3047        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3048
3049        let input = Value::build_text("text");
3050        let expected = Value::Blob(vec![]);
3051        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3052
3053        let input = Value::from_f64(2.6);
3054        let expected = Value::Blob(vec![0; 2]);
3055        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3056
3057        let input = Value::Blob(vec![1]);
3058        let expected = Value::Blob(vec![]);
3059        assert_eq!(input.exec_zeroblob().unwrap(), expected);
3060
3061        // Test TooBig error
3062        let input = Value::from_i64(Value::MAX_BLOB_LENGTH + 1);
3063        assert!(input.exec_zeroblob().is_err());
3064    }
3065
3066    #[test]
3067    fn test_replace() {
3068        let input_str = Value::build_text("bob");
3069        let pattern_str = Value::build_text("b");
3070        let replace_str = Value::build_text("a");
3071        let expected_str = Value::build_text("aoa");
3072        assert_eq!(
3073            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3074            expected_str
3075        );
3076
3077        let input_str = Value::build_text("bob");
3078        let pattern_str = Value::build_text("b");
3079        let replace_str = Value::build_text("");
3080        let expected_str = Value::build_text("o");
3081        assert_eq!(
3082            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3083            expected_str
3084        );
3085
3086        let input_str = Value::build_text("bob");
3087        let pattern_str = Value::build_text("b");
3088        let replace_str = Value::build_text("abc");
3089        let expected_str = Value::build_text("abcoabc");
3090        assert_eq!(
3091            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3092            expected_str
3093        );
3094
3095        let input_str = Value::build_text("bob");
3096        let pattern_str = Value::build_text("a");
3097        let replace_str = Value::build_text("b");
3098        let expected_str = Value::build_text("bob");
3099        assert_eq!(
3100            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3101            expected_str
3102        );
3103
3104        let input_str = Value::build_text("bob");
3105        let pattern_str = Value::build_text("");
3106        let replace_str = Value::build_text("a");
3107        let expected_str = Value::build_text("bob");
3108        assert_eq!(
3109            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3110            expected_str
3111        );
3112
3113        let input_str = Value::build_text("bob");
3114        let pattern_str = Value::Null;
3115        let replace_str = Value::build_text("a");
3116        let expected_str = Value::Null;
3117        assert_eq!(
3118            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3119            expected_str
3120        );
3121
3122        let input_str = Value::build_text("bo5");
3123        let pattern_str = Value::from_i64(5);
3124        let replace_str = Value::build_text("a");
3125        let expected_str = Value::build_text("boa");
3126        assert_eq!(
3127            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3128            expected_str
3129        );
3130
3131        let input_str = Value::build_text("bo5.0");
3132        let pattern_str = Value::from_f64(5.0);
3133        let replace_str = Value::build_text("a");
3134        let expected_str = Value::build_text("boa");
3135        assert_eq!(
3136            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3137            expected_str
3138        );
3139
3140        let input_str = Value::build_text("bo5");
3141        let pattern_str = Value::from_f64(5.0);
3142        let replace_str = Value::build_text("a");
3143        let expected_str = Value::build_text("bo5");
3144        assert_eq!(
3145            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3146            expected_str
3147        );
3148
3149        let input_str = Value::build_text("bo5.0");
3150        let pattern_str = Value::from_f64(5.0);
3151        let replace_str = Value::from_f64(6.0);
3152        let expected_str = Value::build_text("bo6.0");
3153        assert_eq!(
3154            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3155            expected_str
3156        );
3157
3158        // todo: change this test to use (0.1 + 0.2) instead of 0.3 when decimals are implemented.
3159        let input_str = Value::build_text("tes3");
3160        let pattern_str = Value::from_i64(3);
3161        let replace_str = Value::from_f64(0.3);
3162        let expected_str = Value::build_text("tes0.3");
3163        assert_eq!(
3164            Value::exec_replace(&input_str, &pattern_str, &replace_str),
3165            expected_str
3166        );
3167    }
3168}