Implement json_array

This commit is contained in:
Kacper Madej
2024-12-18 02:11:25 +01:00
parent 94d69c5a4e
commit 19ae42dfa3
9 changed files with 717 additions and 503 deletions

View File

@@ -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)),

View File

@@ -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<OwnedValue> {
match json_value {
OwnedValue::Text(ref t) => match crate::json::from_str::<Val>(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::<Val>(&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<OwnedValue> {
}
}
pub fn json_array(values: Vec<OwnedValue>) -> crate::Result<OwnedValue> {
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")),
}
}
}

View File

@@ -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,

View File

@@ -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<Vec<ast::Expr>>,
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,

View File

@@ -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<String>,
pub subtype: TextSubtype,
}
impl LimboText {
pub fn new(value: Rc<String>) -> Self {
Self {
value,
subtype: TextSubtype::Text,
}
}
pub fn json(value: Rc<String>) -> Self {
Self {
value,
subtype: TextSubtype::Json,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum OwnedValue {
Null,
Integer(i64),
Float(f64),
Text(Rc<String>),
Text(LimboText),
Blob(Rc<Vec<u8>>),
Agg(Box<AggContext>), // 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<String>) -> 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<OwnedValue> 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<OwnedValue> 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!(),

View File

@@ -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<NaiveDateTime> {
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

View File

@@ -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),
),
@@ -226,7 +227,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),
),
@@ -239,7 +240,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(),
),

File diff suppressed because it is too large Load Diff