diff --git a/core/function.rs b/core/function.rs index c4885925f..86c88a1e4 100644 --- a/core/function.rs +++ b/core/function.rs @@ -5,6 +5,7 @@ use std::fmt::Display; #[derive(Debug, Clone, PartialEq)] pub enum JsonFunc { Json, + JsonArray, } #[cfg(feature = "json")] @@ -15,6 +16,7 @@ impl Display for JsonFunc { "{}", match self { JsonFunc::Json => "json".to_string(), + JsonFunc::JsonArray => "json_array".to_string(), } ) } @@ -328,6 +330,8 @@ impl Func { "replace" => Ok(Func::Scalar(ScalarFunc::Replace)), #[cfg(feature = "json")] "json" => Ok(Func::Json(JsonFunc::Json)), + #[cfg(feature = "json")] + "json_array" => Ok(Func::Json(JsonFunc::JsonArray)), "unixepoch" => Ok(Func::Scalar(ScalarFunc::UnixEpoch)), "hex" => Ok(Func::Scalar(ScalarFunc::Hex)), "unhex" => Ok(Func::Scalar(ScalarFunc::Unhex)), diff --git a/core/json/mod.rs b/core/json/mod.rs index 06169abd8..f0bffa8f1 100644 --- a/core/json/mod.rs +++ b/core/json/mod.rs @@ -6,7 +6,7 @@ use std::rc::Rc; pub use crate::json::de::from_str; pub use crate::json::ser::to_string; -use crate::types::OwnedValue; +use crate::types::{LimboText, OwnedValue, TextSubtype}; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; @@ -24,18 +24,24 @@ pub enum Val { pub fn get_json(json_value: &OwnedValue) -> crate::Result { match json_value { - OwnedValue::Text(ref t) => match crate::json::from_str::(t) { - Ok(json) => { - let json = crate::json::to_string(&json).unwrap(); - Ok(OwnedValue::Text(Rc::new(json))) + OwnedValue::Text(ref t) => { + if t.subtype == TextSubtype::Json { + return Ok(json_value.to_owned()); } - Err(_) => { - crate::bail_parse_error!("malformed JSON") + + match crate::json::from_str::(&t.value) { + Ok(json) => { + let json = crate::json::to_string(&json).unwrap(); + Ok(OwnedValue::Text(LimboText::json(Rc::new(json)))) + } + Err(_) => { + crate::bail_parse_error!("malformed JSON") + } } - }, + } OwnedValue::Blob(b) => { if let Ok(json) = jsonb::from_slice(b) { - Ok(OwnedValue::Text(Rc::new(json.to_string()))) + Ok(OwnedValue::Text(LimboText::json(Rc::new(json.to_string())))) } else { crate::bail_parse_error!("malformed JSON"); } @@ -44,6 +50,37 @@ pub fn get_json(json_value: &OwnedValue) -> crate::Result { } } +pub fn json_array(values: Vec) -> crate::Result { + let mut s = String::new(); + s.push('['); + + for (idx, value) in values.iter().enumerate() { + match value { + OwnedValue::Blob(_) => crate::bail_parse_error!("JSON cannot hold BLOB values"), + OwnedValue::Text(t) => { + if t.subtype == TextSubtype::Json { + s.push_str(&t.value); + } else { + match crate::json::to_string(&*t.value) { + Ok(json) => s.push_str(&json), + Err(_) => crate::bail_parse_error!("malformed JSON"), + } + } + } + OwnedValue::Integer(i) => s.push_str(&i.to_string()), + OwnedValue::Float(f) => s.push_str(&f.to_string()), + _ => unreachable!(), + } + + if idx < values.len() - 1 { + s.push(','); + } + } + + s.push(']'); + Ok(OwnedValue::build_text(Rc::new(s))) +} + #[cfg(test)] mod tests { use super::*; @@ -51,10 +88,10 @@ mod tests { #[test] fn test_get_json_valid_json5() { - let input = OwnedValue::Text(Rc::new("{ key: 'value' }".to_string())); + let input = OwnedValue::build_text(Rc::new("{ key: 'value' }".to_string())); let result = get_json(&input).unwrap(); if let OwnedValue::Text(result_str) = result { - assert!(result_str.contains("\"key\":\"value\"")); + assert!(result_str.value.contains("\"key\":\"value\"")); } else { panic!("Expected OwnedValue::Text"); } @@ -62,10 +99,10 @@ mod tests { #[test] fn test_get_json_valid_json5_double_single_quotes() { - let input = OwnedValue::Text(Rc::new("{ key: ''value'' }".to_string())); + let input = OwnedValue::build_text(Rc::new("{ key: ''value'' }".to_string())); let result = get_json(&input).unwrap(); if let OwnedValue::Text(result_str) = result { - assert!(result_str.contains("\"key\":\"value\"")); + assert!(result_str.value.contains("\"key\":\"value\"")); } else { panic!("Expected OwnedValue::Text"); } @@ -73,10 +110,10 @@ mod tests { #[test] fn test_get_json_valid_json5_infinity() { - let input = OwnedValue::Text(Rc::new("{ \"key\": Infinity }".to_string())); + let input = OwnedValue::build_text(Rc::new("{ \"key\": Infinity }".to_string())); let result = get_json(&input).unwrap(); if let OwnedValue::Text(result_str) = result { - assert!(result_str.contains("{\"key\":9e999}")); + assert!(result_str.value.contains("{\"key\":9e999}")); } else { panic!("Expected OwnedValue::Text"); } @@ -84,10 +121,10 @@ mod tests { #[test] fn test_get_json_valid_json5_negative_infinity() { - let input = OwnedValue::Text(Rc::new("{ \"key\": -Infinity }".to_string())); + let input = OwnedValue::build_text(Rc::new("{ \"key\": -Infinity }".to_string())); let result = get_json(&input).unwrap(); if let OwnedValue::Text(result_str) = result { - assert!(result_str.contains("{\"key\":-9e999}")); + assert!(result_str.value.contains("{\"key\":-9e999}")); } else { panic!("Expected OwnedValue::Text"); } @@ -95,10 +132,10 @@ mod tests { #[test] fn test_get_json_valid_json5_nan() { - let input = OwnedValue::Text(Rc::new("{ \"key\": NaN }".to_string())); + let input = OwnedValue::build_text(Rc::new("{ \"key\": NaN }".to_string())); let result = get_json(&input).unwrap(); if let OwnedValue::Text(result_str) = result { - assert!(result_str.contains("{\"key\":null}")); + assert!(result_str.value.contains("{\"key\":null}")); } else { panic!("Expected OwnedValue::Text"); } @@ -106,7 +143,7 @@ mod tests { #[test] fn test_get_json_invalid_json5() { - let input = OwnedValue::Text(Rc::new("{ key: value }".to_string())); + let input = OwnedValue::build_text(Rc::new("{ key: value }".to_string())); let result = get_json(&input); match result { Ok(_) => panic!("Expected error for malformed JSON"), @@ -116,10 +153,10 @@ mod tests { #[test] fn test_get_json_valid_jsonb() { - let input = OwnedValue::Text(Rc::new("{\"key\":\"value\"}".to_string())); + let input = OwnedValue::build_text(Rc::new("{\"key\":\"value\"}".to_string())); let result = get_json(&input).unwrap(); if let OwnedValue::Text(result_str) = result { - assert!(result_str.contains("\"key\":\"value\"")); + assert!(result_str.value.contains("\"key\":\"value\"")); } else { panic!("Expected OwnedValue::Text"); } @@ -127,7 +164,7 @@ mod tests { #[test] fn test_get_json_invalid_jsonb() { - let input = OwnedValue::Text(Rc::new("{key:\"value\"".to_string())); + let input = OwnedValue::build_text(Rc::new("{key:\"value\"".to_string())); let result = get_json(&input); match result { Ok(_) => panic!("Expected error for malformed JSON"), @@ -141,7 +178,7 @@ mod tests { let input = OwnedValue::Blob(Rc::new(binary_json)); let result = get_json(&input).unwrap(); if let OwnedValue::Text(result_str) = result { - assert!(result_str.contains("\"asd\":\"adf\"")); + assert!(result_str.value.contains("\"asd\":\"adf\"")); } else { panic!("Expected OwnedValue::Text"); } @@ -168,4 +205,44 @@ mod tests { panic!("Expected OwnedValue::Null"); } } + + #[test] + fn test_json_array_simple() { + let text = OwnedValue::build_text(Rc::new("value1".to_string())); + let json = OwnedValue::Text(LimboText::json(Rc::new("\"value2\"".to_string()))); + let input = vec![text, json, OwnedValue::Integer(1), OwnedValue::Float(1.1)]; + + let result = json_array(input).unwrap(); + if let OwnedValue::Text(res) = result { + assert_eq!(res.value.as_str(), "[\"value1\",\"value2\",1,1.1]"); + } else { + panic!("Expected OwnedValue::Text"); + } + } + + #[test] + fn test_json_array_empty() { + let input = vec![]; + + let result = json_array(input).unwrap(); + if let OwnedValue::Text(res) = result { + assert_eq!(res.value.as_str(), "[]"); + } else { + panic!("Expected OwnedValue::Text"); + } + } + + #[test] + fn test_json_array_blob_invalid() { + let blob = OwnedValue::Blob(Rc::new("1".as_bytes().to_vec())); + + let input = vec![blob]; + + let result = json_array(input); + + match result { + Ok(_) => panic!("Expected error for blob input"), + Err(e) => assert!(e.to_string().contains("JSON cannot hold BLOB values")), + } + } } diff --git a/core/storage/sqlite3_ondisk.rs b/core/storage/sqlite3_ondisk.rs index a1f58d38a..a1a8aec0c 100644 --- a/core/storage/sqlite3_ondisk.rs +++ b/core/storage/sqlite3_ondisk.rs @@ -934,7 +934,7 @@ pub fn read_value(buf: &[u8], serial_type: &SerialType) -> Result<(OwnedValue, u } let bytes = buf[0..n].to_vec(); let value = unsafe { String::from_utf8_unchecked(bytes) }; - Ok((OwnedValue::Text(value.into()), n)) + Ok((OwnedValue::build_text(value.into()), n)) } } } @@ -1271,7 +1271,7 @@ mod tests { #[case(&[], SerialType::ConstInt0, OwnedValue::Integer(0))] #[case(&[], SerialType::ConstInt1, OwnedValue::Integer(1))] #[case(&[1, 2, 3], SerialType::Blob(3), OwnedValue::Blob(vec![1, 2, 3].into()))] - #[case(&[65, 66, 67], SerialType::String(3), OwnedValue::Text("ABC".to_string().into()))] + #[case(&[65, 66, 67], SerialType::String(3), OwnedValue::build_text("ABC".to_string().into()))] fn test_read_value( #[case] buf: &[u8], #[case] serial_type: SerialType, diff --git a/core/translate/expr.rs b/core/translate/expr.rs index b1db3ac92..679e86819 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -898,6 +898,22 @@ pub fn translate_expr( }); Ok(target_register) } + JsonFunc::JsonArray => { + allocate_registers( + program, + args, + referenced_tables, + precomputed_exprs_to_registers, + )?; + + program.emit_insn(Insn::Function { + constant_mask: 0, + start_reg: target_register + 1, + dest: target_register, + func: func_ctx, + }); + Ok(target_register) + } }, Func::Scalar(srf) => { match srf { @@ -905,18 +921,12 @@ pub fn translate_expr( unreachable!("this is always ast::Expr::Cast") } ScalarFunc::Char => { - let args = args.clone().unwrap_or_else(Vec::new); - - for arg in args.iter() { - let reg = program.alloc_register(); - translate_expr( - program, - referenced_tables, - arg, - reg, - precomputed_exprs_to_registers, - )?; - } + allocate_registers( + program, + args, + referenced_tables, + precomputed_exprs_to_registers, + )?; program.emit_insn(Insn::Function { constant_mask: 0, @@ -1942,6 +1952,28 @@ pub fn translate_expr( } } +fn allocate_registers( + program: &mut ProgramBuilder, + args: &Option>, + referenced_tables: Option<&[BTreeTableReference]>, + precomputed_exprs_to_registers: Option<&Vec<(&ast::Expr, usize)>>, +) -> Result<()> { + let args = args.clone().unwrap_or_else(Vec::new); + + for arg in args.iter() { + let reg = program.alloc_register(); + translate_expr( + program, + referenced_tables, + arg, + reg, + precomputed_exprs_to_registers, + )?; + } + + Ok(()) +} + fn wrap_eval_jump_expr( program: &mut ProgramBuilder, insn: Insn, diff --git a/core/types.rs b/core/types.rs index 7024ef257..5f1b55d7b 100644 --- a/core/types.rs +++ b/core/types.rs @@ -27,24 +27,59 @@ impl<'a> Display for Value<'a> { } } +#[derive(Debug, Clone, PartialEq)] +pub enum TextSubtype { + Text, + Json, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct LimboText { + pub value: Rc, + pub subtype: TextSubtype, +} + +impl LimboText { + pub fn new(value: Rc) -> Self { + Self { + value, + subtype: TextSubtype::Text, + } + } + + pub fn json(value: Rc) -> Self { + Self { + value, + subtype: TextSubtype::Json, + } + } +} + #[derive(Debug, Clone, PartialEq)] pub enum OwnedValue { Null, Integer(i64), Float(f64), - Text(Rc), + Text(LimboText), Blob(Rc>), Agg(Box), // TODO(pere): make this without Box. Currently this might cause cache miss but let's leave it for future analysis Record(OwnedRecord), } +impl OwnedValue { + // A helper function that makes building a text OwnedValue easier. + pub fn build_text(text: Rc) -> Self { + OwnedValue::Text(LimboText::new(text)) + } +} + impl Display for OwnedValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { OwnedValue::Null => write!(f, "NULL"), OwnedValue::Integer(i) => write!(f, "{}", i), OwnedValue::Float(fl) => write!(f, "{:?}", fl), - OwnedValue::Text(s) => write!(f, "{}", s), + OwnedValue::Text(s) => write!(f, "{}", s.value), OwnedValue::Blob(b) => write!(f, "{}", String::from_utf8_lossy(b)), OwnedValue::Agg(a) => match a.as_ref() { AggContext::Avg(acc, _count) => write!(f, "{}", acc), @@ -111,7 +146,7 @@ impl PartialOrd for OwnedValue { ) => Some(std::cmp::Ordering::Greater), (OwnedValue::Text(text_left), OwnedValue::Text(text_right)) => { - text_left.partial_cmp(text_right) + text_left.value.partial_cmp(&text_right.value) } // Text vs Blob (OwnedValue::Text(_), OwnedValue::Blob(_)) => Some(std::cmp::Ordering::Less), @@ -171,21 +206,27 @@ impl std::ops::Add for OwnedValue { OwnedValue::Float(float_left + float_right) } (OwnedValue::Text(string_left), OwnedValue::Text(string_right)) => { - OwnedValue::Text(Rc::new(string_left.to_string() + &string_right.to_string())) + OwnedValue::build_text(Rc::new( + string_left.value.to_string() + &string_right.value.to_string(), + )) } (OwnedValue::Text(string_left), OwnedValue::Integer(int_right)) => { - OwnedValue::Text(Rc::new(string_left.to_string() + &int_right.to_string())) + OwnedValue::build_text(Rc::new( + string_left.value.to_string() + &int_right.to_string(), + )) } (OwnedValue::Integer(int_left), OwnedValue::Text(string_right)) => { - OwnedValue::Text(Rc::new(int_left.to_string() + &string_right.to_string())) + OwnedValue::build_text(Rc::new( + int_left.to_string() + &string_right.value.to_string(), + )) } (OwnedValue::Text(string_left), OwnedValue::Float(float_right)) => { let string_right = OwnedValue::Float(float_right).to_string(); - OwnedValue::Text(Rc::new(string_left.to_string() + &string_right)) + OwnedValue::build_text(Rc::new(string_left.value.to_string() + &string_right)) } (OwnedValue::Float(float_left), OwnedValue::Text(string_right)) => { let string_left = OwnedValue::Float(float_left).to_string(); - OwnedValue::Text(Rc::new(string_left + &string_right.to_string())) + OwnedValue::build_text(Rc::new(string_left + &string_right.value.to_string())) } (lhs, OwnedValue::Null) => lhs, (OwnedValue::Null, rhs) => rhs, @@ -269,7 +310,7 @@ pub fn to_value(value: &OwnedValue) -> Value<'_> { OwnedValue::Null => Value::Null, OwnedValue::Integer(i) => Value::Integer(*i), OwnedValue::Float(f) => Value::Float(*f), - OwnedValue::Text(s) => Value::Text(s), + OwnedValue::Text(s) => Value::Text(&s.value), OwnedValue::Blob(b) => Value::Blob(b), OwnedValue::Agg(a) => match a.as_ref() { AggContext::Avg(acc, _count) => match acc { @@ -359,7 +400,7 @@ impl OwnedRecord { OwnedValue::Null => 0, OwnedValue::Integer(_) => 6, // for now let's only do i64 OwnedValue::Float(_) => 7, - OwnedValue::Text(t) => (t.len() * 2 + 13) as u64, + OwnedValue::Text(t) => (t.value.len() * 2 + 13) as u64, OwnedValue::Blob(b) => (b.len() * 2 + 12) as u64, // not serializable values OwnedValue::Agg(_) => unreachable!(), @@ -380,7 +421,7 @@ impl OwnedRecord { OwnedValue::Null => {} OwnedValue::Integer(i) => buf.extend_from_slice(&i.to_be_bytes()), OwnedValue::Float(f) => buf.extend_from_slice(&f.to_be_bytes()), - OwnedValue::Text(t) => buf.extend_from_slice(t.as_bytes()), + OwnedValue::Text(t) => buf.extend_from_slice(t.value.as_bytes()), OwnedValue::Blob(b) => buf.extend_from_slice(b), // non serializable OwnedValue::Agg(_) => unreachable!(), diff --git a/core/vdbe/datetime.rs b/core/vdbe/datetime.rs index 86ad57677..7b9e49fd6 100644 --- a/core/vdbe/datetime.rs +++ b/core/vdbe/datetime.rs @@ -10,53 +10,53 @@ use crate::Result; /// Implementation of the date() SQL function. pub fn exec_date(values: &[OwnedValue]) -> OwnedValue { let maybe_dt = match values.first() { - None => parse_naive_date_time(&OwnedValue::Text(Rc::new("now".to_string()))), + None => parse_naive_date_time(&OwnedValue::build_text(Rc::new("now".to_string()))), Some(value) => parse_naive_date_time(value), }; // early return, no need to look at modifiers if result invalid if maybe_dt.is_none() { - return OwnedValue::Text(Rc::new(String::new())); + return OwnedValue::build_text(Rc::new(String::new())); } // apply modifiers if result is valid let mut dt = maybe_dt.unwrap(); for modifier in values.iter().skip(1) { if let OwnedValue::Text(modifier_str) = modifier { - if apply_modifier(&mut dt, modifier_str).is_err() { - return OwnedValue::Text(Rc::new(String::new())); + if apply_modifier(&mut dt, &modifier_str.value).is_err() { + return OwnedValue::build_text(Rc::new(String::new())); } } else { - return OwnedValue::Text(Rc::new(String::new())); + return OwnedValue::build_text(Rc::new(String::new())); } } - OwnedValue::Text(Rc::new(get_date_from_naive_datetime(dt))) + OwnedValue::build_text(Rc::new(get_date_from_naive_datetime(dt))) } /// Implementation of the time() SQL function. pub fn exec_time(time_value: &[OwnedValue]) -> OwnedValue { let maybe_dt = match time_value.first() { - None => parse_naive_date_time(&OwnedValue::Text(Rc::new("now".to_string()))), + None => parse_naive_date_time(&OwnedValue::build_text(Rc::new("now".to_string()))), Some(value) => parse_naive_date_time(value), }; // early return, no need to look at modifiers if result invalid if maybe_dt.is_none() { - return OwnedValue::Text(Rc::new(String::new())); + return OwnedValue::build_text(Rc::new(String::new())); } // apply modifiers if result is valid let mut dt = maybe_dt.unwrap(); for modifier in time_value.iter().skip(1) { if let OwnedValue::Text(modifier_str) = modifier { - if apply_modifier(&mut dt, modifier_str).is_err() { - return OwnedValue::Text(Rc::new(String::new())); + if apply_modifier(&mut dt, &modifier_str.value).is_err() { + return OwnedValue::build_text(Rc::new(String::new())); } } else { - return OwnedValue::Text(Rc::new(String::new())); + return OwnedValue::build_text(Rc::new(String::new())); } } - OwnedValue::Text(Rc::new(get_time_from_naive_datetime(dt))) + OwnedValue::build_text(Rc::new(get_time_from_naive_datetime(dt))) } fn apply_modifier(dt: &mut NaiveDateTime, modifier: &str) -> Result<()> { @@ -125,7 +125,7 @@ fn get_unixepoch_from_naive_datetime(value: NaiveDateTime) -> String { fn parse_naive_date_time(time_value: &OwnedValue) -> Option { match time_value { - OwnedValue::Text(s) => get_date_time_from_time_value_string(s), + OwnedValue::Text(s) => get_date_time_from_time_value_string(&s.value), OwnedValue::Integer(i) => get_date_time_from_time_value_integer(*i), OwnedValue::Float(f) => get_date_time_from_time_value_float(*f), _ => None, @@ -410,197 +410,200 @@ mod tests { let test_cases = vec![ // Format 1: YYYY-MM-DD (no timezone applicable) ( - OwnedValue::Text(Rc::new("2024-07-21".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21".to_string())), test_date_str, ), // Format 2: YYYY-MM-DD HH:MM ( - OwnedValue::Text(Rc::new("2024-07-21 22:30".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30+02:00".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30-05:00".to_string())), next_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 01:30+05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 01:30+05:00".to_string())), prev_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30Z".to_string())), test_date_str, ), // Format 3: YYYY-MM-DD HH:MM:SS ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45+02:00".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45-05:00".to_string())), next_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 01:30:45+05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 01:30:45+05:00".to_string())), prev_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45Z".to_string())), test_date_str, ), // Format 4: YYYY-MM-DD HH:MM:SS.SSS ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45.123".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45.123".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45.123+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45.123+02:00".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45.123-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45.123-05:00".to_string())), next_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 01:30:45.123+05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 01:30:45.123+05:00".to_string())), prev_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45.123Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45.123Z".to_string())), test_date_str, ), // Format 5: YYYY-MM-DDTHH:MM ( - OwnedValue::Text(Rc::new("2024-07-21T22:30".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30+02:00".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30-05:00".to_string())), next_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T01:30+05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T01:30+05:00".to_string())), prev_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30Z".to_string())), test_date_str, ), // Format 6: YYYY-MM-DDTHH:MM:SS ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45+02:00".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45-05:00".to_string())), next_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T01:30:45+05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T01:30:45+05:00".to_string())), prev_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45Z".to_string())), test_date_str, ), // Format 7: YYYY-MM-DDTHH:MM:SS.SSS ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45.123".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45.123".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45.123+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45.123+02:00".to_string())), test_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45.123-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45.123-05:00".to_string())), next_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T01:30:45.123+05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T01:30:45.123+05:00".to_string())), prev_date_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45.123Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45.123Z".to_string())), test_date_str, ), // Format 8: HH:MM - (OwnedValue::Text(Rc::new("22:30".to_string())), "2000-01-01"), ( - OwnedValue::Text(Rc::new("22:30+02:00".to_string())), + OwnedValue::build_text(Rc::new("22:30".to_string())), "2000-01-01", ), ( - OwnedValue::Text(Rc::new("22:30-05:00".to_string())), + OwnedValue::build_text(Rc::new("22:30+02:00".to_string())), + "2000-01-01", + ), + ( + OwnedValue::build_text(Rc::new("22:30-05:00".to_string())), "2000-01-02", ), ( - OwnedValue::Text(Rc::new("01:30+05:00".to_string())), + OwnedValue::build_text(Rc::new("01:30+05:00".to_string())), "1999-12-31", ), ( - OwnedValue::Text(Rc::new("22:30Z".to_string())), + OwnedValue::build_text(Rc::new("22:30Z".to_string())), "2000-01-01", ), // Format 9: HH:MM:SS ( - OwnedValue::Text(Rc::new("22:30:45".to_string())), + OwnedValue::build_text(Rc::new("22:30:45".to_string())), "2000-01-01", ), ( - OwnedValue::Text(Rc::new("22:30:45+02:00".to_string())), + OwnedValue::build_text(Rc::new("22:30:45+02:00".to_string())), "2000-01-01", ), ( - OwnedValue::Text(Rc::new("22:30:45-05:00".to_string())), + OwnedValue::build_text(Rc::new("22:30:45-05:00".to_string())), "2000-01-02", ), ( - OwnedValue::Text(Rc::new("01:30:45+05:00".to_string())), + OwnedValue::build_text(Rc::new("01:30:45+05:00".to_string())), "1999-12-31", ), ( - OwnedValue::Text(Rc::new("22:30:45Z".to_string())), + OwnedValue::build_text(Rc::new("22:30:45Z".to_string())), "2000-01-01", ), // Format 10: HH:MM:SS.SSS ( - OwnedValue::Text(Rc::new("22:30:45.123".to_string())), + OwnedValue::build_text(Rc::new("22:30:45.123".to_string())), "2000-01-01", ), ( - OwnedValue::Text(Rc::new("22:30:45.123+02:00".to_string())), + OwnedValue::build_text(Rc::new("22:30:45.123+02:00".to_string())), "2000-01-01", ), ( - OwnedValue::Text(Rc::new("22:30:45.123-05:00".to_string())), + OwnedValue::build_text(Rc::new("22:30:45.123-05:00".to_string())), "2000-01-02", ), ( - OwnedValue::Text(Rc::new("01:30:45.123+05:00".to_string())), + OwnedValue::build_text(Rc::new("01:30:45.123+05:00".to_string())), "1999-12-31", ), ( - OwnedValue::Text(Rc::new("22:30:45.123Z".to_string())), + OwnedValue::build_text(Rc::new("22:30:45.123Z".to_string())), "2000-01-01", ), // Test Format 11: 'now' - (OwnedValue::Text(Rc::new("now".to_string())), &now), + (OwnedValue::build_text(Rc::new("now".to_string())), &now), // Format 12: DDDDDDDDDD (Julian date as float or integer) (OwnedValue::Float(2460512.5), test_date_str), (OwnedValue::Integer(2460513), test_date_str), @@ -610,7 +613,7 @@ mod tests { let result = exec_date(&[input.clone()]); assert_eq!( result, - OwnedValue::Text(Rc::new(expected.to_string())), + OwnedValue::build_text(Rc::new(expected.to_string())), "Failed for input: {:?}", input ); @@ -620,37 +623,37 @@ mod tests { #[test] fn test_invalid_get_date_from_time_value() { let invalid_cases = vec![ - OwnedValue::Text(Rc::new("2024-07-21 25:00".to_string())), // Invalid hour - OwnedValue::Text(Rc::new("2024-07-21 24:00:00".to_string())), // Invalid hour - OwnedValue::Text(Rc::new("2024-07-21 23:60:00".to_string())), // Invalid minute - OwnedValue::Text(Rc::new("2024-07-21 22:58:60".to_string())), // Invalid second - OwnedValue::Text(Rc::new("2024-07-32".to_string())), // Invalid day - OwnedValue::Text(Rc::new("2024-13-01".to_string())), // Invalid month - OwnedValue::Text(Rc::new("invalid_date".to_string())), // Completely invalid string - OwnedValue::Text(Rc::new("".to_string())), // Empty string - OwnedValue::Integer(i64::MAX), // Large Julian day - OwnedValue::Integer(-1), // Negative Julian day - OwnedValue::Float(f64::MAX), // Large float + OwnedValue::build_text(Rc::new("2024-07-21 25:00".to_string())), // Invalid hour + OwnedValue::build_text(Rc::new("2024-07-21 24:00:00".to_string())), // Invalid hour + OwnedValue::build_text(Rc::new("2024-07-21 23:60:00".to_string())), // Invalid minute + OwnedValue::build_text(Rc::new("2024-07-21 22:58:60".to_string())), // Invalid second + OwnedValue::build_text(Rc::new("2024-07-32".to_string())), // Invalid day + OwnedValue::build_text(Rc::new("2024-13-01".to_string())), // Invalid month + OwnedValue::build_text(Rc::new("invalid_date".to_string())), // Completely invalid string + OwnedValue::build_text(Rc::new("".to_string())), // Empty string + OwnedValue::Integer(i64::MAX), // Large Julian day + OwnedValue::Integer(-1), // Negative Julian day + OwnedValue::Float(f64::MAX), // Large float OwnedValue::Float(-1.0), // Negative Julian day as float OwnedValue::Float(f64::NAN), // NaN OwnedValue::Float(f64::INFINITY), // Infinity OwnedValue::Null, // Null value OwnedValue::Blob(vec![1, 2, 3].into()), // Blob (unsupported type) // Invalid timezone tests - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+24:00".to_string())), // Invalid timezone offset (too large) - OwnedValue::Text(Rc::new("2024-07-21T12:00:00-24:00".to_string())), // Invalid timezone offset (too small) - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+00:60".to_string())), // Invalid timezone minutes - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+00:00:00".to_string())), // Invalid timezone format (extra seconds) - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+".to_string())), // Incomplete timezone - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+Z".to_string())), // Invalid timezone format - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+00:00Z".to_string())), // Mixing offset and Z - OwnedValue::Text(Rc::new("2024-07-21T12:00:00UTC".to_string())), // Named timezone (not supported) + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+24:00".to_string())), // Invalid timezone offset (too large) + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00-24:00".to_string())), // Invalid timezone offset (too small) + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+00:60".to_string())), // Invalid timezone minutes + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+00:00:00".to_string())), // Invalid timezone format (extra seconds) + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+".to_string())), // Incomplete timezone + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+Z".to_string())), // Invalid timezone format + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+00:00Z".to_string())), // Mixing offset and Z + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00UTC".to_string())), // Named timezone (not supported) ]; for case in invalid_cases.iter() { let result = exec_date(&[case.clone()]); match result { - OwnedValue::Text(ref result_str) if result_str.is_empty() => (), + OwnedValue::Text(ref result_str) if result_str.value.is_empty() => (), _ => panic!( "Expected empty string for input: {:?}, but got: {:?}", case, result @@ -670,158 +673,164 @@ mod tests { let test_cases = vec![ // Format 1: YYYY-MM-DD (no timezone applicable) ( - OwnedValue::Text(Rc::new("2024-07-21".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21".to_string())), "00:00:00", ), // Format 2: YYYY-MM-DD HH:MM ( - OwnedValue::Text(Rc::new("2024-07-21 22:30".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30".to_string())), "22:30:00", ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30+02:00".to_string())), "20:30:00", ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30-05:00".to_string())), "03:30:00", ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30Z".to_string())), "22:30:00", ), // Format 3: YYYY-MM-DD HH:MM:SS ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45".to_string())), test_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45+02:00".to_string())), prev_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45-05:00".to_string())), next_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45Z".to_string())), test_time_str, ), // Format 4: YYYY-MM-DD HH:MM:SS.SSS ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45.123".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45.123".to_string())), test_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45.123+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45.123+02:00".to_string())), prev_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45.123-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45.123-05:00".to_string())), next_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21 22:30:45.123Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21 22:30:45.123Z".to_string())), test_time_str, ), // Format 5: YYYY-MM-DDTHH:MM ( - OwnedValue::Text(Rc::new("2024-07-21T22:30".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30".to_string())), "22:30:00", ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30+02:00".to_string())), "20:30:00", ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30-05:00".to_string())), "03:30:00", ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30Z".to_string())), "22:30:00", ), // Format 6: YYYY-MM-DDTHH:MM:SS ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45".to_string())), test_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45+02:00".to_string())), prev_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45-05:00".to_string())), next_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45Z".to_string())), test_time_str, ), // Format 7: YYYY-MM-DDTHH:MM:SS.SSS ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45.123".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45.123".to_string())), test_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45.123+02:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45.123+02:00".to_string())), prev_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45.123-05:00".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45.123-05:00".to_string())), next_time_str, ), ( - OwnedValue::Text(Rc::new("2024-07-21T22:30:45.123Z".to_string())), + OwnedValue::build_text(Rc::new("2024-07-21T22:30:45.123Z".to_string())), test_time_str, ), // Format 8: HH:MM - (OwnedValue::Text(Rc::new("22:30".to_string())), "22:30:00"), ( - OwnedValue::Text(Rc::new("22:30+02:00".to_string())), + OwnedValue::build_text(Rc::new("22:30".to_string())), + "22:30:00", + ), + ( + OwnedValue::build_text(Rc::new("22:30+02:00".to_string())), "20:30:00", ), ( - OwnedValue::Text(Rc::new("22:30-05:00".to_string())), + OwnedValue::build_text(Rc::new("22:30-05:00".to_string())), "03:30:00", ), - (OwnedValue::Text(Rc::new("22:30Z".to_string())), "22:30:00"), + ( + OwnedValue::build_text(Rc::new("22:30Z".to_string())), + "22:30:00", + ), // Format 9: HH:MM:SS ( - OwnedValue::Text(Rc::new("22:30:45".to_string())), + OwnedValue::build_text(Rc::new("22:30:45".to_string())), test_time_str, ), ( - OwnedValue::Text(Rc::new("22:30:45+02:00".to_string())), + OwnedValue::build_text(Rc::new("22:30:45+02:00".to_string())), prev_time_str, ), ( - OwnedValue::Text(Rc::new("22:30:45-05:00".to_string())), + OwnedValue::build_text(Rc::new("22:30:45-05:00".to_string())), next_time_str, ), ( - OwnedValue::Text(Rc::new("22:30:45Z".to_string())), + OwnedValue::build_text(Rc::new("22:30:45Z".to_string())), test_time_str, ), // Format 10: HH:MM:SS.SSS ( - OwnedValue::Text(Rc::new("22:30:45.123".to_string())), + OwnedValue::build_text(Rc::new("22:30:45.123".to_string())), test_time_str, ), ( - OwnedValue::Text(Rc::new("22:30:45.123+02:00".to_string())), + OwnedValue::build_text(Rc::new("22:30:45.123+02:00".to_string())), prev_time_str, ), ( - OwnedValue::Text(Rc::new("22:30:45.123-05:00".to_string())), + OwnedValue::build_text(Rc::new("22:30:45.123-05:00".to_string())), next_time_str, ), ( - OwnedValue::Text(Rc::new("22:30:45.123Z".to_string())), + OwnedValue::build_text(Rc::new("22:30:45.123Z".to_string())), test_time_str, ), // Test Format 11: 'now' - (OwnedValue::Text(Rc::new("now".to_string())), &now), + (OwnedValue::build_text(Rc::new("now".to_string())), &now), // Format 12: DDDDDDDDDD (Julian date as float or integer) (OwnedValue::Float(2460082.1), "14:24:00"), (OwnedValue::Integer(2460082), "12:00:00"), @@ -830,7 +839,7 @@ mod tests { for (input, expected) in test_cases { let result = exec_time(&[input]); if let OwnedValue::Text(result_str) = result { - assert_eq!(result_str.as_str(), expected); + assert_eq!(result_str.value.as_str(), expected); } else { panic!("Expected OwnedValue::Text, but got: {:?}", result); } @@ -840,37 +849,37 @@ mod tests { #[test] fn test_invalid_get_time_from_datetime_value() { let invalid_cases = vec![ - OwnedValue::Text(Rc::new("2024-07-21 25:00".to_string())), // Invalid hour - OwnedValue::Text(Rc::new("2024-07-21 24:00:00".to_string())), // Invalid hour - OwnedValue::Text(Rc::new("2024-07-21 23:60:00".to_string())), // Invalid minute - OwnedValue::Text(Rc::new("2024-07-21 22:58:60".to_string())), // Invalid second - OwnedValue::Text(Rc::new("2024-07-32".to_string())), // Invalid day - OwnedValue::Text(Rc::new("2024-13-01".to_string())), // Invalid month - OwnedValue::Text(Rc::new("invalid_date".to_string())), // Completely invalid string - OwnedValue::Text(Rc::new("".to_string())), // Empty string - OwnedValue::Integer(i64::MAX), // Large Julian day - OwnedValue::Integer(-1), // Negative Julian day - OwnedValue::Float(f64::MAX), // Large float + OwnedValue::build_text(Rc::new("2024-07-21 25:00".to_string())), // Invalid hour + OwnedValue::build_text(Rc::new("2024-07-21 24:00:00".to_string())), // Invalid hour + OwnedValue::build_text(Rc::new("2024-07-21 23:60:00".to_string())), // Invalid minute + OwnedValue::build_text(Rc::new("2024-07-21 22:58:60".to_string())), // Invalid second + OwnedValue::build_text(Rc::new("2024-07-32".to_string())), // Invalid day + OwnedValue::build_text(Rc::new("2024-13-01".to_string())), // Invalid month + OwnedValue::build_text(Rc::new("invalid_date".to_string())), // Completely invalid string + OwnedValue::build_text(Rc::new("".to_string())), // Empty string + OwnedValue::Integer(i64::MAX), // Large Julian day + OwnedValue::Integer(-1), // Negative Julian day + OwnedValue::Float(f64::MAX), // Large float OwnedValue::Float(-1.0), // Negative Julian day as float OwnedValue::Float(f64::NAN), // NaN OwnedValue::Float(f64::INFINITY), // Infinity OwnedValue::Null, // Null value OwnedValue::Blob(vec![1, 2, 3].into()), // Blob (unsupported type) // Invalid timezone tests - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+24:00".to_string())), // Invalid timezone offset (too large) - OwnedValue::Text(Rc::new("2024-07-21T12:00:00-24:00".to_string())), // Invalid timezone offset (too small) - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+00:60".to_string())), // Invalid timezone minutes - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+00:00:00".to_string())), // Invalid timezone format (extra seconds) - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+".to_string())), // Incomplete timezone - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+Z".to_string())), // Invalid timezone format - OwnedValue::Text(Rc::new("2024-07-21T12:00:00+00:00Z".to_string())), // Mixing offset and Z - OwnedValue::Text(Rc::new("2024-07-21T12:00:00UTC".to_string())), // Named timezone (not supported) + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+24:00".to_string())), // Invalid timezone offset (too large) + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00-24:00".to_string())), // Invalid timezone offset (too small) + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+00:60".to_string())), // Invalid timezone minutes + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+00:00:00".to_string())), // Invalid timezone format (extra seconds) + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+".to_string())), // Incomplete timezone + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+Z".to_string())), // Invalid timezone format + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00+00:00Z".to_string())), // Mixing offset and Z + OwnedValue::build_text(Rc::new("2024-07-21T12:00:00UTC".to_string())), // Named timezone (not supported) ]; for case in invalid_cases { let result = exec_time(&[case.clone()]); match result { - OwnedValue::Text(ref result_str) if result_str.is_empty() => (), + OwnedValue::Text(ref result_str) if result_str.value.is_empty() => (), _ => panic!( "Expected empty string for input: {:?}, but got: {:?}", case, result diff --git a/core/vdbe/explain.rs b/core/vdbe/explain.rs index c88ac8b91..ce03a53fd 100644 --- a/core/vdbe/explain.rs +++ b/core/vdbe/explain.rs @@ -1,4 +1,5 @@ use super::{Insn, InsnReference, OwnedValue, Program}; +use crate::types::LimboText; use std::rc::Rc; pub fn insn_to_str( @@ -15,7 +16,7 @@ pub fn insn_to_str( 0, *target_pc as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("Start at {}", target_pc), ), @@ -24,7 +25,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *dest as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=r[{}]+r[{}]", dest, lhs, rhs), ), @@ -33,7 +34,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *dest as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=r[{}]-r[{}]", dest, lhs, rhs), ), @@ -42,7 +43,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *dest as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=r[{}]*r[{}]", dest, lhs, rhs), ), @@ -51,7 +52,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *dest as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=r[{}]/r[{}]", dest, lhs, rhs), ), @@ -60,7 +61,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *dest as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=r[{}]&r[{}]", dest, lhs, rhs), ), @@ -69,7 +70,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *dest as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=r[{}]|r[{}]", dest, lhs, rhs), ), @@ -78,7 +79,7 @@ pub fn insn_to_str( *reg as i32, *dest as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=~r[{}]", dest, reg), ), @@ -87,7 +88,7 @@ pub fn insn_to_str( 0, *dest as i32, dest_end.map_or(0, |end| end as i32), - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, dest_end.map_or(format!("r[{}]=NULL", dest), |end| { format!("r[{}..{}]=NULL", dest, end) @@ -98,7 +99,7 @@ pub fn insn_to_str( *cursor_id as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("Set cursor {} to a (pseudo) NULL row", cursor_id), ), @@ -107,7 +108,7 @@ pub fn insn_to_str( *reg as i32, *target_pc as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]!=NULL -> goto {}", reg, target_pc), ), @@ -120,7 +121,7 @@ pub fn insn_to_str( *start_reg_a as i32, *start_reg_b as i32, *count as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "r[{}..{}]==r[{}..{}]", @@ -139,7 +140,7 @@ pub fn insn_to_str( *target_pc_lt as i32, *target_pc_eq as i32, *target_pc_gt as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -152,7 +153,7 @@ pub fn insn_to_str( *source_reg as i32, *dest_reg as i32, *count as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "r[{}..{}]=r[{}..{}]", @@ -171,7 +172,7 @@ pub fn insn_to_str( *reg as i32, *target_pc as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "r[{}]>0 -> r[{}]-={}, goto {}", @@ -187,7 +188,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *target_pc as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("if r[{}]==r[{}] goto {}", lhs, rhs, target_pc), ), @@ -200,7 +201,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *target_pc as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("if r[{}]!=r[{}] goto {}", lhs, rhs, target_pc), ), @@ -213,7 +214,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *target_pc as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("if r[{}]r[{}] goto {}", lhs, rhs, target_pc), ), @@ -252,7 +253,7 @@ pub fn insn_to_str( *lhs as i32, *rhs as i32, *target_pc as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("if r[{}]>=r[{}] goto {}", lhs, rhs, target_pc), ), @@ -265,7 +266,7 @@ pub fn insn_to_str( *reg as i32, *target_pc as i32, *null_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("if r[{}] goto {}", reg, target_pc), ), @@ -278,7 +279,7 @@ pub fn insn_to_str( *reg as i32, *target_pc as i32, *null_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("if !r[{}] goto {}", reg, target_pc), ), @@ -290,7 +291,7 @@ pub fn insn_to_str( *cursor_id as i32, *root_page as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "table={}, root={}", @@ -306,7 +307,7 @@ pub fn insn_to_str( 0, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -319,7 +320,7 @@ pub fn insn_to_str( *cursor_id as i32, *content_reg as i32, *num_fields as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("{} columns in r[{}]", num_fields, content_reg), ), @@ -328,7 +329,7 @@ pub fn insn_to_str( *cursor_id as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -340,7 +341,7 @@ pub fn insn_to_str( *cursor_id as i32, *pc_if_empty as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "Rewind table {}", @@ -361,7 +362,7 @@ pub fn insn_to_str( *cursor_id as i32, *column as i32, *dest as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "r[{}]={}.{}", @@ -385,7 +386,7 @@ pub fn insn_to_str( *start_reg as i32, *count as i32, *dest_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "r[{}]=mkrec(r[{}..{}])", @@ -399,7 +400,7 @@ pub fn insn_to_str( *start_reg as i32, *count as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, if *count == 1 { format!("output=r[{}]", start_reg) @@ -412,7 +413,7 @@ pub fn insn_to_str( *cursor_id as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -424,7 +425,7 @@ pub fn insn_to_str( *cursor_id as i32, *pc_if_next as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -436,7 +437,7 @@ pub fn insn_to_str( *err_code as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -445,7 +446,7 @@ pub fn insn_to_str( 0, *write as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -454,7 +455,7 @@ pub fn insn_to_str( 0, *target_pc as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -466,7 +467,7 @@ pub fn insn_to_str( *return_reg as i32, *target_pc as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -475,7 +476,7 @@ pub fn insn_to_str( *return_reg as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -484,7 +485,7 @@ pub fn insn_to_str( *value as i32, *dest as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]={}", dest, value), ), @@ -502,7 +503,7 @@ pub fn insn_to_str( *register as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -511,7 +512,7 @@ pub fn insn_to_str( 0, *dest as i32, 0, - OwnedValue::Text(Rc::new(value.clone())), + OwnedValue::build_text(Rc::new(value.clone())), 0, format!("r[{}]='{}'", dest, value), ), @@ -534,7 +535,7 @@ pub fn insn_to_str( *cursor_id as i32, *dest as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "r[{}]={}.rowid", @@ -554,7 +555,7 @@ pub fn insn_to_str( *cursor_id as i32, *src_reg as i32, *target_pc as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!( "if (r[{}]!={}.rowid) goto {}", @@ -574,7 +575,7 @@ pub fn insn_to_str( *index_cursor_id as i32, *table_cursor_id as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -589,7 +590,7 @@ pub fn insn_to_str( *cursor_id as i32, *target_pc as i32, *start_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -604,7 +605,7 @@ pub fn insn_to_str( *cursor_id as i32, *target_pc as i32, *start_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -618,7 +619,7 @@ pub fn insn_to_str( *cursor_id as i32, *target_pc as i32, *start_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -632,7 +633,7 @@ pub fn insn_to_str( *cursor_id as i32, *target_pc as i32, *start_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -641,7 +642,7 @@ pub fn insn_to_str( *reg as i32, *target_pc as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("if (--r[{}]==0) goto {}", reg, target_pc), ), @@ -655,7 +656,7 @@ pub fn insn_to_str( 0, *col as i32, *acc_reg as i32, - OwnedValue::Text(Rc::new(func.to_string().into())), + OwnedValue::build_text(Rc::new(func.to_string().into())), 0, format!("accum=r[{}] step(r[{}])", *acc_reg, *col), ), @@ -664,7 +665,7 @@ pub fn insn_to_str( 0, *register as i32, 0, - OwnedValue::Text(Rc::new(func.to_string().into())), + OwnedValue::build_text(Rc::new(func.to_string().into())), 0, format!("accum=r[{}]", *register), ), @@ -693,7 +694,7 @@ pub fn insn_to_str( *cursor_id as i32, *columns as i32, 0, - OwnedValue::Text(Rc::new(format!( + OwnedValue::build_text(Rc::new(format!( "k({},{})", order.values.len(), to_print.join(",") @@ -711,7 +712,7 @@ pub fn insn_to_str( *cursor_id as i32, *dest_reg as i32, *pseudo_cursor as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=data", dest_reg), ), @@ -735,7 +736,7 @@ pub fn insn_to_str( *cursor_id as i32, *pc_if_empty as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -747,7 +748,7 @@ pub fn insn_to_str( *cursor_id as i32, *pc_if_next as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -761,7 +762,7 @@ pub fn insn_to_str( *constant_mask, *start_reg as i32, *dest as i32, - OwnedValue::Text(Rc::new(func.func.to_string())), + OwnedValue::build_text(Rc::new(func.func.to_string())), 0, if func.arg_count == 0 { format!("r[{}]=func()", dest) @@ -785,7 +786,7 @@ pub fn insn_to_str( *yield_reg as i32, *jump_on_definition as i32, *start_offset as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -794,7 +795,7 @@ pub fn insn_to_str( *yield_reg as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -806,7 +807,7 @@ pub fn insn_to_str( *yield_reg as i32, *end_offset as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -820,7 +821,7 @@ pub fn insn_to_str( *cursor as i32, *record_reg as i32, *key_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), *flag as u16, "".to_string(), ), @@ -829,7 +830,7 @@ pub fn insn_to_str( *cursor_id as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -842,7 +843,7 @@ pub fn insn_to_str( *cursor as i32, *rowid_reg as i32, *prev_largest_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -851,7 +852,7 @@ pub fn insn_to_str( *reg as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -860,7 +861,7 @@ pub fn insn_to_str( *reg as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -873,7 +874,7 @@ pub fn insn_to_str( *cursor as i32, *target_pc as i32, *rowid_reg as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -885,7 +886,7 @@ pub fn insn_to_str( *cursor_id as i32, *root_page as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -894,7 +895,7 @@ pub fn insn_to_str( 0, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -907,7 +908,7 @@ pub fn insn_to_str( *src_reg as i32, *dst_reg as i32, *amount as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=r[{}]", dst_reg, src_reg), ), @@ -916,7 +917,7 @@ pub fn insn_to_str( *db as i32, *root as i32, *flags as i32, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("r[{}]=root iDb={} flags={}", root, db, flags), ), @@ -925,7 +926,7 @@ pub fn insn_to_str( *cursor_id as i32, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -934,7 +935,7 @@ pub fn insn_to_str( 0, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -943,7 +944,7 @@ pub fn insn_to_str( *src as i32, *target_pc as i32, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, format!("if (r[{}]==NULL) goto {}", src, target_pc), ), @@ -952,7 +953,7 @@ pub fn insn_to_str( *db as i32, 0, 0, - OwnedValue::Text(Rc::new(where_clause.clone())), + OwnedValue::build_text(Rc::new(where_clause.clone())), 0, where_clause.clone(), ), @@ -961,7 +962,7 @@ pub fn insn_to_str( 0, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -970,7 +971,7 @@ pub fn insn_to_str( 0, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), @@ -979,7 +980,7 @@ pub fn insn_to_str( 0, 0, 0, - OwnedValue::Text(Rc::new("".to_string())), + OwnedValue::build_text(Rc::new("".to_string())), 0, "".to_string(), ), diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 069782c9a..9d07d94b0 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -34,7 +34,7 @@ use crate::types::{ }; use crate::util::parse_schema_rows; #[cfg(feature = "json")] -use crate::{function::JsonFunc, json::get_json}; +use crate::{function::JsonFunc, json::get_json, json::json_array}; use crate::{Connection, Result, TransactionState}; use crate::{Rows, DATABASE_VERSION}; @@ -1727,7 +1727,7 @@ impl Program { state.pc += 1; } Insn::String8 { value, dest } => { - state.registers[*dest] = OwnedValue::Text(Rc::new(value.into())); + state.registers[*dest] = OwnedValue::build_text(Rc::new(value.into())); state.pc += 1; } Insn::Blob { value, dest } => { @@ -1994,9 +1994,11 @@ impl Program { } } } - AggFunc::GroupConcat | AggFunc::StringAgg => OwnedValue::Agg(Box::new( - AggContext::GroupConcat(OwnedValue::Text(Rc::new("".to_string()))), - )), + AggFunc::GroupConcat | AggFunc::StringAgg => { + OwnedValue::Agg(Box::new(AggContext::GroupConcat( + OwnedValue::build_text(Rc::new("".to_string())), + ))) + } }; } match func { @@ -2067,7 +2069,7 @@ impl Program { Some(OwnedValue::Text(ref mut current_max)), OwnedValue::Text(value), ) => { - if value > *current_max { + if value.value > current_max.value { *current_max = value; } } @@ -2108,10 +2110,10 @@ impl Program { } ( Some(OwnedValue::Text(ref mut current_min)), - OwnedValue::Text(value), + OwnedValue::Text(text), ) => { - if value < *current_min { - *current_min = value; + if text.value < current_min.value { + *current_min = text; } } _ => { @@ -2263,6 +2265,18 @@ impl Program { Err(e) => return Err(e), } } + #[cfg(feature = "json")] + crate::function::Func::Json(JsonFunc::JsonArray) => { + let reg_values = + state.registers[*start_reg..*start_reg + arg_count].to_vec(); + + let json_array = json_array(reg_values); + + match json_array { + Ok(json) => state.registers[*dest] = json, + Err(e) => return Err(e), + } + } crate::function::Func::Scalar(scalar_func) => match scalar_func { ScalarFunc::Cast => { assert!(arg_count == 2); @@ -2273,7 +2287,7 @@ impl Program { else { unreachable!("Cast with non-text type"); }; - let result = exec_cast(®_value_argument, ®_value_type); + let result = exec_cast(®_value_argument, ®_value_type.value); state.registers[*dest] = result; } ScalarFunc::Char => { @@ -2304,7 +2318,12 @@ impl Program { } else { None }; - OwnedValue::Integer(exec_glob(cache, pattern, text) as i64) + OwnedValue::Integer(exec_glob( + cache, + &pattern.value, + &text.value, + ) + as i64) } _ => { unreachable!("Like on non-text registers"); @@ -2338,7 +2357,12 @@ impl Program { } else { None }; - OwnedValue::Integer(exec_like(cache, pattern, text) as i64) + OwnedValue::Integer(exec_like( + cache, + &pattern.value, + &text.value, + ) + as i64) } _ => { unreachable!("Like on non-text registers"); @@ -2457,16 +2481,18 @@ impl Program { } ScalarFunc::UnixEpoch => { if *start_reg == 0 { - let unixepoch: String = exec_unixepoch(&OwnedValue::Text( - Rc::new("now".to_string()), - ))?; - state.registers[*dest] = OwnedValue::Text(Rc::new(unixepoch)); + let unixepoch: String = exec_unixepoch( + &OwnedValue::build_text(Rc::new("now".to_string())), + )?; + state.registers[*dest] = + OwnedValue::build_text(Rc::new(unixepoch)); } else { let datetime_value = &state.registers[*start_reg]; let unixepoch = exec_unixepoch(datetime_value); match unixepoch { Ok(time) => { - state.registers[*dest] = OwnedValue::Text(Rc::new(time)) + state.registers[*dest] = + OwnedValue::build_text(Rc::new(time)) } Err(e) => { return Err(LimboError::ParseError(format!( @@ -2481,7 +2507,7 @@ impl Program { let version_integer: i64 = DATABASE_VERSION.get().unwrap().parse()?; let version = execute_sqlite_version(version_integer); - state.registers[*dest] = OwnedValue::Text(Rc::new(version)); + state.registers[*dest] = OwnedValue::build_text(Rc::new(version)); } ScalarFunc::Replace => { assert!(arg_count == 3); @@ -2817,7 +2843,7 @@ fn get_indent_count(indent_count: usize, curr_insn: &Insn, prev_insn: Option<&In fn exec_lower(reg: &OwnedValue) -> Option { match reg { - OwnedValue::Text(t) => Some(OwnedValue::Text(Rc::new(t.to_lowercase()))), + OwnedValue::Text(t) => Some(OwnedValue::build_text(Rc::new(t.value.to_lowercase()))), t => Some(t.to_owned()), } } @@ -2846,7 +2872,7 @@ fn exec_octet_length(reg: &OwnedValue) -> OwnedValue { fn exec_upper(reg: &OwnedValue) -> Option { match reg { - OwnedValue::Text(t) => Some(OwnedValue::Text(Rc::new(t.to_uppercase()))), + OwnedValue::Text(t) => Some(OwnedValue::build_text(Rc::new(t.value.to_uppercase()))), t => Some(t.to_owned()), } } @@ -2855,7 +2881,7 @@ fn exec_concat(registers: &[OwnedValue]) -> OwnedValue { let mut result = String::new(); for reg in registers { match reg { - OwnedValue::Text(text) => result.push_str(text), + OwnedValue::Text(text) => result.push_str(&text.value), OwnedValue::Integer(i) => result.push_str(&i.to_string()), OwnedValue::Float(f) => result.push_str(&f.to_string()), OwnedValue::Agg(aggctx) => result.push_str(&aggctx.final_value().to_string()), @@ -2864,7 +2890,7 @@ fn exec_concat(registers: &[OwnedValue]) -> OwnedValue { OwnedValue::Record(_) => unreachable!(), } } - OwnedValue::Text(Rc::new(result)) + OwnedValue::build_text(Rc::new(result)) } fn exec_concat_ws(registers: &[OwnedValue]) -> OwnedValue { @@ -2873,7 +2899,7 @@ fn exec_concat_ws(registers: &[OwnedValue]) -> OwnedValue { } let separator = match ®isters[0] { - OwnedValue::Text(text) => text.clone(), + OwnedValue::Text(text) => text.value.clone(), OwnedValue::Integer(i) => Rc::new(i.to_string()), OwnedValue::Float(f) => Rc::new(f.to_string()), _ => return OwnedValue::Null, @@ -2885,14 +2911,14 @@ fn exec_concat_ws(registers: &[OwnedValue]) -> OwnedValue { result.push_str(&separator); } match reg { - OwnedValue::Text(text) => result.push_str(text), + OwnedValue::Text(text) => result.push_str(&text.value), OwnedValue::Integer(i) => result.push_str(&i.to_string()), OwnedValue::Float(f) => result.push_str(&f.to_string()), _ => continue, } } - OwnedValue::Text(Rc::new(result)) + OwnedValue::build_text(Rc::new(result)) } fn exec_sign(reg: &OwnedValue) -> Option { @@ -2900,9 +2926,9 @@ fn exec_sign(reg: &OwnedValue) -> Option { OwnedValue::Integer(i) => *i as f64, OwnedValue::Float(f) => *f, OwnedValue::Text(s) => { - if let Ok(i) = s.parse::() { + if let Ok(i) = s.value.parse::() { i as f64 - } else if let Ok(f) = s.parse::() { + } else if let Ok(f) = s.value.parse::() { f } else { return Some(OwnedValue::Null); @@ -2937,25 +2963,26 @@ fn exec_sign(reg: &OwnedValue) -> Option { /// Generates the Soundex code for a given word pub fn exec_soundex(reg: &OwnedValue) -> OwnedValue { let s = match reg { - OwnedValue::Null => return OwnedValue::Text(Rc::new("?000".to_string())), + OwnedValue::Null => return OwnedValue::build_text(Rc::new("?000".to_string())), OwnedValue::Text(s) => { // return ?000 if non ASCII alphabet character is found - if !s.chars().all(|c| c.is_ascii_alphabetic()) { - return OwnedValue::Text(Rc::new("?000".to_string())); + if !s.value.chars().all(|c| c.is_ascii_alphabetic()) { + return OwnedValue::build_text(Rc::new("?000".to_string())); } s.clone() } - _ => return OwnedValue::Text(Rc::new("?000".to_string())), // For unsupported types, return NULL + _ => return OwnedValue::build_text(Rc::new("?000".to_string())), // For unsupported types, return NULL }; // Remove numbers and spaces let word: String = s + .value .chars() .filter(|c| !c.is_digit(10)) .collect::() .replace(" ", ""); if word.is_empty() { - return OwnedValue::Text(Rc::new("0000".to_string())); + return OwnedValue::build_text(Rc::new("0000".to_string())); } let soundex_code = |c| match c { @@ -3021,7 +3048,7 @@ pub fn exec_soundex(reg: &OwnedValue) -> OwnedValue { // Retain the first 4 characters and convert to uppercase result.truncate(4); - OwnedValue::Text(Rc::new(result.to_uppercase())) + OwnedValue::build_text(Rc::new(result.to_uppercase())) } fn exec_abs(reg: &OwnedValue) -> Option { @@ -3056,7 +3083,7 @@ fn exec_randomblob(reg: &OwnedValue) -> OwnedValue { let length = match reg { OwnedValue::Integer(i) => *i, OwnedValue::Float(f) => *f as i64, - OwnedValue::Text(t) => t.parse().unwrap_or(1), + OwnedValue::Text(t) => t.value.parse().unwrap_or(1), _ => 1, } .max(1) as usize; @@ -3068,13 +3095,13 @@ fn exec_randomblob(reg: &OwnedValue) -> OwnedValue { fn exec_quote(value: &OwnedValue) -> OwnedValue { match value { - OwnedValue::Null => OwnedValue::Text(OwnedValue::Null.to_string().into()), + OwnedValue::Null => OwnedValue::build_text(OwnedValue::Null.to_string().into()), OwnedValue::Integer(_) | OwnedValue::Float(_) => value.to_owned(), OwnedValue::Blob(_) => todo!(), OwnedValue::Text(s) => { - let mut quoted = String::with_capacity(s.len() + 2); + let mut quoted = String::with_capacity(s.value.len() + 2); quoted.push('\''); - for c in s.chars() { + for c in s.value.chars() { if c == '\0' { break; } else { @@ -3082,7 +3109,7 @@ fn exec_quote(value: &OwnedValue) -> OwnedValue { } } quoted.push('\''); - OwnedValue::Text(Rc::new(quoted)) + OwnedValue::build_text(Rc::new(quoted)) } _ => OwnedValue::Null, // For unsupported types, return NULL } @@ -3099,7 +3126,7 @@ fn exec_char(values: Vec) -> OwnedValue { } }) .collect(); - OwnedValue::Text(Rc::new(result)) + OwnedValue::build_text(Rc::new(result)) } fn construct_like_regex(pattern: &str) -> Regex { @@ -3183,31 +3210,33 @@ fn exec_substring( (str_value, start_value, length_value) { let start = *start as usize; - if start > str.len() { - return OwnedValue::Text(Rc::new("".to_string())); + let str_len = str.value.len(); + + if start > str_len { + return OwnedValue::build_text(Rc::new("".to_string())); } let start_idx = start - 1; - let str_len = str.len(); let end = if *length != -1 { start_idx + *length as usize } else { str_len }; - let substring = &str[start_idx..end.min(str_len)]; + let substring = &str.value[start_idx..end.min(str_len)]; - OwnedValue::Text(Rc::new(substring.to_string())) + OwnedValue::build_text(Rc::new(substring.to_string())) } else if let (OwnedValue::Text(str), OwnedValue::Integer(start)) = (str_value, start_value) { let start = *start as usize; - if start > str.len() { - return OwnedValue::Text(Rc::new("".to_string())); + let str_len = str.value.len(); + + if start > str_len { + return OwnedValue::build_text(Rc::new("".to_string())); } let start_idx = start - 1; - let str_len = str.len(); - let substring = &str[start_idx..str_len]; + let substring = &str.value[start_idx..str_len]; - OwnedValue::Text(Rc::new(substring.to_string())) + OwnedValue::build_text(Rc::new(substring.to_string())) } else { OwnedValue::Null } @@ -3228,7 +3257,7 @@ fn exec_instr(reg: &OwnedValue, pattern: &OwnedValue) -> OwnedValue { let reg_str; let reg = match reg { - OwnedValue::Text(s) => s.as_str(), + OwnedValue::Text(s) => s.value.as_str(), _ => { reg_str = reg.to_string(); reg_str.as_str() @@ -3237,7 +3266,7 @@ fn exec_instr(reg: &OwnedValue, pattern: &OwnedValue) -> OwnedValue { let pattern_str; let pattern = match pattern { - OwnedValue::Text(s) => s.as_str(), + OwnedValue::Text(s) => s.value.as_str(), _ => { pattern_str = pattern.to_string(); pattern_str.as_str() @@ -3252,11 +3281,11 @@ fn exec_instr(reg: &OwnedValue, pattern: &OwnedValue) -> OwnedValue { fn exec_typeof(reg: &OwnedValue) -> OwnedValue { match reg { - OwnedValue::Null => OwnedValue::Text(Rc::new("null".to_string())), - OwnedValue::Integer(_) => OwnedValue::Text(Rc::new("integer".to_string())), - OwnedValue::Float(_) => OwnedValue::Text(Rc::new("real".to_string())), - OwnedValue::Text(_) => OwnedValue::Text(Rc::new("text".to_string())), - OwnedValue::Blob(_) => OwnedValue::Text(Rc::new("blob".to_string())), + OwnedValue::Null => OwnedValue::build_text(Rc::new("null".to_string())), + OwnedValue::Integer(_) => OwnedValue::build_text(Rc::new("integer".to_string())), + OwnedValue::Float(_) => OwnedValue::build_text(Rc::new("real".to_string())), + OwnedValue::Text(_) => OwnedValue::build_text(Rc::new("text".to_string())), + OwnedValue::Blob(_) => OwnedValue::build_text(Rc::new("blob".to_string())), OwnedValue::Agg(ctx) => exec_typeof(ctx.final_value()), OwnedValue::Record(_) => unimplemented!(), } @@ -3269,7 +3298,7 @@ fn exec_hex(reg: &OwnedValue) -> OwnedValue { | OwnedValue::Float(_) | OwnedValue::Blob(_) => { let text = reg.to_string(); - OwnedValue::Text(Rc::new(hex::encode_upper(text))) + OwnedValue::build_text(Rc::new(hex::encode_upper(text))) } _ => OwnedValue::Null, } @@ -3321,7 +3350,7 @@ fn exec_unicode(reg: &OwnedValue) -> OwnedValue { fn _to_float(reg: &OwnedValue) -> f64 { match reg { - OwnedValue::Text(x) => x.parse().unwrap_or(0.0), + OwnedValue::Text(x) => x.value.parse().unwrap_or(0.0), OwnedValue::Integer(x) => *x as f64, OwnedValue::Float(x) => *x, _ => 0.0, @@ -3330,7 +3359,7 @@ fn _to_float(reg: &OwnedValue) -> f64 { fn exec_round(reg: &OwnedValue, precision: Option) -> OwnedValue { let precision = match precision { - Some(OwnedValue::Text(x)) => x.parse().unwrap_or(0.0), + Some(OwnedValue::Text(x)) => x.value.parse().unwrap_or(0.0), Some(OwnedValue::Integer(x)) => x as f64, Some(OwnedValue::Float(x)) => x, Some(OwnedValue::Null) => return OwnedValue::Null, @@ -3353,13 +3382,13 @@ fn exec_trim(reg: &OwnedValue, pattern: Option) -> OwnedValue { (reg, Some(pattern)) => match reg { OwnedValue::Text(_) | OwnedValue::Integer(_) | OwnedValue::Float(_) => { let pattern_chars: Vec = pattern.to_string().chars().collect(); - OwnedValue::Text(Rc::new( + OwnedValue::build_text(Rc::new( reg.to_string().trim_matches(&pattern_chars[..]).to_string(), )) } _ => reg.to_owned(), }, - (OwnedValue::Text(t), None) => OwnedValue::Text(Rc::new(t.trim().to_string())), + (OwnedValue::Text(t), None) => OwnedValue::build_text(Rc::new(t.value.trim().to_string())), (reg, _) => reg.to_owned(), } } @@ -3370,7 +3399,7 @@ fn exec_ltrim(reg: &OwnedValue, pattern: Option) -> OwnedValue { (reg, Some(pattern)) => match reg { OwnedValue::Text(_) | OwnedValue::Integer(_) | OwnedValue::Float(_) => { let pattern_chars: Vec = pattern.to_string().chars().collect(); - OwnedValue::Text(Rc::new( + OwnedValue::build_text(Rc::new( reg.to_string() .trim_start_matches(&pattern_chars[..]) .to_string(), @@ -3378,7 +3407,9 @@ fn exec_ltrim(reg: &OwnedValue, pattern: Option) -> OwnedValue { } _ => reg.to_owned(), }, - (OwnedValue::Text(t), None) => OwnedValue::Text(Rc::new(t.trim_start().to_string())), + (OwnedValue::Text(t), None) => { + OwnedValue::build_text(Rc::new(t.value.trim_start().to_string())) + } (reg, _) => reg.to_owned(), } } @@ -3389,7 +3420,7 @@ fn exec_rtrim(reg: &OwnedValue, pattern: Option) -> OwnedValue { (reg, Some(pattern)) => match reg { OwnedValue::Text(_) | OwnedValue::Integer(_) | OwnedValue::Float(_) => { let pattern_chars: Vec = pattern.to_string().chars().collect(); - OwnedValue::Text(Rc::new( + OwnedValue::build_text(Rc::new( reg.to_string() .trim_end_matches(&pattern_chars[..]) .to_string(), @@ -3397,7 +3428,9 @@ fn exec_rtrim(reg: &OwnedValue, pattern: Option) -> OwnedValue { } _ => reg.to_owned(), }, - (OwnedValue::Text(t), None) => OwnedValue::Text(Rc::new(t.trim_end().to_string())), + (OwnedValue::Text(t), None) => { + OwnedValue::build_text(Rc::new(t.value.trim_end().to_string())) + } (reg, _) => reg.to_owned(), } } @@ -3406,7 +3439,7 @@ fn exec_zeroblob(req: &OwnedValue) -> OwnedValue { let length: i64 = match req { OwnedValue::Integer(i) => *i, OwnedValue::Float(f) => *f as i64, - OwnedValue::Text(s) => s.parse().unwrap_or(0), + OwnedValue::Text(s) => s.value.parse().unwrap_or(0), _ => 0, }; OwnedValue::Blob(Rc::new(vec![0; length.max(0) as usize])) @@ -3444,7 +3477,7 @@ fn exec_cast(value: &OwnedValue, datatype: &str) -> OwnedValue { Affinity::Text => { // Convert everything to text representation // TODO: handle encoding and whatever sqlite3_snprintf does - OwnedValue::Text(Rc::new(value.to_string())) + OwnedValue::build_text(Rc::new(value.to_string())) } Affinity::Real => match value { OwnedValue::Blob(b) => { @@ -3452,7 +3485,7 @@ fn exec_cast(value: &OwnedValue, datatype: &str) -> OwnedValue { let text = String::from_utf8_lossy(b); cast_text_to_real(&text) } - OwnedValue::Text(t) => cast_text_to_real(t), + OwnedValue::Text(t) => cast_text_to_real(&t.value), OwnedValue::Integer(i) => OwnedValue::Float(*i as f64), OwnedValue::Float(f) => OwnedValue::Float(*f), _ => OwnedValue::Float(0.0), @@ -3463,7 +3496,7 @@ fn exec_cast(value: &OwnedValue, datatype: &str) -> OwnedValue { let text = String::from_utf8_lossy(b); cast_text_to_integer(&text) } - OwnedValue::Text(t) => cast_text_to_integer(t), + OwnedValue::Text(t) => cast_text_to_integer(&t.value), OwnedValue::Integer(i) => OwnedValue::Integer(*i), // A cast of a REAL value into an INTEGER results in the integer between the REAL value and zero // that is closest to the REAL value. If a REAL is greater than the greatest possible signed integer (+9223372036854775807) @@ -3486,7 +3519,7 @@ fn exec_cast(value: &OwnedValue, datatype: &str) -> OwnedValue { let text = String::from_utf8_lossy(b); cast_text_to_numeric(&text) } - OwnedValue::Text(t) => cast_text_to_numeric(t), + OwnedValue::Text(t) => cast_text_to_numeric(&t.value), OwnedValue::Integer(i) => OwnedValue::Integer(*i), OwnedValue::Float(f) => OwnedValue::Float(*f), _ => value.clone(), // TODO probably wrong @@ -3514,12 +3547,14 @@ fn exec_replace(source: &OwnedValue, pattern: &OwnedValue, replacement: &OwnedVa // If any of the casts failed, panic as text casting is not expected to fail. match (&source, &pattern, &replacement) { (OwnedValue::Text(source), OwnedValue::Text(pattern), OwnedValue::Text(replacement)) => { - if pattern.is_empty() { - return OwnedValue::Text(source.clone()); + if pattern.value.is_empty() { + return OwnedValue::build_text(source.value.clone()); } - let result = source.replace(pattern.as_str(), replacement); - OwnedValue::Text(Rc::new(result)) + let result = source + .value + .replace(pattern.value.as_str(), &replacement.value); + OwnedValue::build_text(Rc::new(result)) } _ => unreachable!("text cast should never fail"), } @@ -3653,7 +3688,7 @@ fn to_f64(reg: &OwnedValue) -> Option { match reg { OwnedValue::Integer(i) => Some(*i as f64), OwnedValue::Float(f) => Some(*f), - OwnedValue::Text(t) => t.parse::().ok(), + OwnedValue::Text(t) => t.value.parse::().ok(), OwnedValue::Agg(ctx) => to_f64(ctx.final_value()), _ => None, } @@ -3928,7 +3963,7 @@ mod tests { #[test] fn test_length() { - let input_str = OwnedValue::Text(Rc::new(String::from("bob"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bob"))); let expected_len = OwnedValue::Integer(3); assert_eq!(exec_length(&input_str), expected_len); @@ -3947,58 +3982,58 @@ mod tests { #[test] fn test_quote() { - let input = OwnedValue::Text(Rc::new(String::from("abc\0edf"))); - let expected = OwnedValue::Text(Rc::new(String::from("'abc'"))); + let input = OwnedValue::build_text(Rc::new(String::from("abc\0edf"))); + let expected = OwnedValue::build_text(Rc::new(String::from("'abc'"))); assert_eq!(exec_quote(&input), expected); let input = OwnedValue::Integer(123); let expected = OwnedValue::Integer(123); assert_eq!(exec_quote(&input), expected); - let input = OwnedValue::Text(Rc::new(String::from("hello''world"))); - let expected = OwnedValue::Text(Rc::new(String::from("'hello''world'"))); + let input = OwnedValue::build_text(Rc::new(String::from("hello''world"))); + let expected = OwnedValue::build_text(Rc::new(String::from("'hello''world'"))); assert_eq!(exec_quote(&input), expected); } #[test] fn test_typeof() { let input = OwnedValue::Null; - let expected: OwnedValue = OwnedValue::Text(Rc::new("null".to_string())); + let expected: OwnedValue = OwnedValue::build_text(Rc::new("null".to_string())); assert_eq!(exec_typeof(&input), expected); let input = OwnedValue::Integer(123); - let expected: OwnedValue = OwnedValue::Text(Rc::new("integer".to_string())); + let expected: OwnedValue = OwnedValue::build_text(Rc::new("integer".to_string())); assert_eq!(exec_typeof(&input), expected); let input = OwnedValue::Float(123.456); - let expected: OwnedValue = OwnedValue::Text(Rc::new("real".to_string())); + let expected: OwnedValue = OwnedValue::build_text(Rc::new("real".to_string())); assert_eq!(exec_typeof(&input), expected); - let input = OwnedValue::Text(Rc::new("hello".to_string())); - let expected: OwnedValue = OwnedValue::Text(Rc::new("text".to_string())); + let input = OwnedValue::build_text(Rc::new("hello".to_string())); + let expected: OwnedValue = OwnedValue::build_text(Rc::new("text".to_string())); assert_eq!(exec_typeof(&input), expected); let input = OwnedValue::Blob(Rc::new("limbo".as_bytes().to_vec())); - let expected: OwnedValue = OwnedValue::Text(Rc::new("blob".to_string())); + let expected: OwnedValue = OwnedValue::build_text(Rc::new("blob".to_string())); assert_eq!(exec_typeof(&input), expected); let input = OwnedValue::Agg(Box::new(AggContext::Sum(OwnedValue::Integer(123)))); - let expected = OwnedValue::Text(Rc::new("integer".to_string())); + let expected = OwnedValue::build_text(Rc::new("integer".to_string())); assert_eq!(exec_typeof(&input), expected); } #[test] fn test_unicode() { assert_eq!( - exec_unicode(&OwnedValue::Text(Rc::new("a".to_string()))), + exec_unicode(&OwnedValue::build_text(Rc::new("a".to_string()))), OwnedValue::Integer(97) ); assert_eq!( - exec_unicode(&OwnedValue::Text(Rc::new("😊".to_string()))), + exec_unicode(&OwnedValue::build_text(Rc::new("😊".to_string()))), OwnedValue::Integer(128522) ); assert_eq!( - exec_unicode(&OwnedValue::Text(Rc::new("".to_string()))), + exec_unicode(&OwnedValue::build_text(Rc::new("".to_string()))), OwnedValue::Null ); assert_eq!( @@ -4030,16 +4065,16 @@ mod tests { assert_eq!(exec_min(input_int_vec.clone()), OwnedValue::Integer(-1)); assert_eq!(exec_max(input_int_vec.clone()), OwnedValue::Integer(10)); - let str1 = OwnedValue::Text(Rc::new(String::from("A"))); - let str2 = OwnedValue::Text(Rc::new(String::from("z"))); + let str1 = OwnedValue::build_text(Rc::new(String::from("A"))); + let str2 = OwnedValue::build_text(Rc::new(String::from("z"))); let input_str_vec = vec![&str2, &str1]; assert_eq!( exec_min(input_str_vec.clone()), - OwnedValue::Text(Rc::new(String::from("A"))) + OwnedValue::build_text(Rc::new(String::from("A"))) ); assert_eq!( exec_max(input_str_vec.clone()), - OwnedValue::Text(Rc::new(String::from("z"))) + OwnedValue::build_text(Rc::new(String::from("z"))) ); let input_null_vec = vec![&OwnedValue::Null, &OwnedValue::Null]; @@ -4050,102 +4085,102 @@ mod tests { assert_eq!(exec_min(input_mixed_vec.clone()), OwnedValue::Integer(10)); assert_eq!( exec_max(input_mixed_vec.clone()), - OwnedValue::Text(Rc::new(String::from("A"))) + OwnedValue::build_text(Rc::new(String::from("A"))) ); } #[test] fn test_trim() { - let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice "))); - let expected_str = OwnedValue::Text(Rc::new(String::from("Bob and Alice"))); + let input_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice "))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("Bob and Alice"))); assert_eq!(exec_trim(&input_str, None), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice "))); - let pattern_str = OwnedValue::Text(Rc::new(String::from("Bob and"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("Alice"))); + let input_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice "))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from("Bob and"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("Alice"))); assert_eq!(exec_trim(&input_str, Some(pattern_str)), expected_str); } #[test] fn test_ltrim() { - let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice "))); - let expected_str = OwnedValue::Text(Rc::new(String::from("Bob and Alice "))); + let input_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice "))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("Bob and Alice "))); assert_eq!(exec_ltrim(&input_str, None), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice "))); - let pattern_str = OwnedValue::Text(Rc::new(String::from("Bob and"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("Alice "))); + let input_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice "))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from("Bob and"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("Alice "))); assert_eq!(exec_ltrim(&input_str, Some(pattern_str)), expected_str); } #[test] fn test_rtrim() { - let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice "))); - let expected_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice"))); + let input_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice "))); + let expected_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice"))); assert_eq!(exec_rtrim(&input_str, None), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice "))); - let pattern_str = OwnedValue::Text(Rc::new(String::from("Bob and"))); - let expected_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice"))); + let input_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice "))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from("Bob and"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice"))); assert_eq!(exec_rtrim(&input_str, Some(pattern_str)), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice "))); - let pattern_str = OwnedValue::Text(Rc::new(String::from("and Alice"))); - let expected_str = OwnedValue::Text(Rc::new(String::from(" Bob"))); + let input_str = OwnedValue::build_text(Rc::new(String::from(" Bob and Alice "))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from("and Alice"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from(" Bob"))); assert_eq!(exec_rtrim(&input_str, Some(pattern_str)), expected_str); } #[test] fn test_soundex() { - let input_str = OwnedValue::Text(Rc::new(String::from("Pfister"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("P236"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Pfister"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("P236"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("husobee"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("H210"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("husobee"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("H210"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("Tymczak"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("T522"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Tymczak"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("T522"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("Ashcraft"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("A261"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Ashcraft"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("A261"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("Robert"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("R163"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Robert"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("R163"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("Rupert"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("R163"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Rupert"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("R163"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("Rubin"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("R150"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Rubin"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("R150"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("Kant"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("K530"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Kant"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("K530"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("Knuth"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("K530"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Knuth"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("K530"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("x"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("X000"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("x"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("X000"))); assert_eq!(exec_soundex(&input_str), expected_str); - let input_str = OwnedValue::Text(Rc::new(String::from("闪电五连鞭"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("?000"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("闪电五连鞭"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("?000"))); assert_eq!(exec_soundex(&input_str), expected_str); } #[test] fn test_upper_case() { - let input_str = OwnedValue::Text(Rc::new(String::from("Limbo"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("LIMBO"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Limbo"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("LIMBO"))); assert_eq!(exec_upper(&input_str).unwrap(), expected_str); let input_int = OwnedValue::Integer(10); @@ -4155,8 +4190,8 @@ mod tests { #[test] fn test_lower_case() { - let input_str = OwnedValue::Text(Rc::new(String::from("Limbo"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("limbo"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("Limbo"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("limbo"))); assert_eq!(exec_lower(&input_str).unwrap(), expected_str); let input_int = OwnedValue::Integer(10); @@ -4166,38 +4201,38 @@ mod tests { #[test] fn test_hex() { - let input_str = OwnedValue::Text(Rc::new("limbo".to_string())); - let expected_val = OwnedValue::Text(Rc::new(String::from("6C696D626F"))); + let input_str = OwnedValue::build_text(Rc::new("limbo".to_string())); + let expected_val = OwnedValue::build_text(Rc::new(String::from("6C696D626F"))); assert_eq!(exec_hex(&input_str), expected_val); let input_int = OwnedValue::Integer(100); - let expected_val = OwnedValue::Text(Rc::new(String::from("313030"))); + let expected_val = OwnedValue::build_text(Rc::new(String::from("313030"))); assert_eq!(exec_hex(&input_int), expected_val); let input_float = OwnedValue::Float(12.34); - let expected_val = OwnedValue::Text(Rc::new(String::from("31322E3334"))); + let expected_val = OwnedValue::build_text(Rc::new(String::from("31322E3334"))); assert_eq!(exec_hex(&input_float), expected_val); } #[test] fn test_unhex() { - let input = OwnedValue::Text(Rc::new(String::from("6F"))); + let input = OwnedValue::build_text(Rc::new(String::from("6F"))); let expected = OwnedValue::Blob(Rc::new(vec![0x6f])); assert_eq!(exec_unhex(&input, None), expected); - let input = OwnedValue::Text(Rc::new(String::from("6f"))); + let input = OwnedValue::build_text(Rc::new(String::from("6f"))); let expected = OwnedValue::Blob(Rc::new(vec![0x6f])); assert_eq!(exec_unhex(&input, None), expected); - let input = OwnedValue::Text(Rc::new(String::from("611"))); + let input = OwnedValue::build_text(Rc::new(String::from("611"))); let expected = OwnedValue::Null; assert_eq!(exec_unhex(&input, None), expected); - let input = OwnedValue::Text(Rc::new(String::from(""))); + let input = OwnedValue::build_text(Rc::new(String::from(""))); let expected = OwnedValue::Blob(Rc::new(vec![])); assert_eq!(exec_unhex(&input, None), expected); - let input = OwnedValue::Text(Rc::new(String::from("61x"))); + let input = OwnedValue::build_text(Rc::new(String::from("61x"))); let expected = OwnedValue::Null; assert_eq!(exec_unhex(&input, None), expected); @@ -4219,7 +4254,7 @@ mod tests { assert_eq!(exec_abs(&float_negative_reg).unwrap(), float_positive_reg); assert_eq!( - exec_abs(&OwnedValue::Text(Rc::new(String::from("a")))).unwrap(), + exec_abs(&OwnedValue::build_text(Rc::new(String::from("a")))).unwrap(), OwnedValue::Float(0.0) ); assert_eq!(exec_abs(&OwnedValue::Null).unwrap(), OwnedValue::Null); @@ -4229,16 +4264,19 @@ mod tests { fn test_char() { assert_eq!( exec_char(vec![OwnedValue::Integer(108), OwnedValue::Integer(105)]), - OwnedValue::Text(Rc::new("li".to_string())) + OwnedValue::build_text(Rc::new("li".to_string())) + ); + assert_eq!( + exec_char(vec![]), + OwnedValue::build_text(Rc::new("".to_string())) ); - assert_eq!(exec_char(vec![]), OwnedValue::Text(Rc::new("".to_string()))); assert_eq!( exec_char(vec![OwnedValue::Null]), - OwnedValue::Text(Rc::new("".to_string())) + OwnedValue::build_text(Rc::new("".to_string())) ); assert_eq!( - exec_char(vec![OwnedValue::Text(Rc::new("a".to_string()))]), - OwnedValue::Text(Rc::new("".to_string())) + exec_char(vec![OwnedValue::build_text(Rc::new("a".to_string()))]), + OwnedValue::build_text(Rc::new("".to_string())) ); } @@ -4303,19 +4341,19 @@ mod tests { expected_len: 1, }, TestCase { - input: OwnedValue::Text(Rc::new(String::from(""))), + input: OwnedValue::build_text(Rc::new(String::from(""))), expected_len: 1, }, TestCase { - input: OwnedValue::Text(Rc::new(String::from("5"))), + input: OwnedValue::build_text(Rc::new(String::from("5"))), expected_len: 5, }, TestCase { - input: OwnedValue::Text(Rc::new(String::from("0"))), + input: OwnedValue::build_text(Rc::new(String::from("0"))), expected_len: 1, }, TestCase { - input: OwnedValue::Text(Rc::new(String::from("-1"))), + input: OwnedValue::build_text(Rc::new(String::from("-1"))), expected_len: 1, }, TestCase { @@ -4355,11 +4393,11 @@ mod tests { assert_eq!(exec_round(&input_val, Some(precision_val)), expected_val); let input_val = OwnedValue::Float(123.456); - let precision_val = OwnedValue::Text(Rc::new(String::from("1"))); + let precision_val = OwnedValue::build_text(Rc::new(String::from("1"))); let expected_val = OwnedValue::Float(123.5); assert_eq!(exec_round(&input_val, Some(precision_val)), expected_val); - let input_val = OwnedValue::Text(Rc::new(String::from("123.456"))); + let input_val = OwnedValue::build_text(Rc::new(String::from("123.456"))); let precision_val = OwnedValue::Integer(2); let expected_val = OwnedValue::Float(123.46); assert_eq!(exec_round(&input_val, Some(precision_val)), expected_val); @@ -4418,8 +4456,8 @@ mod tests { ); assert_eq!( exec_nullif( - &OwnedValue::Text(Rc::new("limbo".to_string())), - &OwnedValue::Text(Rc::new("limbo".to_string())) + &OwnedValue::build_text(Rc::new("limbo".to_string())), + &OwnedValue::build_text(Rc::new("limbo".to_string())) ), OwnedValue::Null ); @@ -4434,55 +4472,55 @@ mod tests { ); assert_eq!( exec_nullif( - &OwnedValue::Text(Rc::new("limbo".to_string())), - &OwnedValue::Text(Rc::new("limb".to_string())) + &OwnedValue::build_text(Rc::new("limbo".to_string())), + &OwnedValue::build_text(Rc::new("limb".to_string())) ), - OwnedValue::Text(Rc::new("limbo".to_string())) + OwnedValue::build_text(Rc::new("limbo".to_string())) ); } #[test] fn test_substring() { - let str_value = OwnedValue::Text(Rc::new("limbo".to_string())); + let str_value = OwnedValue::build_text(Rc::new("limbo".to_string())); let start_value = OwnedValue::Integer(1); let length_value = OwnedValue::Integer(3); - let expected_val = OwnedValue::Text(Rc::new(String::from("lim"))); + let expected_val = OwnedValue::build_text(Rc::new(String::from("lim"))); assert_eq!( exec_substring(&str_value, &start_value, &length_value), expected_val ); - let str_value = OwnedValue::Text(Rc::new("limbo".to_string())); + let str_value = OwnedValue::build_text(Rc::new("limbo".to_string())); let start_value = OwnedValue::Integer(1); let length_value = OwnedValue::Integer(10); - let expected_val = OwnedValue::Text(Rc::new(String::from("limbo"))); + let expected_val = OwnedValue::build_text(Rc::new(String::from("limbo"))); assert_eq!( exec_substring(&str_value, &start_value, &length_value), expected_val ); - let str_value = OwnedValue::Text(Rc::new("limbo".to_string())); + let str_value = OwnedValue::build_text(Rc::new("limbo".to_string())); let start_value = OwnedValue::Integer(10); let length_value = OwnedValue::Integer(3); - let expected_val = OwnedValue::Text(Rc::new(String::from(""))); + let expected_val = OwnedValue::build_text(Rc::new(String::from(""))); assert_eq!( exec_substring(&str_value, &start_value, &length_value), expected_val ); - let str_value = OwnedValue::Text(Rc::new("limbo".to_string())); + let str_value = OwnedValue::build_text(Rc::new("limbo".to_string())); let start_value = OwnedValue::Integer(3); let length_value = OwnedValue::Null; - let expected_val = OwnedValue::Text(Rc::new(String::from("mbo"))); + let expected_val = OwnedValue::build_text(Rc::new(String::from("mbo"))); assert_eq!( exec_substring(&str_value, &start_value, &length_value), expected_val ); - let str_value = OwnedValue::Text(Rc::new("limbo".to_string())); + let str_value = OwnedValue::build_text(Rc::new("limbo".to_string())); let start_value = OwnedValue::Integer(10); let length_value = OwnedValue::Null; - let expected_val = OwnedValue::Text(Rc::new(String::from(""))); + let expected_val = OwnedValue::build_text(Rc::new(String::from(""))); assert_eq!( exec_substring(&str_value, &start_value, &length_value), expected_val @@ -4491,43 +4529,43 @@ mod tests { #[test] fn test_exec_instr() { - let input = OwnedValue::Text(Rc::new(String::from("limbo"))); - let pattern = OwnedValue::Text(Rc::new(String::from("im"))); + let input = OwnedValue::build_text(Rc::new(String::from("limbo"))); + let pattern = OwnedValue::build_text(Rc::new(String::from("im"))); let expected = OwnedValue::Integer(2); assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from("limbo"))); - let pattern = OwnedValue::Text(Rc::new(String::from("limbo"))); + let input = OwnedValue::build_text(Rc::new(String::from("limbo"))); + let pattern = OwnedValue::build_text(Rc::new(String::from("limbo"))); let expected = OwnedValue::Integer(1); assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from("limbo"))); - let pattern = OwnedValue::Text(Rc::new(String::from("o"))); + let input = OwnedValue::build_text(Rc::new(String::from("limbo"))); + let pattern = OwnedValue::build_text(Rc::new(String::from("o"))); let expected = OwnedValue::Integer(5); assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from("liiiiimbo"))); - let pattern = OwnedValue::Text(Rc::new(String::from("ii"))); + let input = OwnedValue::build_text(Rc::new(String::from("liiiiimbo"))); + let pattern = OwnedValue::build_text(Rc::new(String::from("ii"))); let expected = OwnedValue::Integer(2); assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from("limbo"))); - let pattern = OwnedValue::Text(Rc::new(String::from("limboX"))); + let input = OwnedValue::build_text(Rc::new(String::from("limbo"))); + let pattern = OwnedValue::build_text(Rc::new(String::from("limboX"))); let expected = OwnedValue::Integer(0); assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from("limbo"))); - let pattern = OwnedValue::Text(Rc::new(String::from(""))); + let input = OwnedValue::build_text(Rc::new(String::from("limbo"))); + let pattern = OwnedValue::build_text(Rc::new(String::from(""))); let expected = OwnedValue::Integer(1); assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from(""))); - let pattern = OwnedValue::Text(Rc::new(String::from("limbo"))); + let input = OwnedValue::build_text(Rc::new(String::from(""))); + let pattern = OwnedValue::build_text(Rc::new(String::from("limbo"))); let expected = OwnedValue::Integer(0); assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from(""))); - let pattern = OwnedValue::Text(Rc::new(String::from(""))); + let input = OwnedValue::build_text(Rc::new(String::from(""))); + let pattern = OwnedValue::build_text(Rc::new(String::from(""))); let expected = OwnedValue::Integer(1); assert_eq!(exec_instr(&input, &pattern), expected); @@ -4536,13 +4574,13 @@ mod tests { let expected = OwnedValue::Null; assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from("limbo"))); + let input = OwnedValue::build_text(Rc::new(String::from("limbo"))); let pattern = OwnedValue::Null; let expected = OwnedValue::Null; assert_eq!(exec_instr(&input, &pattern), expected); let input = OwnedValue::Null; - let pattern = OwnedValue::Text(Rc::new(String::from("limbo"))); + let pattern = OwnedValue::build_text(Rc::new(String::from("limbo"))); let expected = OwnedValue::Null; assert_eq!(exec_instr(&input, &pattern), expected); @@ -4567,7 +4605,7 @@ mod tests { assert_eq!(exec_instr(&input, &pattern), expected); let input = OwnedValue::Float(12.34); - let pattern = OwnedValue::Text(Rc::new(String::from("."))); + let pattern = OwnedValue::build_text(Rc::new(String::from("."))); let expected = OwnedValue::Integer(3); assert_eq!(exec_instr(&input, &pattern), expected); @@ -4582,11 +4620,11 @@ mod tests { assert_eq!(exec_instr(&input, &pattern), expected); let input = OwnedValue::Blob(Rc::new(vec![0x61, 0x62, 0x63, 0x64, 0x65])); - let pattern = OwnedValue::Text(Rc::new(String::from("cd"))); + let pattern = OwnedValue::build_text(Rc::new(String::from("cd"))); let expected = OwnedValue::Integer(3); assert_eq!(exec_instr(&input, &pattern), expected); - let input = OwnedValue::Text(Rc::new(String::from("abcde"))); + let input = OwnedValue::build_text(Rc::new(String::from("abcde"))); let pattern = OwnedValue::Blob(Rc::new(vec![0x63, 0x64])); let expected = OwnedValue::Integer(3); assert_eq!(exec_instr(&input, &pattern), expected); @@ -4622,19 +4660,19 @@ mod tests { let expected = Some(OwnedValue::Integer(-1)); assert_eq!(exec_sign(&input), expected); - let input = OwnedValue::Text(Rc::new("abc".to_string())); + let input = OwnedValue::build_text(Rc::new("abc".to_string())); let expected = Some(OwnedValue::Null); assert_eq!(exec_sign(&input), expected); - let input = OwnedValue::Text(Rc::new("42".to_string())); + let input = OwnedValue::build_text(Rc::new("42".to_string())); let expected = Some(OwnedValue::Integer(1)); assert_eq!(exec_sign(&input), expected); - let input = OwnedValue::Text(Rc::new("-42".to_string())); + let input = OwnedValue::build_text(Rc::new("-42".to_string())); let expected = Some(OwnedValue::Integer(-1)); assert_eq!(exec_sign(&input), expected); - let input = OwnedValue::Text(Rc::new("0".to_string())); + let input = OwnedValue::build_text(Rc::new("0".to_string())); let expected = Some(OwnedValue::Integer(0)); assert_eq!(exec_sign(&input), expected); @@ -4677,15 +4715,15 @@ mod tests { let expected = OwnedValue::Blob(Rc::new(vec![])); assert_eq!(exec_zeroblob(&input), expected); - let input = OwnedValue::Text(Rc::new("5".to_string())); + let input = OwnedValue::build_text(Rc::new("5".to_string())); let expected = OwnedValue::Blob(Rc::new(vec![0; 5])); assert_eq!(exec_zeroblob(&input), expected); - let input = OwnedValue::Text(Rc::new("-5".to_string())); + let input = OwnedValue::build_text(Rc::new("-5".to_string())); let expected = OwnedValue::Blob(Rc::new(vec![])); assert_eq!(exec_zeroblob(&input), expected); - let input = OwnedValue::Text(Rc::new("text".to_string())); + let input = OwnedValue::build_text(Rc::new("text".to_string())); let expected = OwnedValue::Blob(Rc::new(vec![])); assert_eq!(exec_zeroblob(&input), expected); @@ -4707,101 +4745,101 @@ mod tests { #[test] fn test_replace() { - let input_str = OwnedValue::Text(Rc::new(String::from("bob"))); - let pattern_str = OwnedValue::Text(Rc::new(String::from("b"))); - let replace_str = OwnedValue::Text(Rc::new(String::from("a"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("aoa"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bob"))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from("b"))); + let replace_str = OwnedValue::build_text(Rc::new(String::from("a"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("aoa"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bob"))); - let pattern_str = OwnedValue::Text(Rc::new(String::from("b"))); - let replace_str = OwnedValue::Text(Rc::new(String::from(""))); - let expected_str = OwnedValue::Text(Rc::new(String::from("o"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bob"))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from("b"))); + let replace_str = OwnedValue::build_text(Rc::new(String::from(""))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("o"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bob"))); - let pattern_str = OwnedValue::Text(Rc::new(String::from("b"))); - let replace_str = OwnedValue::Text(Rc::new(String::from("abc"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("abcoabc"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bob"))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from("b"))); + let replace_str = OwnedValue::build_text(Rc::new(String::from("abc"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("abcoabc"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bob"))); - let pattern_str = OwnedValue::Text(Rc::new(String::from("a"))); - let replace_str = OwnedValue::Text(Rc::new(String::from("b"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("bob"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bob"))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from("a"))); + let replace_str = OwnedValue::build_text(Rc::new(String::from("b"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("bob"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bob"))); - let pattern_str = OwnedValue::Text(Rc::new(String::from(""))); - let replace_str = OwnedValue::Text(Rc::new(String::from("a"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("bob"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bob"))); + let pattern_str = OwnedValue::build_text(Rc::new(String::from(""))); + let replace_str = OwnedValue::build_text(Rc::new(String::from("a"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("bob"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bob"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bob"))); let pattern_str = OwnedValue::Null; - let replace_str = OwnedValue::Text(Rc::new(String::from("a"))); + let replace_str = OwnedValue::build_text(Rc::new(String::from("a"))); let expected_str = OwnedValue::Null; assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bo5"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bo5"))); let pattern_str = OwnedValue::Integer(5); - let replace_str = OwnedValue::Text(Rc::new(String::from("a"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("boa"))); + let replace_str = OwnedValue::build_text(Rc::new(String::from("a"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("boa"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bo5.0"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bo5.0"))); let pattern_str = OwnedValue::Float(5.0); - let replace_str = OwnedValue::Text(Rc::new(String::from("a"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("boa"))); + let replace_str = OwnedValue::build_text(Rc::new(String::from("a"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("boa"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bo5"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bo5"))); let pattern_str = OwnedValue::Float(5.0); - let replace_str = OwnedValue::Text(Rc::new(String::from("a"))); - let expected_str = OwnedValue::Text(Rc::new(String::from("bo5"))); + let replace_str = OwnedValue::build_text(Rc::new(String::from("a"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("bo5"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); - let input_str = OwnedValue::Text(Rc::new(String::from("bo5.0"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("bo5.0"))); let pattern_str = OwnedValue::Float(5.0); let replace_str = OwnedValue::Float(6.0); - let expected_str = OwnedValue::Text(Rc::new(String::from("bo6.0"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("bo6.0"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str ); // todo: change this test to use (0.1 + 0.2) instead of 0.3 when decimals are implemented. - let input_str = OwnedValue::Text(Rc::new(String::from("tes3"))); + let input_str = OwnedValue::build_text(Rc::new(String::from("tes3"))); let pattern_str = OwnedValue::Integer(3); let replace_str = OwnedValue::Agg(Box::new(AggContext::Sum(OwnedValue::Float(0.3)))); - let expected_str = OwnedValue::Text(Rc::new(String::from("tes0.3"))); + let expected_str = OwnedValue::build_text(Rc::new(String::from("tes0.3"))); assert_eq!( exec_replace(&input_str, &pattern_str, &replace_str), expected_str diff --git a/testing/json.test b/testing/json.test old mode 100644 new mode 100755 index 6f566fa05..3b839f3c9 --- a/testing/json.test +++ b/testing/json.test @@ -55,3 +55,15 @@ do_execsql_test json5-multi-comment { SELECT json(' /* abc */ { /*def*/ aaa /* xyz */ : // to the end of line 123 /* xyz */ , /* 123 */ }') } {{{"aaa":123}}} + +do_execsql_test json_array_str { + SELECT json_array('a') +} {{["a"]}} + +do_execsql_test json_array_not_json { + SELECT json_array('{"a":1}'); +} {{["{\"a\":1}"]}} + +do_execsql_test json_array_json { + SELECT json_array(json('{"a":1}')); +} {{[{"a":1}]}}