diff --git a/core/json/cache.rs b/core/json/cache.rs index 0231183d9..c9542833c 100644 --- a/core/json/cache.rs +++ b/core/json/cache.rs @@ -1,6 +1,7 @@ use std::cell::{Cell, UnsafeCell}; -use crate::Value; +use crate::types::AsValueRef; +use crate::{Value, ValueRef}; use super::jsonb::Jsonb; @@ -38,25 +39,27 @@ impl JsonCache { oldest_idx } - pub fn insert(&mut self, key: &Value, value: &Jsonb) { + pub fn insert(&mut self, key: impl AsValueRef, value: &Jsonb) { + let key = key.as_value_ref(); if self.used < JSON_CACHE_SIZE { - self.entries[self.used] = Some((key.clone(), value.clone())); + self.entries[self.used] = Some((key.to_owned(), value.clone())); self.age[self.used] = self.counter; self.counter += 1; self.used += 1 } else { let id = self.find_oldest_entry(); - self.entries[id] = Some((key.clone(), value.clone())); + self.entries[id] = Some((key.to_owned(), value.clone())); self.age[id] = self.counter; self.counter += 1; } } - pub fn lookup(&mut self, key: &Value) -> Option { + pub fn lookup(&mut self, key: impl AsValueRef) -> Option { + let key = key.as_value_ref(); for i in (0..self.used).rev() { if let Some((stored_key, value)) = &self.entries[i] { - if key == stored_key { + if key == *stored_key { self.age[i] = self.counter; self.counter += 1; let json = value.clone(); @@ -89,7 +92,7 @@ impl JsonCacheCell { } #[cfg(test)] - pub fn lookup(&self, key: &Value) -> Option { + pub fn lookup(&self, key: impl AsValueRef) -> Option { assert!(!self.accessed.get()); self.accessed.set(true); @@ -113,11 +116,12 @@ impl JsonCacheCell { pub fn get_or_insert_with( &self, - key: &Value, - value: impl Fn(&Value) -> crate::Result, + key: impl AsValueRef, + value: impl FnOnce(ValueRef) -> crate::Result, ) -> crate::Result { assert!(!self.accessed.get()); + let key = key.as_value_ref(); self.accessed.set(true); let result = unsafe { let cache_ptr = self.inner.get(); @@ -354,7 +358,7 @@ mod tests { // Insert the value using get_or_insert_with let insert_result = cache_cell.get_or_insert_with(&key, |k| { // Verify that k is the same as our key - assert_eq!(k, &key); + assert_eq!(k, key); Ok(value.clone()) }); diff --git a/core/json/mod.rs b/core/json/mod.rs index a1825d3f6..9a7948ca4 100644 --- a/core/json/mod.rs +++ b/core/json/mod.rs @@ -11,8 +11,7 @@ pub use crate::json::ops::{ jsonb_replace, }; use crate::json::path::{json_path, JsonPath, PathElement}; -use crate::types::{Text, TextRef, TextSubtype, Value, ValueType}; -use crate::vdbe::Register; +use crate::types::{AsValueRef, Text, TextSubtype, Value, ValueType}; use crate::{bail_constraint_error, bail_parse_error, LimboError, ValueRef}; pub use cache::JsonCacheCell; use jsonb::{ElementType, Jsonb, JsonbHeader, PathOperationMode, SearchOperation, SetOperation}; @@ -100,17 +99,9 @@ pub fn json_from_raw_bytes_agg(data: &[u8], raw: bool) -> crate::Result { } } -pub fn convert_dbtype_to_jsonb(val: &Value, strict: Conv) -> crate::Result { - convert_ref_dbtype_to_jsonb( - match val { - Value::Null => ValueRef::Null, - Value::Integer(x) => ValueRef::Integer(*x), - Value::Float(x) => ValueRef::Float(*x), - Value::Text(text) => ValueRef::Text(TextRef::new(text.as_str(), text.subtype)), - Value::Blob(items) => ValueRef::Blob(items.as_slice()), - }, - strict, - ) +pub fn convert_dbtype_to_jsonb(val: impl AsValueRef, strict: Conv) -> crate::Result { + let val = val.as_value_ref(); + convert_ref_dbtype_to_jsonb(val, strict) } fn parse_as_json_text(slice: &[u8], mode: Conv) -> crate::Result { @@ -187,18 +178,27 @@ pub fn convert_ref_dbtype_to_jsonb(val: ValueRef<'_>, strict: Conv) -> crate::Re } } -pub fn curry_convert_dbtype_to_jsonb(strict: Conv) -> impl Fn(&Value) -> crate::Result { +pub fn curry_convert_dbtype_to_jsonb( + strict: Conv, +) -> impl FnOnce(ValueRef) -> crate::Result { move |val| convert_dbtype_to_jsonb(val, strict) } -pub fn json_array(values: &[Register]) -> crate::Result { +pub fn json_array(values: I) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let values = values.into_iter(); let mut json = Jsonb::make_empty_array(values.len()); - for value in values.iter() { - if matches!(value.get_value(), Value::Blob(_)) { + for value in values { + let value = value.as_value_ref(); + if matches!(value, ValueRef::Blob(_)) { crate::bail_constraint_error!("JSON cannot hold BLOB values") } - let value = convert_dbtype_to_jsonb(value.get_value(), Conv::NotStrict)?; + let value = convert_dbtype_to_jsonb(value, Conv::NotStrict)?; json.append_jsonb_to_end(value.data()); } json.finalize_unsafe(ElementType::ARRAY)?; @@ -206,14 +206,21 @@ pub fn json_array(values: &[Register]) -> crate::Result { json_string_to_db_type(json, ElementType::ARRAY, OutputVariant::ElementType) } -pub fn jsonb_array(values: &[Register]) -> crate::Result { +pub fn jsonb_array(values: I) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let values = values.into_iter(); let mut json = Jsonb::make_empty_array(values.len()); - for value in values.iter() { - if matches!(value.get_value(), Value::Blob(_)) { + for value in values { + let value = value.as_value_ref(); + if matches!(value, ValueRef::Blob(_)) { crate::bail_constraint_error!("JSON cannot hold BLOB values") } - let value = convert_dbtype_to_jsonb(value.get_value(), Conv::NotStrict)?; + let value = convert_dbtype_to_jsonb(value, Conv::NotStrict)?; json.append_jsonb_to_end(value.data()); } json.finalize_unsafe(ElementType::ARRAY)?; @@ -246,19 +253,27 @@ pub fn json_array_length( Ok(Value::Null) } -pub fn json_set(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result { - if args.is_empty() { +pub fn json_set(args: I, json_cache: &JsonCacheCell) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut args = args.into_iter(); + if args.len() == 0 { return Ok(Value::Null); } - let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut json = json_cache.get_or_insert_with(args[0].get_value(), make_jsonb_fn)?; - let other = args[1..].chunks_exact(2); + let mut json = json_cache.get_or_insert_with(args.next().unwrap(), make_jsonb_fn)?; - for chunk in other { - let path = json_path_from_db_value(chunk[0].get_value(), true)?; + // TODO: when `array_chunks` is stabilized we can chunk by 2 here + while args.len() > 1 { + let first = args.next().unwrap(); - let value = convert_dbtype_to_jsonb(chunk[1].get_value(), Conv::NotStrict)?; + let path = json_path_from_db_value(&first, true)?; + + let second = args.next().unwrap(); + let value = convert_dbtype_to_jsonb(second, Conv::NotStrict)?; let mut op = SetOperation::new(value); if let Some(path) = path { let _ = json.operate_on_path(&path, &mut op); @@ -270,19 +285,27 @@ pub fn json_set(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result< json_string_to_db_type(json, el_type, OutputVariant::String) } -pub fn jsonb_set(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result { - if args.is_empty() { +pub fn jsonb_set(args: I, json_cache: &JsonCacheCell) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut args = args.into_iter(); + if args.len() == 0 { return Ok(Value::Null); } let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut json = json_cache.get_or_insert_with(args[0].get_value(), make_jsonb_fn)?; - let other = args[1..].chunks_exact(2); + let mut json = json_cache.get_or_insert_with(args.next().unwrap(), make_jsonb_fn)?; - for chunk in other { - let path = json_path_from_db_value(chunk[0].get_value(), true)?; + // TODO: when `array_chunks` is stabilized we can chunk by 2 here + while args.len() > 1 { + let first = args.next().unwrap(); + let path = json_path_from_db_value(&first, true)?; - let value = convert_dbtype_to_jsonb(chunk[1].get_value(), Conv::NotStrict)?; + let second = args.next().unwrap(); + let value = convert_dbtype_to_jsonb(second, Conv::NotStrict)?; let mut op = SetOperation::new(value); if let Some(path) = path { let _ = json.operate_on_path(&path, &mut op); @@ -297,15 +320,16 @@ pub fn jsonb_set(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result /// Implements the -> operator. Always returns a proper JSON value. /// https://sqlite.org/json1.html#the_and_operators pub fn json_arrow_extract( - value: &Value, - path: &Value, + value: impl AsValueRef, + path: impl AsValueRef, json_cache: &JsonCacheCell, ) -> crate::Result { - if let Value::Null = value { + let value = value.as_value_ref(); + if let ValueRef::Null = value { return Ok(Value::Null); } - if let Some(path) = json_path_from_db_value(path, false)? { + if let Some(path) = json_path_from_db_value(&path, false)? { let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); let mut json = json_cache.get_or_insert_with(value, make_jsonb_fn)?; let mut op = SearchOperation::new(json.len()); @@ -324,14 +348,15 @@ pub fn json_arrow_extract( /// Implements the ->> operator. Always returns a SQL representation of the JSON subcomponent. /// https://sqlite.org/json1.html#the_and_operators pub fn json_arrow_shift_extract( - value: &Value, - path: &Value, + value: impl AsValueRef, + path: impl AsValueRef, json_cache: &JsonCacheCell, ) -> crate::Result { - if let Value::Null = value { + let value = value.as_value_ref(); + if let ValueRef::Null = value { return Ok(Value::Null); } - if let Some(path) = json_path_from_db_value(path, false)? { + if let Some(path) = json_path_from_db_value(&path, false)? { let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); let mut json = json_cache.get_or_insert_with(value, make_jsonb_fn)?; let mut op = SearchOperation::new(json.len()); @@ -359,16 +384,23 @@ pub fn json_arrow_shift_extract( /// Extracts a JSON value from a JSON object or array. /// If there's only a single path, the return value might be either a TEXT or a database type. /// https://sqlite.org/json1.html#the_json_extract_function -pub fn json_extract( - value: &Value, - paths: &[Register], +pub fn json_extract( + value: impl AsValueRef, + paths: I, json_cache: &JsonCacheCell, -) -> crate::Result { - if let Value::Null = value { +) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let value = value.as_value_ref(); + if let ValueRef::Null = value { return Ok(Value::Null); } - if paths.is_empty() { + let paths = paths.into_iter(); + if paths.len() == 0 { return Ok(Value::Null); } let convert_to_jsonb = curry_convert_dbtype_to_jsonb(Conv::Strict); @@ -380,16 +412,22 @@ pub fn json_extract( Ok(result) } -pub fn jsonb_extract( +pub fn jsonb_extract( value: &Value, - paths: &[Register], + paths: I, json_cache: &JsonCacheCell, -) -> crate::Result { +) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ if let Value::Null = value { return Ok(Value::Null); } - if paths.is_empty() { + let paths = paths.into_iter(); + if paths.len() == 0 { return Ok(Value::Null); } let convert_to_jsonb = curry_convert_dbtype_to_jsonb(Conv::Strict); @@ -401,10 +439,14 @@ pub fn jsonb_extract( Ok(result) } -fn jsonb_extract_internal(value: Jsonb, paths: &[Register]) -> crate::Result<(Jsonb, ElementType)> { +fn jsonb_extract_internal(value: Jsonb, mut paths: E) -> crate::Result<(Jsonb, ElementType)> +where + V: AsValueRef, + E: ExactSizeIterator, +{ let null = Jsonb::from_raw_data(JsonbHeader::make_null().into_bytes().as_bytes()); if paths.len() == 1 { - if let Some(path) = json_path_from_db_value(paths[0].get_value(), true)? { + if let Some(path) = json_path_from_db_value(&paths.next().unwrap(), true)? { let mut json = value; let mut op = SearchOperation::new(json.len()); @@ -428,10 +470,8 @@ fn jsonb_extract_internal(value: Jsonb, paths: &[Register]) -> crate::Result<(Js let mut result = Jsonb::make_empty_array(json.len()); // TODO: make an op to avoid creating new json for every path element - let paths = paths - .iter() - .map(|p| json_path_from_db_value(p.get_value(), true)); for path in paths { + let path = json_path_from_db_value(&path, true); if let Some(path) = path? { let mut op = SearchOperation::new(json.len()); let res = json.operate_on_path(&path, &mut op); @@ -502,8 +542,9 @@ pub fn json_string_to_db_type( } } -pub fn json_type(value: &Value, path: Option<&Value>) -> crate::Result { - if let Value::Null = value { +pub fn json_type(value: impl AsValueRef, path: Option) -> crate::Result { + let value = value.as_value_ref(); + if let ValueRef::Null = value { return Ok(Value::Null); } if path.is_none() { @@ -512,7 +553,7 @@ pub fn json_type(value: &Value, path: Option<&Value>) -> crate::Result { return Ok(Value::Text(Text::json(element_type.into()))); } - if let Some(path) = json_path_from_db_value(path.unwrap(), true)? { + if let Some(path) = json_path_from_db_value(&path.unwrap(), true)? { let mut json = convert_dbtype_to_jsonb(value, Conv::Strict)?; if let Ok(mut path) = json.navigate_path(&path, PathOperationMode::ReplaceExisting) { @@ -531,16 +572,20 @@ pub fn json_type(value: &Value, path: Option<&Value>) -> crate::Result { } } -fn json_path_from_db_value(path: &Value, strict: bool) -> crate::Result>> { +fn json_path_from_db_value<'a>( + path: &'a (impl AsValueRef + 'a), + strict: bool, +) -> crate::Result>> { + let path = path.as_value_ref(); let json_path = if strict { match path { - Value::Text(t) => json_path(t.as_str())?, - Value::Null => return Ok(None), + ValueRef::Text(t) => json_path(t.as_str())?, + ValueRef::Null => return Ok(None), _ => crate::bail_constraint_error!("JSON path error near: {:?}", path.to_string()), } } else { match path { - Value::Text(t) => { + ValueRef::Text(t) => { if t.as_str().starts_with("$") { json_path(t.as_str())? } else { @@ -552,14 +597,14 @@ fn json_path_from_db_value(path: &Value, strict: bool) -> crate::Result return Ok(None), - Value::Integer(i) => JsonPath { + ValueRef::Null => return Ok(None), + ValueRef::Integer(i) => JsonPath { elements: vec![ PathElement::Root(), - PathElement::ArrayLocator(Some(*i as i32)), + PathElement::ArrayLocator(Some(i as i32)), ], }, - Value::Float(f) => JsonPath { + ValueRef::Float(f) => JsonPath { elements: vec![ PathElement::Root(), PathElement::Key(Cow::Owned(f.to_string()), false), @@ -572,9 +617,9 @@ fn json_path_from_db_value(path: &Value, strict: bool) -> crate::Result crate::Result { - match json { - Value::Text(t) => match Jsonb::from_str(t.as_str()) { +pub fn json_error_position(json: impl AsValueRef) -> crate::Result { + match json.as_value_ref() { + ValueRef::Text(t) => match Jsonb::from_str(t.as_str()) { Ok(_) => Ok(Value::Integer(0)), Err(JsonError::Message { location, .. }) => { if let Some(loc) = location { @@ -587,10 +632,10 @@ pub fn json_error_position(json: &Value) -> crate::Result { } } }, - Value::Blob(_) => { + ValueRef::Blob(_) => { bail_parse_error!("Unsupported") } - Value::Null => Ok(Value::Null), + ValueRef::Null => Ok(Value::Null), _ => Ok(Value::Integer(0)), } } @@ -598,19 +643,30 @@ pub fn json_error_position(json: &Value) -> crate::Result { /// Constructs a JSON object from a list of values that represent key-value pairs. /// The number of values must be even, and the first value of each pair (which represents the map key) /// must be a TEXT value. The second value of each pair can be any JSON value (which represents the map value) -pub fn json_object(values: &[Register]) -> crate::Result { +pub fn json_object(values: I) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut values = values.into_iter(); if values.len() % 2 != 0 { bail_constraint_error!("json_object() requires an even number of arguments") } let mut json = Jsonb::make_empty_obj(values.len() * 50); - for chunk in values.chunks_exact(2) { - if chunk[0].get_value().value_type() != ValueType::Text { + // TODO: when `array_chunks` is stabilized we can chunk by 2 here + while values.len() > 1 { + let first = values.next().unwrap(); + let first = first.as_value_ref(); + if first.value_type() != ValueType::Text { bail_constraint_error!("json_object() labels must be TEXT") } - let key = convert_dbtype_to_jsonb(chunk[0].get_value(), Conv::ToString)?; + let key = convert_dbtype_to_jsonb(first, Conv::ToString)?; json.append_jsonb_to_end(key.data()); - let value = convert_dbtype_to_jsonb(chunk[1].get_value(), Conv::NotStrict)?; + + let second = values.next().unwrap(); + let value = convert_dbtype_to_jsonb(second, Conv::NotStrict)?; json.append_jsonb_to_end(value.data()); } @@ -619,19 +675,30 @@ pub fn json_object(values: &[Register]) -> crate::Result { json_string_to_db_type(json, ElementType::OBJECT, OutputVariant::String) } -pub fn jsonb_object(values: &[Register]) -> crate::Result { +pub fn jsonb_object(values: I) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut values = values.into_iter(); if values.len() % 2 != 0 { bail_constraint_error!("json_object() requires an even number of arguments") } let mut json = Jsonb::make_empty_obj(values.len() * 50); - for chunk in values.chunks_exact(2) { - if chunk[0].get_value().value_type() != ValueType::Text { + // TODO: when `array_chunks` is stabilized we can chunk by 2 here + while values.len() > 1 { + let first = values.next().unwrap(); + let first = first.as_value_ref(); + if first.value_type() != ValueType::Text { bail_constraint_error!("json_object() labels must be TEXT") } - let key = convert_dbtype_to_jsonb(chunk[0].get_value(), Conv::ToString)?; + let key = convert_dbtype_to_jsonb(first, Conv::ToString)?; json.append_jsonb_to_end(key.data()); - let value = convert_dbtype_to_jsonb(chunk[1].get_value(), Conv::NotStrict)?; + + let second = values.next().unwrap(); + let value = convert_dbtype_to_jsonb(second, Conv::NotStrict)?; json.append_jsonb_to_end(value.data()); } @@ -642,8 +709,9 @@ pub fn jsonb_object(values: &[Register]) -> crate::Result { /// Tries to convert the value to jsonb. Returns Value::Integer(1) if it the conversion /// succeeded, and Value::Integer(0) if it didn't. -pub fn is_json_valid(json_value: &Value) -> Value { - if matches!(json_value, Value::Null) { +pub fn is_json_valid(json_value: impl AsValueRef) -> Value { + let json_value = json_value.as_value_ref(); + if matches!(json_value, ValueRef::Null) { return Value::Null; } convert_dbtype_to_jsonb(json_value, Conv::Strict) @@ -651,9 +719,10 @@ pub fn is_json_valid(json_value: &Value) -> Value { .unwrap_or(Value::Integer(0)) } -pub fn json_quote(value: &Value) -> crate::Result { +pub fn json_quote(value: impl AsValueRef) -> crate::Result { + let value = value.as_value_ref(); match value { - Value::Text(ref t) => { + ValueRef::Text(ref t) => { // If X is a JSON value returned by another JSON function, // then this function is a no-op if t.subtype == TextSubtype::Json { @@ -678,10 +747,10 @@ pub fn json_quote(value: &Value) -> crate::Result { Ok(Value::build_text(escaped_value)) } // Numbers are unquoted in json - Value::Integer(ref int) => Ok(Value::Integer(int.to_owned())), - Value::Float(ref float) => Ok(Value::Float(float.to_owned())), - Value::Blob(_) => crate::bail_constraint_error!("JSON cannot hold BLOB values"), - Value::Null => Ok(Value::build_text("null")), + ValueRef::Integer(int) => Ok(Value::Integer(int)), + ValueRef::Float(float) => Ok(Value::Float(float)), + ValueRef::Blob(_) => crate::bail_constraint_error!("JSON cannot hold BLOB values"), + ValueRef::Null => Ok(Value::build_text("null")), } } @@ -808,14 +877,9 @@ mod tests { #[test] fn test_json_array_simple() { - let text = Register::Value(Value::build_text("value1")); - let json = Register::Value(Value::Text(Text::json("\"value2\"".to_string()))); - let input = vec![ - text, - json, - Register::Value(Value::Integer(1)), - Register::Value(Value::Float(1.1)), - ]; + let text = Value::build_text("value1"); + let json = Value::Text(Text::json("\"value2\"".to_string())); + let input = [text, json, Value::Integer(1), Value::Float(1.1)]; let result = json_array(&input).unwrap(); if let Value::Text(res) = result { @@ -828,9 +892,9 @@ mod tests { #[test] fn test_json_array_empty() { - let input = vec![]; + let input: [Value; 0] = []; - let result = json_array(&input).unwrap(); + let result = json_array(input).unwrap(); if let Value::Text(res) = result { assert_eq!(res.as_str(), "[]"); assert_eq!(res.subtype, TextSubtype::Json); @@ -841,9 +905,9 @@ mod tests { #[test] fn test_json_array_blob_invalid() { - let blob = Register::Value(Value::Blob("1".as_bytes().to_vec())); + let blob = Value::Blob("1".as_bytes().to_vec()); - let input = vec![blob]; + let input = [blob]; let result = json_array(&input); @@ -968,7 +1032,7 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_extract( &Value::build_text("{\"a\":2}"), - &[Register::Value(Value::build_text("$.x"))], + &[Value::build_text("$.x")], &json_cache, ); @@ -980,11 +1044,7 @@ mod tests { #[test] fn test_json_extract_null_path() { let json_cache = JsonCacheCell::new(); - let result = json_extract( - &Value::build_text("{\"a\":2}"), - &[Register::Value(Value::Null)], - &json_cache, - ); + let result = json_extract(&Value::build_text("{\"a\":2}"), &[Value::Null], &json_cache); match result { Ok(Value::Null) => (), @@ -997,7 +1057,7 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_extract( &Value::build_text("{\"a\":2}"), - &[Register::Value(Value::Float(1.1))], + &[Value::Float(1.1)], &json_cache, ); @@ -1058,9 +1118,9 @@ mod tests { #[test] fn test_json_object_simple() { - let key = Register::Value(Value::build_text("key")); - let value = Register::Value(Value::build_text("value")); - let input = vec![key, value]; + let key = Value::build_text("key"); + let value = Value::build_text("value"); + let input = [key, value]; let result = json_object(&input).unwrap(); let Value::Text(json_text) = result else { @@ -1082,17 +1142,17 @@ mod tests { let null_key = Value::build_text("null_key"); let null_value = Value::Null; - let input = vec![ - Register::Value(text_key), - Register::Value(text_value), - Register::Value(json_key), - Register::Value(json_value), - Register::Value(integer_key), - Register::Value(integer_value), - Register::Value(float_key), - Register::Value(float_value), - Register::Value(null_key), - Register::Value(null_value), + let input = [ + text_key, + text_value, + json_key, + json_value, + integer_key, + integer_value, + float_key, + float_value, + null_key, + null_value, ]; let result = json_object(&input).unwrap(); @@ -1107,9 +1167,9 @@ mod tests { #[test] fn test_json_object_json_value_is_rendered_as_json() { - let key = Register::Value(Value::build_text("key")); - let value = Register::Value(Value::Text(Text::json(r#"{"json":"value"}"#.to_string()))); - let input = vec![key, value]; + let key = Value::build_text("key"); + let value = Value::Text(Text::json(r#"{"json":"value"}"#.to_string())); + let input = [key, value]; let result = json_object(&input).unwrap(); let Value::Text(json_text) = result else { @@ -1120,9 +1180,9 @@ mod tests { #[test] fn test_json_object_json_text_value_is_rendered_as_regular_text() { - let key = Register::Value(Value::build_text("key")); - let value = Register::Value(Value::Text(Text::new(r#"{"json":"value"}"#))); - let input = vec![key, value]; + let key = Value::build_text("key"); + let value = Value::Text(Text::new(r#"{"json":"value"}"#)); + let input = [key, value]; let result = json_object(&input).unwrap(); let Value::Text(json_text) = result else { @@ -1133,13 +1193,13 @@ mod tests { #[test] fn test_json_object_nested() { - let key = Register::Value(Value::build_text("key")); - let value = Register::Value(Value::build_text("value")); - let input = vec![key, value]; + let key = Value::build_text("key"); + let value = Value::build_text("value"); + let input = [key, value]; - let parent_key = Register::Value(Value::build_text("parent_key")); - let parent_value = Register::Value(json_object(&input).unwrap()); - let parent_input = vec![parent_key, parent_value]; + let parent_key = Value::build_text("parent_key"); + let parent_value = json_object(&input).unwrap(); + let parent_input = [parent_key, parent_value]; let result = json_object(&parent_input).unwrap(); @@ -1151,9 +1211,9 @@ mod tests { #[test] fn test_json_object_duplicated_keys() { - let key = Register::Value(Value::build_text("key")); - let value = Register::Value(Value::build_text("value")); - let input = vec![key.clone(), value.clone(), key, value]; + let key = Value::build_text("key"); + let value = Value::build_text("value"); + let input = [key.clone(), value.clone(), key, value]; let result = json_object(&input).unwrap(); let Value::Text(json_text) = result else { @@ -1164,7 +1224,7 @@ mod tests { #[test] fn test_json_object_empty() { - let input = vec![]; + let input: [Value; 0] = []; let result = json_object(&input).unwrap(); let Value::Text(json_text) = result else { @@ -1175,9 +1235,9 @@ mod tests { #[test] fn test_json_object_non_text_key() { - let key = Register::Value(Value::Integer(1)); - let value = Register::Value(Value::build_text("value")); - let input = vec![key, value]; + let key = Value::Integer(1); + let value = Value::build_text("value"); + let input = [key, value]; match json_object(&input) { Ok(_) => panic!("Expected error for non-TEXT key"), @@ -1187,9 +1247,9 @@ mod tests { #[test] fn test_json_odd_number_of_values() { - let key = Register::Value(Value::build_text("key")); - let value = Register::Value(Value::build_text("value")); - let input = vec![key.clone(), value, key]; + let key = Value::build_text("key"); + let value = Value::build_text("value"); + let input = [key.clone(), value, key]; assert!(json_object(&input).is_err()); } @@ -1326,9 +1386,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("{}")), - Register::Value(Value::build_text("$.field")), - Register::Value(Value::build_text("value")), + Value::build_text("{}"), + Value::build_text("$.field"), + Value::build_text("value"), ], &json_cache, ); @@ -1343,9 +1403,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text(r#"{"field":"old_value"}"#)), - Register::Value(Value::build_text("$.field")), - Register::Value(Value::build_text("new_value")), + Value::build_text(r#"{"field":"old_value"}"#), + Value::build_text("$.field"), + Value::build_text("new_value"), ], &json_cache, ); @@ -1363,9 +1423,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("{}")), - Register::Value(Value::build_text("$.object.doesnt.exist")), - Register::Value(Value::build_text("value")), + Value::build_text("{}"), + Value::build_text("$.object.doesnt.exist"), + Value::build_text("value"), ], &json_cache, ); @@ -1383,9 +1443,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("[]")), - Register::Value(Value::build_text("$[0]")), - Register::Value(Value::build_text("value")), + Value::build_text("[]"), + Value::build_text("$[0]"), + Value::build_text("value"), ], &json_cache, ); @@ -1400,9 +1460,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("{}")), - Register::Value(Value::build_text("$.some_array[0]")), - Register::Value(Value::Integer(123)), + Value::build_text("{}"), + Value::build_text("$.some_array[0]"), + Value::Integer(123), ], &json_cache, ); @@ -1420,9 +1480,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("[123]")), - Register::Value(Value::build_text("$[1]")), - Register::Value(Value::Integer(456)), + Value::build_text("[123]"), + Value::build_text("$[1]"), + Value::Integer(456), ], &json_cache, ); @@ -1437,9 +1497,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("[123]")), - Register::Value(Value::build_text("$[200]")), - Register::Value(Value::Integer(456)), + Value::build_text("[123]"), + Value::build_text("$[200]"), + Value::Integer(456), ], &json_cache, ); @@ -1454,9 +1514,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("[123]")), - Register::Value(Value::build_text("$[0]")), - Register::Value(Value::Integer(456)), + Value::build_text("[123]"), + Value::build_text("$[0]"), + Value::Integer(456), ], &json_cache, ); @@ -1470,11 +1530,7 @@ mod tests { fn test_json_set_null_path() { let json_cache = JsonCacheCell::new(); let result = json_set( - &[ - Register::Value(Value::build_text("{}")), - Register::Value(Value::Null), - Register::Value(Value::Integer(456)), - ], + &[Value::build_text("{}"), Value::Null, Value::Integer(456)], &json_cache, ); @@ -1488,11 +1544,11 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("[123]")), - Register::Value(Value::build_text("$[0]")), - Register::Value(Value::Integer(456)), - Register::Value(Value::build_text("$[1]")), - Register::Value(Value::Integer(789)), + Value::build_text("[123]"), + Value::build_text("$[0]"), + Value::Integer(456), + Value::build_text("$[1]"), + Value::Integer(789), ], &json_cache, ); @@ -1507,9 +1563,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("{}")), - Register::Value(Value::build_text("$.object[0].field")), - Register::Value(Value::Integer(123)), + Value::build_text("{}"), + Value::build_text("$.object[0].field"), + Value::Integer(123), ], &json_cache, ); @@ -1527,9 +1583,9 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("{}")), - Register::Value(Value::build_text("$.object[0][0]")), - Register::Value(Value::Integer(123)), + Value::build_text("{}"), + Value::build_text("$.object[0][0]"), + Value::Integer(123), ], &json_cache, ); @@ -1544,11 +1600,11 @@ mod tests { let json_cache = JsonCacheCell::new(); let result = json_set( &[ - Register::Value(Value::build_text("{}")), - Register::Value(Value::build_text("$.object[123].another")), - Register::Value(Value::build_text("value")), - Register::Value(Value::build_text("$.field")), - Register::Value(Value::build_text("value")), + Value::build_text("{}"), + Value::build_text("$.object[123].another"), + Value::build_text("value"), + Value::build_text("$.field"), + Value::build_text("value"), ], &json_cache, ); diff --git a/core/json/ops.rs b/core/json/ops.rs index f1589eeba..476f81f69 100644 --- a/core/json/ops.rs +++ b/core/json/ops.rs @@ -1,4 +1,7 @@ -use crate::{types::Value, vdbe::Register}; +use crate::{ + types::{AsValueRef, Value}, + ValueRef, +}; use super::{ convert_dbtype_to_jsonb, curry_convert_dbtype_to_jsonb, json_path_from_db_value, @@ -12,16 +15,22 @@ use super::{ /// * If the patch contains a scalar value, the target is replaced with that value /// * If both target and patch are objects, the patch is recursively applied /// * null values in the patch result in property removal from the target -pub fn json_patch(target: &Value, patch: &Value, cache: &JsonCacheCell) -> crate::Result { +pub fn json_patch( + target: impl AsValueRef, + patch: impl AsValueRef, + cache: &JsonCacheCell, +) -> crate::Result { + let (target, patch) = (target.as_value_ref(), patch.as_value_ref()); match (target, patch) { - (Value::Blob(_), _) | (_, Value::Blob(_)) => { + (ValueRef::Blob(_), _) | (_, ValueRef::Blob(_)) => { crate::bail_constraint_error!("blob is not supported!"); } _ => (), } let make_jsonb = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut target = cache.get_or_insert_with(target, &make_jsonb)?; - let patch = cache.get_or_insert_with(patch, &make_jsonb)?; + let mut target = cache.get_or_insert_with(target, make_jsonb)?; + let make_jsonb = curry_convert_dbtype_to_jsonb(Conv::Strict); + let patch = cache.get_or_insert_with(patch, make_jsonb)?; target.patch(&patch)?; @@ -30,16 +39,22 @@ pub fn json_patch(target: &Value, patch: &Value, cache: &JsonCacheCell) -> crate json_string_to_db_type(target, element_type, OutputVariant::ElementType) } -pub fn jsonb_patch(target: &Value, patch: &Value, cache: &JsonCacheCell) -> crate::Result { +pub fn jsonb_patch( + target: impl AsValueRef, + patch: impl AsValueRef, + cache: &JsonCacheCell, +) -> crate::Result { + let (target, patch) = (target.as_value_ref(), patch.as_value_ref()); match (target, patch) { - (Value::Blob(_), _) | (_, Value::Blob(_)) => { + (ValueRef::Blob(_), _) | (_, ValueRef::Blob(_)) => { crate::bail_constraint_error!("blob is not supported!"); } _ => (), } let make_jsonb = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut target = cache.get_or_insert_with(target, &make_jsonb)?; - let patch = cache.get_or_insert_with(patch, &make_jsonb)?; + let mut target = cache.get_or_insert_with(target, make_jsonb)?; + let make_jsonb = curry_convert_dbtype_to_jsonb(Conv::Strict); + let patch = cache.get_or_insert_with(patch, make_jsonb)?; target.patch(&patch)?; @@ -48,15 +63,21 @@ pub fn jsonb_patch(target: &Value, patch: &Value, cache: &JsonCacheCell) -> crat json_string_to_db_type(target, element_type, OutputVariant::Binary) } -pub fn json_remove(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result { - if args.is_empty() { +pub fn json_remove(args: I, json_cache: &JsonCacheCell) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut args = args.into_iter(); + if args.len() == 0 { return Ok(Value::Null); } let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut json = json_cache.get_or_insert_with(args[0].get_value(), make_jsonb_fn)?; - for arg in &args[1..] { - if let Some(path) = json_path_from_db_value(arg.get_value(), true)? { + let mut json = json_cache.get_or_insert_with(args.next().unwrap(), make_jsonb_fn)?; + for arg in args { + if let Some(path) = json_path_from_db_value(&arg, true)? { let mut op = DeleteOperation::new(); let _ = json.operate_on_path(&path, &mut op); } @@ -67,15 +88,21 @@ pub fn json_remove(args: &[Register], json_cache: &JsonCacheCell) -> crate::Resu json_string_to_db_type(json, el_type, OutputVariant::String) } -pub fn jsonb_remove(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result { - if args.is_empty() { +pub fn jsonb_remove(args: I, json_cache: &JsonCacheCell) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut args = args.into_iter(); + if args.len() == 0 { return Ok(Value::Null); } let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut json = json_cache.get_or_insert_with(args[0].get_value(), make_jsonb_fn)?; - for arg in &args[1..] { - if let Some(path) = json_path_from_db_value(arg.get_value(), true)? { + let mut json = json_cache.get_or_insert_with(args.next().unwrap(), make_jsonb_fn)?; + for arg in args { + if let Some(path) = json_path_from_db_value(&arg, true)? { let mut op = DeleteOperation::new(); let _ = json.operate_on_path(&path, &mut op); } @@ -84,18 +111,26 @@ pub fn jsonb_remove(args: &[Register], json_cache: &JsonCacheCell) -> crate::Res Ok(Value::Blob(json.data())) } -pub fn json_replace(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result { - if args.is_empty() { +pub fn json_replace(args: I, json_cache: &JsonCacheCell) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut args = args.into_iter(); + if args.len() == 0 { return Ok(Value::Null); } let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut json = json_cache.get_or_insert_with(args[0].get_value(), make_jsonb_fn)?; - let other = args[1..].chunks_exact(2); - for chunk in other { - let path = json_path_from_db_value(chunk[0].get_value(), true)?; + let mut json = json_cache.get_or_insert_with(args.next().unwrap(), make_jsonb_fn)?; + // TODO: when `array_chunks` is stabilized we can chunk by 2 here + while args.len() > 1 { + let first = args.next().unwrap(); + let path = json_path_from_db_value(&first, true)?; - let value = convert_dbtype_to_jsonb(chunk[1].get_value(), Conv::NotStrict)?; + let second = args.next().unwrap(); + let value = convert_dbtype_to_jsonb(&second, Conv::NotStrict)?; if let Some(path) = path { let mut op = ReplaceOperation::new(value); @@ -108,17 +143,26 @@ pub fn json_replace(args: &[Register], json_cache: &JsonCacheCell) -> crate::Res json_string_to_db_type(json, el_type, super::OutputVariant::String) } -pub fn jsonb_replace(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result { - if args.is_empty() { +pub fn jsonb_replace(args: I, json_cache: &JsonCacheCell) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut args = args.into_iter(); + if args.len() == 0 { return Ok(Value::Null); } let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut json = json_cache.get_or_insert_with(args[0].get_value(), make_jsonb_fn)?; - let other = args[1..].chunks_exact(2); - for chunk in other { - let path = json_path_from_db_value(chunk[0].get_value(), true)?; - let value = convert_dbtype_to_jsonb(chunk[1].get_value(), Conv::NotStrict)?; + let mut json = json_cache.get_or_insert_with(args.next().unwrap(), make_jsonb_fn)?; + // TODO: when `array_chunks` is stabilized we can chunk by 2 here + while args.len() > 1 { + let first = args.next().unwrap(); + let path = json_path_from_db_value(&first, true)?; + + let second = args.next().unwrap(); + let value = convert_dbtype_to_jsonb(&second, Conv::NotStrict)?; if let Some(path) = path { let mut op = ReplaceOperation::new(value); @@ -131,17 +175,27 @@ pub fn jsonb_replace(args: &[Register], json_cache: &JsonCacheCell) -> crate::Re json_string_to_db_type(json, el_type, OutputVariant::Binary) } -pub fn json_insert(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result { - if args.is_empty() { +pub fn json_insert(args: I, json_cache: &JsonCacheCell) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut args = args.into_iter(); + if args.len() == 0 { return Ok(Value::Null); } let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut json = json_cache.get_or_insert_with(args[0].get_value(), make_jsonb_fn)?; - let other = args[1..].chunks_exact(2); - for chunk in other { - let path = json_path_from_db_value(chunk[0].get_value(), true)?; - let value = convert_dbtype_to_jsonb(chunk[1].get_value(), Conv::NotStrict)?; + let mut json = json_cache.get_or_insert_with(args.next().unwrap(), make_jsonb_fn)?; + + // TODO: when `array_chunks` is stabilized we can chunk by 2 here + while args.len() > 1 { + let first = args.next().unwrap(); + let path = json_path_from_db_value(&first, true)?; + + let second = args.next().unwrap(); + let value = convert_dbtype_to_jsonb(&second, Conv::NotStrict)?; if let Some(path) = path { let mut op = InsertOperation::new(value); @@ -154,17 +208,27 @@ pub fn json_insert(args: &[Register], json_cache: &JsonCacheCell) -> crate::Resu json_string_to_db_type(json, el_type, OutputVariant::String) } -pub fn jsonb_insert(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result { - if args.is_empty() { +pub fn jsonb_insert(args: I, json_cache: &JsonCacheCell) -> crate::Result +where + V: AsValueRef, + E: ExactSizeIterator, + I: IntoIterator, +{ + let mut args = args.into_iter(); + if args.len() == 0 { return Ok(Value::Null); } let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict); - let mut json = json_cache.get_or_insert_with(args[0].get_value(), make_jsonb_fn)?; - let other = args[1..].chunks_exact(2); - for chunk in other { - let path = json_path_from_db_value(chunk[0].get_value(), true)?; - let value = convert_dbtype_to_jsonb(chunk[1].get_value(), Conv::NotStrict)?; + let mut json = json_cache.get_or_insert_with(args.next().unwrap(), make_jsonb_fn)?; + + // TODO: when `array_chunks` is stabilized we can chunk by 2 here + while args.len() > 1 { + let first = args.next().unwrap(); + let path = json_path_from_db_value(&first, true)?; + + let second = args.next().unwrap(); + let value = convert_dbtype_to_jsonb(&second, Conv::NotStrict)?; if let Some(path) = path { let mut op = InsertOperation::new(value); @@ -282,17 +346,14 @@ mod tests { #[test] fn test_json_remove_empty_args() { - let args = vec![]; + let args: [Value; 0] = []; let json_cache = JsonCacheCell::new(); assert_eq!(json_remove(&args, &json_cache).unwrap(), Value::Null); } #[test] fn test_json_remove_array_element() { - let args = vec![ - Register::Value(create_json(r#"[1,2,3,4,5]"#)), - Register::Value(create_text("$[2]")), - ]; + let args = [create_json(r#"[1,2,3,4,5]"#), create_text("$[2]")]; let json_cache = JsonCacheCell::new(); let result = json_remove(&args, &json_cache).unwrap(); @@ -304,10 +365,10 @@ mod tests { #[test] fn test_json_remove_multiple_paths() { - let args = vec![ - Register::Value(create_json(r#"{"a": 1, "b": 2, "c": 3}"#)), - Register::Value(create_text("$.a")), - Register::Value(create_text("$.c")), + let args = [ + create_json(r#"{"a": 1, "b": 2, "c": 3}"#), + create_text("$.a"), + create_text("$.c"), ]; let json_cache = JsonCacheCell::new(); @@ -320,9 +381,9 @@ mod tests { #[test] fn test_json_remove_nested_paths() { - let args = vec![ - Register::Value(create_json(r#"{"a": {"b": {"c": 1, "d": 2}}}"#)), - Register::Value(create_text("$.a.b.c")), + let args = [ + create_json(r#"{"a": {"b": {"c": 1, "d": 2}}}"#), + create_text("$.a.b.c"), ]; let json_cache = JsonCacheCell::new(); @@ -335,9 +396,9 @@ mod tests { #[test] fn test_json_remove_duplicate_keys() { - let args = vec![ - Register::Value(create_json(r#"{"a": 1, "a": 2, "a": 3}"#)), - Register::Value(create_text("$.a")), + let args = [ + create_json(r#"{"a": 1, "a": 2, "a": 3}"#), + create_text("$.a"), ]; let json_cache = JsonCacheCell::new(); @@ -350,9 +411,9 @@ mod tests { #[test] fn test_json_remove_invalid_path() { - let args = vec![ - Register::Value(create_json(r#"{"a": 1}"#)), - Register::Value(Value::Integer(42)), // Invalid path type + let args = [ + create_json(r#"{"a": 1}"#), + Value::Integer(42), // Invalid path type ]; let json_cache = JsonCacheCell::new(); @@ -361,13 +422,11 @@ mod tests { #[test] fn test_json_remove_complex_case() { - let args = vec![ - Register::Value(create_json( - r#"{"a":[1,2,3],"b":{"x":1,"x":2},"c":[{"y":1},{"y":2}]}"#, - )), - Register::Value(create_text("$.a[1]")), - Register::Value(create_text("$.b.x")), - Register::Value(create_text("$.c[0].y")), + let args = [ + create_json(r#"{"a":[1,2,3],"b":{"x":1,"x":2},"c":[{"y":1},{"y":2}]}"#), + create_text("$.a[1]"), + create_text("$.b.x"), + create_text("$.c[0].y"), ]; let json_cache = JsonCacheCell::new(); diff --git a/core/types.rs b/core/types.rs index 138703521..768fe6ece 100644 --- a/core/types.rs +++ b/core/types.rs @@ -1566,6 +1566,13 @@ impl<'a> PartialEq> for ValueRef<'a> { } } +impl<'a> PartialEq for ValueRef<'a> { + fn eq(&self, other: &Value) -> bool { + let other = other.as_value_ref(); + self.eq(&other) + } +} + impl<'a> Eq for ValueRef<'a> {} #[expect(clippy::non_canonical_partial_ord_impl)] diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 27fa9188c..aaf3a33c4 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -4442,7 +4442,8 @@ pub fn op_function( | JsonFunc::JsonObject | JsonFunc::JsonbArray | JsonFunc::JsonbObject => { - let reg_values = &state.registers[*start_reg..*start_reg + arg_count]; + let reg_values = + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]); let json_func = match json_func { JsonFunc::JsonArray => json_array, @@ -4463,7 +4464,9 @@ pub fn op_function( 0 => Ok(Value::Null), _ => { let val = &state.registers[*start_reg]; - let reg_values = &state.registers[*start_reg + 1..*start_reg + arg_count]; + let reg_values = registers_to_ref_values( + &state.registers[*start_reg + 1..*start_reg + arg_count], + ); json_extract(val.get_value(), reg_values, &state.json_cache) } @@ -4479,7 +4482,9 @@ pub fn op_function( 0 => Ok(Value::Null), _ => { let val = &state.registers[*start_reg]; - let reg_values = &state.registers[*start_reg + 1..*start_reg + arg_count]; + let reg_values = registers_to_ref_values( + &state.registers[*start_reg + 1..*start_reg + arg_count], + ); jsonb_extract(val.get_value(), reg_values, &state.json_cache) } @@ -4565,7 +4570,7 @@ pub fn op_function( } JsonFunc::JsonRemove => { if let Ok(json) = json_remove( - &state.registers[*start_reg..*start_reg + arg_count], + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]), &state.json_cache, ) { state.registers[*dest] = Register::Value(json); @@ -4575,7 +4580,7 @@ pub fn op_function( } JsonFunc::JsonbRemove => { if let Ok(json) = jsonb_remove( - &state.registers[*start_reg..*start_reg + arg_count], + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]), &state.json_cache, ) { state.registers[*dest] = Register::Value(json); @@ -4585,7 +4590,7 @@ pub fn op_function( } JsonFunc::JsonReplace => { if let Ok(json) = json_replace( - &state.registers[*start_reg..*start_reg + arg_count], + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]), &state.json_cache, ) { state.registers[*dest] = Register::Value(json); @@ -4595,7 +4600,7 @@ pub fn op_function( } JsonFunc::JsonbReplace => { if let Ok(json) = jsonb_replace( - &state.registers[*start_reg..*start_reg + arg_count], + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]), &state.json_cache, ) { state.registers[*dest] = Register::Value(json); @@ -4605,7 +4610,7 @@ pub fn op_function( } JsonFunc::JsonInsert => { if let Ok(json) = json_insert( - &state.registers[*start_reg..*start_reg + arg_count], + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]), &state.json_cache, ) { state.registers[*dest] = Register::Value(json); @@ -4615,7 +4620,7 @@ pub fn op_function( } JsonFunc::JsonbInsert => { if let Ok(json) = jsonb_insert( - &state.registers[*start_reg..*start_reg + arg_count], + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]), &state.json_cache, ) { state.registers[*dest] = Register::Value(json); @@ -4654,7 +4659,8 @@ pub fn op_function( if arg_count % 2 == 0 { bail_constraint_error!("json_set() needs an odd number of arguments") } - let reg_values = &state.registers[*start_reg..*start_reg + arg_count]; + let reg_values = + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]); let json_result = json_set(reg_values, &state.json_cache); @@ -4667,7 +4673,8 @@ pub fn op_function( if arg_count % 2 == 0 { bail_constraint_error!("json_set() needs an odd number of arguments") } - let reg_values = &state.registers[*start_reg..*start_reg + arg_count]; + let reg_values = + registers_to_ref_values(&state.registers[*start_reg..*start_reg + arg_count]); let json_result = jsonb_set(reg_values, &state.json_cache);