Introduce Register struct

OwnedValue has become a powerhouse of madness, mainly because I decided
to do it like that when I first introduced AggContext. I decided it was
enough and I introduced a `Register` struct that contains `OwnedValue`,
`Record` and `Aggregation`, this way we don't use `OwnedValue` for
everything make everyone's life harder.

This is the next step towards making ImmutableRecords the default
because I want to remove unnecessary allocations. Right now we clone
OwnedValues when we generate a record more than needed.
This commit is contained in:
Pere Diaz Bou
2025-03-26 14:52:35 +01:00
parent af6e9cd2c2
commit 9291f60722
18 changed files with 867 additions and 713 deletions

View File

@@ -160,7 +160,6 @@ impl LimboValue {
limbo_core::OwnedValue::Null => {
LimboValue::new(ValueType::Null, ValueUnion::from_null())
}
_ => unreachable!(),
}
}

View File

@@ -116,7 +116,6 @@ fn row_to_obj_array<'local>(
}
limbo_core::OwnedValue::Text(s) => env.new_string(s.as_str())?.into(),
limbo_core::OwnedValue::Blob(b) => env.byte_array_from_slice(&b)?.into(),
_ => unreachable!(),
};
if let Err(e) = env.set_object_array_element(&obj_array, i as i32, obj) {
eprintln!("Error on parsing row: {:?}", e);

View File

@@ -101,7 +101,6 @@ fn to_js_value(env: &napi::Env, value: &limbo_core::OwnedValue) -> JsUnknown {
limbo_core::OwnedValue::Blob(b) => {
env.create_buffer_copy(b.as_ref()).unwrap().into_unknown()
}
_ => env.get_null().unwrap().into_unknown(),
}
}

View File

@@ -333,7 +333,6 @@ fn row_to_py(py: Python, row: &limbo_core::Row) -> Result<PyObject> {
limbo_core::OwnedValue::Blob(b) => {
py_values.push(PyBytes::new(py, b.as_slice()).into())
}
_ => unreachable!(),
}
}
Ok(PyTuple::new(py, &py_values)

View File

@@ -236,8 +236,6 @@ impl Row {
limbo_core::OwnedValue::Float(f) => Ok(Value::Real(*f)),
limbo_core::OwnedValue::Text(text) => Ok(Value::Text(text.to_string())),
limbo_core::OwnedValue::Blob(items) => Ok(Value::Blob(items.to_vec())),
limbo_core::OwnedValue::Agg(_agg_context) => todo!(),
limbo_core::OwnedValue::Record(_record) => todo!(),
}
}
}

View File

@@ -191,7 +191,6 @@ fn to_js_value(value: &limbo_core::OwnedValue) -> JsValue {
limbo_core::OwnedValue::Float(f) => JsValue::from(*f),
limbo_core::OwnedValue::Text(t) => JsValue::from_str(t.as_str()),
limbo_core::OwnedValue::Blob(b) => js_sys::Uint8Array::from(b.as_slice()).into(),
_ => unreachable!(),
}
}

View File

@@ -717,7 +717,6 @@ impl<'a> Limbo<'a> {
OwnedValue::Blob(b) => {
format!("{}", String::from_utf8_lossy(b))
}
_ => unreachable!(),
}
.as_bytes(),
)?;
@@ -784,7 +783,6 @@ impl<'a> Limbo<'a> {
String::from_utf8_lossy(b).to_string(),
CellAlignment::Left,
),
_ => unreachable!(),
};
row.add_cell(
Cell::new(content)

View File

@@ -1,33 +1,33 @@
use crate::types::OwnedValue;
use crate::LimboError::InvalidModifier;
use crate::Result;
use crate::{types::OwnedValue, vdbe::Register};
use chrono::{
DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, TimeDelta, TimeZone, Timelike, Utc,
};
/// Execution of date/time/datetime functions
#[inline(always)]
pub fn exec_date(values: &[OwnedValue]) -> OwnedValue {
pub fn exec_date(values: &[Register]) -> OwnedValue {
exec_datetime(values, DateTimeOutput::Date)
}
#[inline(always)]
pub fn exec_time(values: &[OwnedValue]) -> OwnedValue {
pub fn exec_time(values: &[Register]) -> OwnedValue {
exec_datetime(values, DateTimeOutput::Time)
}
#[inline(always)]
pub fn exec_datetime_full(values: &[OwnedValue]) -> OwnedValue {
pub fn exec_datetime_full(values: &[Register]) -> OwnedValue {
exec_datetime(values, DateTimeOutput::DateTime)
}
#[inline(always)]
pub fn exec_strftime(values: &[OwnedValue]) -> OwnedValue {
pub fn exec_strftime(values: &[Register]) -> OwnedValue {
if values.is_empty() {
return OwnedValue::Null;
}
let format_str = match &values[0] {
let format_str = match &values[0].get_owned_value() {
OwnedValue::Text(text) => text.as_str().to_string(),
OwnedValue::Integer(num) => num.to_string(),
OwnedValue::Float(num) => format!("{:.14}", num),
@@ -45,7 +45,7 @@ enum DateTimeOutput {
StrfTime(String),
}
fn exec_datetime(values: &[OwnedValue], output_type: DateTimeOutput) -> OwnedValue {
fn exec_datetime(values: &[Register], output_type: DateTimeOutput) -> OwnedValue {
if values.is_empty() {
let now = parse_naive_date_time(&OwnedValue::build_text("now")).unwrap();
@@ -59,7 +59,7 @@ fn exec_datetime(values: &[OwnedValue], output_type: DateTimeOutput) -> OwnedVal
// Parse here
return OwnedValue::build_text(&formatted_str);
}
if let Some(mut dt) = parse_naive_date_time(&values[0]) {
if let Some(mut dt) = parse_naive_date_time(values[0].get_owned_value()) {
// if successful, treat subsequent entries as modifiers
modify_dt(&mut dt, &values[1..], output_type)
} else {
@@ -69,15 +69,11 @@ fn exec_datetime(values: &[OwnedValue], output_type: DateTimeOutput) -> OwnedVal
}
}
fn modify_dt(
dt: &mut NaiveDateTime,
mods: &[OwnedValue],
output_type: DateTimeOutput,
) -> OwnedValue {
fn modify_dt(dt: &mut NaiveDateTime, mods: &[Register], output_type: DateTimeOutput) -> OwnedValue {
let mut subsec_requested = false;
for modifier in mods {
if let OwnedValue::Text(ref text_rc) = modifier {
if let OwnedValue::Text(ref text_rc) = modifier.get_owned_value() {
// TODO: to prevent double conversion and properly support 'utc'/'localtime', we also
// need to keep track of the current timezone and apply it to the modifier.
match apply_modifier(dt, text_rc.as_str()) {
@@ -806,7 +802,7 @@ mod tests {
];
for (input, expected) in test_cases {
let result = exec_date(&[input.clone()]);
let result = exec_date(&[Register::OwnedValue(input.clone())]);
assert_eq!(
result,
OwnedValue::build_text(expected),
@@ -847,7 +843,7 @@ mod tests {
];
for case in invalid_cases.iter() {
let result = exec_date(&[case.clone()]);
let result = exec_date(&[Register::OwnedValue(case.clone())]);
match result {
OwnedValue::Text(ref result_str) if result_str.value.is_empty() => (),
_ => panic!(
@@ -960,7 +956,7 @@ mod tests {
];
for (input, expected) in test_cases {
let result = exec_time(&[input]);
let result = exec_time(&[Register::OwnedValue(input)]);
if let OwnedValue::Text(result_str) = result {
assert_eq!(result_str.as_str(), expected);
} else {
@@ -1000,7 +996,7 @@ mod tests {
];
for case in invalid_cases {
let result = exec_time(&[case.clone()]);
let result = exec_time(&[Register::OwnedValue(case.clone())]);
match result {
OwnedValue::Text(ref result_str) if result_str.value.is_empty() => (),
_ => panic!(
@@ -1302,8 +1298,8 @@ mod tests {
assert_eq!(dt, create_datetime(2023, 6, 15, 0, 0, 0));
}
fn text(value: &str) -> OwnedValue {
OwnedValue::build_text(value)
fn text(value: &str) -> Register {
Register::OwnedValue(OwnedValue::build_text(value))
}
fn format(dt: NaiveDateTime) -> String {
@@ -1321,7 +1317,7 @@ mod tests {
&[text("2023-06-15 12:30:45"), text("-1 day")],
DateTimeOutput::DateTime,
);
assert_eq!(result, text(&expected));
assert_eq!(result, *text(&expected).get_owned_value());
}
#[test]
@@ -1336,7 +1332,7 @@ mod tests {
],
DateTimeOutput::DateTime,
);
assert_eq!(result, text(&expected));
assert_eq!(result, *text(&expected).get_owned_value());
}
#[test]
@@ -1363,7 +1359,7 @@ mod tests {
],
DateTimeOutput::DateTime,
);
assert_eq!(result, text(&expected));
assert_eq!(result, *text(&expected).get_owned_value());
}
#[test]
@@ -1382,7 +1378,7 @@ mod tests {
],
DateTimeOutput::DateTime,
);
assert_eq!(result, text(&expected));
assert_eq!(result, *text(&expected).get_owned_value());
}
#[test]
@@ -1402,7 +1398,7 @@ mod tests {
],
DateTimeOutput::DateTime,
);
assert_eq!(result, text(&expected));
assert_eq!(result, *text(&expected).get_owned_value());
}
#[test]
@@ -1414,12 +1410,13 @@ mod tests {
);
assert_eq!(
result_local,
text(
*text(
&dt.and_utc()
.with_timezone(&chrono::Local)
.format("%Y-%m-%d %H:%M:%S")
.to_string()
)
.get_owned_value()
);
// TODO: utc modifier assumes time given is not already utc
// add test when fixed in the future
@@ -1457,7 +1454,7 @@ mod tests {
.unwrap();
let expected = format(max);
let result = exec_datetime(&[text("9999-12-31 23:59:59")], DateTimeOutput::DateTime);
assert_eq!(result, text(&expected));
assert_eq!(result, *text(&expected).get_owned_value());
}
// leap second
@@ -1469,7 +1466,7 @@ mod tests {
.unwrap();
let expected = String::new(); // SQLite ignores leap seconds
let result = exec_datetime(&[text(&leap_second.to_string())], DateTimeOutput::DateTime);
assert_eq!(result, text(&expected));
assert_eq!(result, *text(&expected).get_owned_value());
}
#[test]

View File

@@ -1,12 +1,13 @@
use crate::types::OwnedValue;
use crate::vdbe::Register;
use crate::LimboError;
#[inline(always)]
pub fn exec_printf(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
pub fn exec_printf(values: &[Register]) -> crate::Result<OwnedValue> {
if values.is_empty() {
return Ok(OwnedValue::Null);
}
let format_str = match &values[0] {
let format_str = match &values[0].get_owned_value() {
OwnedValue::Text(t) => t.as_str(),
_ => return Ok(OwnedValue::Null),
};
@@ -30,7 +31,7 @@ pub fn exec_printf(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
if args_index >= values.len() {
return Err(LimboError::InvalidArgument("not enough arguments".into()));
}
match &values[args_index] {
match &values[args_index].get_owned_value() {
OwnedValue::Integer(i) => result.push_str(&i.to_string()),
OwnedValue::Float(f) => result.push_str(&f.to_string()),
_ => result.push_str("0".into()),
@@ -41,7 +42,7 @@ pub fn exec_printf(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
if args_index >= values.len() {
return Err(LimboError::InvalidArgument("not enough arguments".into()));
}
match &values[args_index] {
match &values[args_index].get_owned_value() {
OwnedValue::Text(t) => result.push_str(t.as_str()),
OwnedValue::Null => result.push_str("(null)"),
v => result.push_str(&v.to_string()),
@@ -52,7 +53,7 @@ pub fn exec_printf(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
if args_index >= values.len() {
return Err(LimboError::InvalidArgument("not enough arguments".into()));
}
match &values[args_index] {
match &values[args_index].get_owned_value() {
OwnedValue::Float(f) => result.push_str(&f.to_string()),
OwnedValue::Integer(i) => result.push_str(&(*i as f64).to_string()),
_ => result.push_str("0.0".into()),
@@ -78,16 +79,16 @@ pub fn exec_printf(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
mod tests {
use super::*;
fn text(value: &str) -> OwnedValue {
OwnedValue::build_text(value)
fn text(value: &str) -> Register {
Register::OwnedValue(OwnedValue::build_text(value))
}
fn integer(value: i64) -> OwnedValue {
OwnedValue::Integer(value)
fn integer(value: i64) -> Register {
Register::OwnedValue(OwnedValue::Integer(value))
}
fn float(value: f64) -> OwnedValue {
OwnedValue::Float(value)
fn float(value: f64) -> Register {
Register::OwnedValue(OwnedValue::Float(value))
}
#[test]
@@ -99,7 +100,7 @@ mod tests {
fn test_printf_basic_string() {
assert_eq!(
exec_printf(&[text("Hello World")]).unwrap(),
text("Hello World")
*text("Hello World").get_owned_value()
);
}
@@ -118,7 +119,7 @@ mod tests {
),
// String with null value
(
vec![text("Hello, %s!"), OwnedValue::Null],
vec![text("Hello, %s!"), Register::OwnedValue(OwnedValue::Null)],
text("Hello, (null)!"),
),
// String with number conversion
@@ -127,7 +128,7 @@ mod tests {
(vec![text("100%% complete")], text("100% complete")),
];
for (input, output) in test_cases {
assert_eq!(exec_printf(&input).unwrap(), output);
assert_eq!(exec_printf(&input).unwrap(), *output.get_owned_value());
}
}
@@ -150,7 +151,7 @@ mod tests {
),
];
for (input, output) in test_cases {
assert_eq!(exec_printf(&input).unwrap(), output)
assert_eq!(exec_printf(&input).unwrap(), *output.get_owned_value())
}
}
@@ -179,7 +180,7 @@ mod tests {
];
for (input, expected) in test_cases {
assert_eq!(exec_printf(&input).unwrap(), expected);
assert_eq!(exec_printf(&input).unwrap(), *expected.get_owned_value());
}
}
@@ -214,7 +215,7 @@ mod tests {
];
for (input, expected) in test_cases {
assert_eq!(exec_printf(&input).unwrap(), expected);
assert_eq!(exec_printf(&input).unwrap(), *expected.get_owned_value());
}
}
@@ -256,7 +257,7 @@ mod tests {
];
for (input, expected) in test_cases {
assert_eq!(exec_printf(&input).unwrap(), expected);
assert_eq!(exec_printf(&input).unwrap(), *expected.get_owned_value());
}
}
}

View File

@@ -1,6 +1,6 @@
use std::{collections::VecDeque, rc::Rc};
use crate::types::OwnedValue;
use crate::{types::OwnedValue, vdbe::Register};
use super::{
convert_dbtype_to_jsonb, convert_json_to_db_type, curry_convert_dbtype_to_jsonb,
@@ -152,15 +152,15 @@ impl JsonPatcher {
}
}
pub fn json_remove(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
pub fn json_remove(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
if args.is_empty() {
return Ok(OwnedValue::Null);
}
let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict);
let mut json = json_cache.get_or_insert_with(&args[0], make_jsonb_fn)?;
let mut json = json_cache.get_or_insert_with(&args[0].get_owned_value(), make_jsonb_fn)?;
for arg in &args[1..] {
if let Some(path) = json_path_from_owned_value(arg, true)? {
if let Some(path) = json_path_from_owned_value(arg.get_owned_value(), true)? {
let mut op = DeleteOperation::new();
let _ = json.operate_on_path(&path, &mut op);
}
@@ -171,15 +171,15 @@ pub fn json_remove(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Re
json_string_to_db_type(json, el_type, OutputVariant::String)
}
pub fn jsonb_remove(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
pub fn jsonb_remove(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
if args.is_empty() {
return Ok(OwnedValue::Null);
}
let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict);
let mut json = json_cache.get_or_insert_with(&args[0], make_jsonb_fn)?;
let mut json = json_cache.get_or_insert_with(&args[0].get_owned_value(), make_jsonb_fn)?;
for arg in &args[1..] {
if let Some(path) = json_path_from_owned_value(arg, true)? {
if let Some(path) = json_path_from_owned_value(arg.get_owned_value(), true)? {
let mut op = DeleteOperation::new();
let _ = json.operate_on_path(&path, &mut op);
}
@@ -188,18 +188,18 @@ pub fn jsonb_remove(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::R
Ok(OwnedValue::Blob(Rc::new(json.data())))
}
pub fn json_replace(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
pub fn json_replace(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
if args.is_empty() {
return Ok(OwnedValue::Null);
}
let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict);
let mut json = json_cache.get_or_insert_with(&args[0], make_jsonb_fn)?;
let mut json = json_cache.get_or_insert_with(&args[0].get_owned_value(), make_jsonb_fn)?;
let other = args[1..].chunks_exact(2);
for chunk in other {
let path = json_path_from_owned_value(&chunk[0], true)?;
let path = json_path_from_owned_value(&chunk[0].get_owned_value(), true)?;
let value = convert_dbtype_to_jsonb(&chunk[1], Conv::NotStrict)?;
let value = convert_dbtype_to_jsonb(&chunk[1].get_owned_value(), Conv::NotStrict)?;
if let Some(path) = path {
let mut op = ReplaceOperation::new(value);
@@ -212,17 +212,17 @@ pub fn json_replace(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::R
json_string_to_db_type(json, el_type, super::OutputVariant::String)
}
pub fn jsonb_replace(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
pub fn jsonb_replace(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
if args.is_empty() {
return Ok(OwnedValue::Null);
}
let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict);
let mut json = json_cache.get_or_insert_with(&args[0], make_jsonb_fn)?;
let mut json = json_cache.get_or_insert_with(&args[0].get_owned_value(), make_jsonb_fn)?;
let other = args[1..].chunks_exact(2);
for chunk in other {
let path = json_path_from_owned_value(&chunk[0], true)?;
let value = convert_dbtype_to_jsonb(&chunk[1], Conv::NotStrict)?;
let path = json_path_from_owned_value(&chunk[0].get_owned_value(), true)?;
let value = convert_dbtype_to_jsonb(&chunk[1].get_owned_value(), Conv::NotStrict)?;
if let Some(path) = path {
let mut op = ReplaceOperation::new(value);
@@ -235,17 +235,17 @@ pub fn jsonb_replace(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::
json_string_to_db_type(json, el_type, OutputVariant::Binary)
}
pub fn json_insert(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
pub fn json_insert(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
if args.is_empty() {
return Ok(OwnedValue::Null);
}
let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict);
let mut json = json_cache.get_or_insert_with(&args[0], make_jsonb_fn)?;
let mut json = json_cache.get_or_insert_with(&args[0].get_owned_value(), make_jsonb_fn)?;
let other = args[1..].chunks_exact(2);
for chunk in other {
let path = json_path_from_owned_value(&chunk[0], true)?;
let value = convert_dbtype_to_jsonb(&chunk[1], Conv::NotStrict)?;
let path = json_path_from_owned_value(&chunk[0].get_owned_value(), true)?;
let value = convert_dbtype_to_jsonb(&chunk[1].get_owned_value(), Conv::NotStrict)?;
if let Some(path) = path {
let mut op = InsertOperation::new(value);
@@ -258,17 +258,17 @@ pub fn json_insert(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Re
json_string_to_db_type(json, el_type, OutputVariant::String)
}
pub fn jsonb_insert(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
pub fn jsonb_insert(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
if args.is_empty() {
return Ok(OwnedValue::Null);
}
let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict);
let mut json = json_cache.get_or_insert_with(&args[0], make_jsonb_fn)?;
let mut json = json_cache.get_or_insert_with(&args[0].get_owned_value(), make_jsonb_fn)?;
let other = args[1..].chunks_exact(2);
for chunk in other {
let path = json_path_from_owned_value(&chunk[0], true)?;
let value = convert_dbtype_to_jsonb(&chunk[1], Conv::NotStrict)?;
let path = json_path_from_owned_value(&chunk[0].get_owned_value(), true)?;
let value = convert_dbtype_to_jsonb(&chunk[1].get_owned_value(), Conv::NotStrict)?;
if let Some(path) = path {
let mut op = InsertOperation::new(value);
@@ -608,7 +608,10 @@ mod tests {
#[test]
fn test_json_remove_array_element() {
let args = vec![create_json(r#"[1,2,3,4,5]"#), create_text("$[2]")];
let args = vec![
Register::OwnedValue(create_json(r#"[1,2,3,4,5]"#)),
Register::OwnedValue(create_text("$[2]")),
];
let json_cache = JsonCacheCell::new();
let result = json_remove(&args, &json_cache).unwrap();
@@ -621,9 +624,9 @@ mod tests {
#[test]
fn test_json_remove_multiple_paths() {
let args = vec![
create_json(r#"{"a": 1, "b": 2, "c": 3}"#),
create_text("$.a"),
create_text("$.c"),
Register::OwnedValue(create_json(r#"{"a": 1, "b": 2, "c": 3}"#)),
Register::OwnedValue(create_text("$.a")),
Register::OwnedValue(create_text("$.c")),
];
let json_cache = JsonCacheCell::new();
@@ -637,8 +640,8 @@ mod tests {
#[test]
fn test_json_remove_nested_paths() {
let args = vec![
create_json(r#"{"a": {"b": {"c": 1, "d": 2}}}"#),
create_text("$.a.b.c"),
Register::OwnedValue(create_json(r#"{"a": {"b": {"c": 1, "d": 2}}}"#)),
Register::OwnedValue(create_text("$.a.b.c")),
];
let json_cache = JsonCacheCell::new();
@@ -652,8 +655,8 @@ mod tests {
#[test]
fn test_json_remove_duplicate_keys() {
let args = vec![
create_json(r#"{"a": 1, "a": 2, "a": 3}"#),
create_text("$.a"),
Register::OwnedValue(create_json(r#"{"a": 1, "a": 2, "a": 3}"#)),
Register::OwnedValue(create_text("$.a")),
];
let json_cache = JsonCacheCell::new();
@@ -667,8 +670,8 @@ mod tests {
#[test]
fn test_json_remove_invalid_path() {
let args = vec![
create_json(r#"{"a": 1}"#),
OwnedValue::Integer(42), // Invalid path type
Register::OwnedValue(create_json(r#"{"a": 1}"#)),
Register::OwnedValue(OwnedValue::Integer(42)), // Invalid path type
];
let json_cache = JsonCacheCell::new();
@@ -678,10 +681,12 @@ mod tests {
#[test]
fn test_json_remove_complex_case() {
let args = vec![
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"),
Register::OwnedValue(create_json(
r#"{"a":[1,2,3],"b":{"x":1,"x":2},"c":[{"y":1},{"y":2}]}"#,
)),
Register::OwnedValue(create_text("$.a[1]")),
Register::OwnedValue(create_text("$.b.x")),
Register::OwnedValue(create_text("$.c[0].y")),
];
let json_cache = JsonCacheCell::new();

View File

@@ -15,6 +15,7 @@ pub use crate::json::json_operations::{
use crate::json::json_path::{json_path, JsonPath, PathElement};
pub use crate::json::ser::to_string;
use crate::types::{OwnedValue, OwnedValueType, Text, TextSubtype};
use crate::vdbe::Register;
use crate::{bail_parse_error, json::de::ordered_object};
pub use json_cache::JsonCacheCell;
use jsonb::{ElementType, Jsonb, JsonbHeader, PathOperationMode, SearchOperation, SetOperation};
@@ -131,9 +132,6 @@ fn convert_dbtype_to_jsonb(val: &OwnedValue, strict: Conv) -> crate::Result<Json
json.is_valid()?;
Ok(json)
}
OwnedValue::Record(_) | OwnedValue::Agg(_) => {
bail_constraint_error!("Wrong number of arguments");
}
OwnedValue::Null => Ok(Jsonb::from_raw_data(
JsonbHeader::make_null().into_bytes().as_bytes(),
)),
@@ -163,18 +161,17 @@ fn get_json_value(json_value: &OwnedValue) -> crate::Result<Val> {
OwnedValue::Null => Ok(Val::Null),
OwnedValue::Float(f) => Ok(Val::Float(*f)),
OwnedValue::Integer(i) => Ok(Val::Integer(*i)),
_ => Ok(Val::String(json_value.to_string())),
}
}
pub fn json_array(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
pub fn json_array(values: &[Register]) -> crate::Result<OwnedValue> {
let mut json = Jsonb::make_empty_array(values.len());
for value in values.iter() {
if matches!(value, OwnedValue::Blob(_)) {
if matches!(value.get_owned_value(), OwnedValue::Blob(_)) {
crate::bail_constraint_error!("JSON cannot hold BLOB values")
}
let value = convert_dbtype_to_jsonb(value, Conv::NotStrict)?;
let value = convert_dbtype_to_jsonb(value.get_owned_value(), Conv::NotStrict)?;
json.append_jsonb_to_end(value.data());
}
json.finalize_unsafe(ElementType::ARRAY)?;
@@ -182,14 +179,14 @@ pub fn json_array(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
json_string_to_db_type(json, ElementType::ARRAY, OutputVariant::ElementType)
}
pub fn jsonb_array(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
pub fn jsonb_array(values: &[Register]) -> crate::Result<OwnedValue> {
let mut json = Jsonb::make_empty_array(values.len());
for value in values.iter() {
if matches!(value, OwnedValue::Blob(_)) {
if matches!(value.get_owned_value(), OwnedValue::Blob(_)) {
crate::bail_constraint_error!("JSON cannot hold BLOB values")
}
let value = convert_dbtype_to_jsonb(value, Conv::NotStrict)?;
let value = convert_dbtype_to_jsonb(value.get_owned_value(), Conv::NotStrict)?;
json.append_jsonb_to_end(value.data());
}
json.finalize_unsafe(ElementType::ARRAY)?;
@@ -222,19 +219,19 @@ pub fn json_array_length(
Ok(OwnedValue::Null)
}
pub fn json_set(args: &[OwnedValue], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
pub fn json_set(args: &[Register], json_cache: &JsonCacheCell) -> crate::Result<OwnedValue> {
if args.is_empty() {
return Ok(OwnedValue::Null);
}
let make_jsonb_fn = curry_convert_dbtype_to_jsonb(Conv::Strict);
let mut json = json_cache.get_or_insert_with(&args[0], make_jsonb_fn)?;
let mut json = json_cache.get_or_insert_with(&args[0].get_owned_value(), make_jsonb_fn)?;
let other = args[1..].chunks_exact(2);
for chunk in other {
let path = json_path_from_owned_value(&chunk[0], true)?;
let path = json_path_from_owned_value(&chunk[0].get_owned_value(), true)?;
let value = convert_dbtype_to_jsonb(&chunk[1], Conv::NotStrict)?;
let value = convert_dbtype_to_jsonb(&chunk[1].get_owned_value(), Conv::NotStrict)?;
let mut op = SetOperation::new(value);
if let Some(path) = path {
let _ = json.operate_on_path(&path, &mut op);
@@ -313,7 +310,7 @@ pub fn json_arrow_shift_extract(
/// https://sqlite.org/json1.html#the_json_extract_function
pub fn json_extract(
value: &OwnedValue,
paths: &[OwnedValue],
paths: &[Register],
json_cache: &JsonCacheCell,
) -> crate::Result<OwnedValue> {
if let OwnedValue::Null = value {
@@ -334,7 +331,7 @@ pub fn json_extract(
pub fn jsonb_extract(
value: &OwnedValue,
paths: &[OwnedValue],
paths: &[Register],
json_cache: &JsonCacheCell,
) -> crate::Result<OwnedValue> {
if let OwnedValue::Null = value {
@@ -353,13 +350,10 @@ pub fn jsonb_extract(
Ok(result)
}
fn jsonb_extract_internal(
value: Jsonb,
paths: &[OwnedValue],
) -> crate::Result<(Jsonb, ElementType)> {
fn jsonb_extract_internal(value: Jsonb, paths: &[Register]) -> crate::Result<(Jsonb, ElementType)> {
let null = Jsonb::from_raw_data(JsonbHeader::make_null().into_bytes().as_bytes());
if paths.len() == 1 {
if let Some(path) = json_path_from_owned_value(&paths[0], true)? {
if let Some(path) = json_path_from_owned_value(&paths[0].get_owned_value(), true)? {
let mut json = value;
let mut op = SearchOperation::new(json.len());
@@ -383,7 +377,9 @@ fn jsonb_extract_internal(
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_owned_value(p, true));
let paths = paths
.iter()
.map(|p| json_path_from_owned_value(p.get_owned_value(), true));
for path in paths {
if let Some(path) = path? {
let mut op = SearchOperation::new(json.len());
@@ -581,19 +577,19 @@ pub fn json_error_position(json: &OwnedValue) -> crate::Result<OwnedValue> {
/// 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: &[OwnedValue]) -> crate::Result<OwnedValue> {
pub fn json_object(values: &[Register]) -> crate::Result<OwnedValue> {
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].value_type() != OwnedValueType::Text {
if chunk[0].get_owned_value().value_type() != OwnedValueType::Text {
bail_constraint_error!("json_object() labels must be TEXT")
}
let key = convert_dbtype_to_jsonb(&chunk[0], Conv::ToString)?;
let key = convert_dbtype_to_jsonb(&chunk[0].get_owned_value(), Conv::ToString)?;
json.append_jsonb_to_end(key.data());
let value = convert_dbtype_to_jsonb(&chunk[1], Conv::NotStrict)?;
let value = convert_dbtype_to_jsonb(&chunk[1].get_owned_value(), Conv::NotStrict)?;
json.append_jsonb_to_end(value.data());
}
@@ -602,19 +598,19 @@ pub fn json_object(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
json_string_to_db_type(json, ElementType::OBJECT, OutputVariant::String)
}
pub fn jsonb_object(values: &[OwnedValue]) -> crate::Result<OwnedValue> {
pub fn jsonb_object(values: &[Register]) -> crate::Result<OwnedValue> {
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].value_type() != OwnedValueType::Text {
if chunk[0].get_owned_value().value_type() != OwnedValueType::Text {
bail_constraint_error!("json_object() labels must be TEXT")
}
let key = convert_dbtype_to_jsonb(&chunk[0], Conv::ToString)?;
let key = convert_dbtype_to_jsonb(&chunk[0].get_owned_value(), Conv::ToString)?;
json.append_jsonb_to_end(key.data());
let value = convert_dbtype_to_jsonb(&chunk[1], Conv::NotStrict)?;
let value = convert_dbtype_to_jsonb(&chunk[1].get_owned_value(), Conv::NotStrict)?;
json.append_jsonb_to_end(value.data());
}
@@ -663,9 +659,6 @@ pub fn json_quote(value: &OwnedValue) -> crate::Result<OwnedValue> {
OwnedValue::Float(ref float) => Ok(OwnedValue::Float(float.to_owned())),
OwnedValue::Blob(_) => crate::bail_constraint_error!("JSON cannot hold BLOB values"),
OwnedValue::Null => Ok(OwnedValue::build_text("null")),
_ => {
unreachable!()
}
}
}
@@ -806,9 +799,14 @@ mod tests {
#[test]
fn test_json_array_simple() {
let text = OwnedValue::build_text("value1");
let json = OwnedValue::Text(Text::json("\"value2\"".to_string()));
let input = vec![text, json, OwnedValue::Integer(1), OwnedValue::Float(1.1)];
let text = Register::OwnedValue(OwnedValue::build_text("value1"));
let json = Register::OwnedValue(OwnedValue::Text(Text::json("\"value2\"".to_string())));
let input = vec![
text,
json,
Register::OwnedValue(OwnedValue::Integer(1)),
Register::OwnedValue(OwnedValue::Float(1.1)),
];
let result = json_array(&input).unwrap();
if let OwnedValue::Text(res) = result {
@@ -834,7 +832,7 @@ mod tests {
#[test]
fn test_json_array_blob_invalid() {
let blob = OwnedValue::Blob(Rc::new("1".as_bytes().to_vec()));
let blob = Register::OwnedValue(OwnedValue::Blob(Rc::new("1".as_bytes().to_vec())));
let input = vec![blob];
@@ -962,7 +960,7 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_extract(
&OwnedValue::build_text("{\"a\":2}"),
&[OwnedValue::build_text("$.x")],
&[Register::OwnedValue(OwnedValue::build_text("$.x"))],
&json_cache,
);
@@ -976,7 +974,7 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_extract(
&OwnedValue::build_text("{\"a\":2}"),
&[OwnedValue::Null],
&[Register::OwnedValue(OwnedValue::Null)],
&json_cache,
);
@@ -991,7 +989,7 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_extract(
&OwnedValue::build_text("{\"a\":2}"),
&[OwnedValue::Float(1.1)],
&[Register::OwnedValue(OwnedValue::Float(1.1))],
&json_cache,
);
@@ -1052,8 +1050,8 @@ mod tests {
#[test]
fn test_json_object_simple() {
let key = OwnedValue::build_text("key");
let value = OwnedValue::build_text("value");
let key = Register::OwnedValue(OwnedValue::build_text("key"));
let value = Register::OwnedValue(OwnedValue::build_text("value"));
let input = vec![key, value];
let result = json_object(&input).unwrap();
@@ -1077,16 +1075,16 @@ mod tests {
let null_value = OwnedValue::Null;
let input = vec![
text_key,
text_value,
json_key,
json_value,
integer_key,
integer_value,
float_key,
float_value,
null_key,
null_value,
Register::OwnedValue(text_key),
Register::OwnedValue(text_value),
Register::OwnedValue(json_key),
Register::OwnedValue(json_value),
Register::OwnedValue(integer_key),
Register::OwnedValue(integer_value),
Register::OwnedValue(float_key),
Register::OwnedValue(float_value),
Register::OwnedValue(null_key),
Register::OwnedValue(null_value),
];
let result = json_object(&input).unwrap();
@@ -1101,8 +1099,10 @@ mod tests {
#[test]
fn test_json_object_json_value_is_rendered_as_json() {
let key = OwnedValue::build_text("key");
let value = OwnedValue::Text(Text::json(r#"{"json":"value"}"#.to_string()));
let key = Register::OwnedValue(OwnedValue::build_text("key"));
let value = Register::OwnedValue(OwnedValue::Text(Text::json(
r#"{"json":"value"}"#.to_string(),
)));
let input = vec![key, value];
let result = json_object(&input).unwrap();
@@ -1114,8 +1114,8 @@ mod tests {
#[test]
fn test_json_object_json_text_value_is_rendered_as_regular_text() {
let key = OwnedValue::build_text("key");
let value = OwnedValue::Text(Text::new(r#"{"json":"value"}"#));
let key = Register::OwnedValue(OwnedValue::build_text("key"));
let value = Register::OwnedValue(OwnedValue::Text(Text::new(r#"{"json":"value"}"#)));
let input = vec![key, value];
let result = json_object(&input).unwrap();
@@ -1127,12 +1127,12 @@ mod tests {
#[test]
fn test_json_object_nested() {
let key = OwnedValue::build_text("key");
let value = OwnedValue::build_text("value");
let key = Register::OwnedValue(OwnedValue::build_text("key"));
let value = Register::OwnedValue(OwnedValue::build_text("value"));
let input = vec![key, value];
let parent_key = OwnedValue::build_text("parent_key");
let parent_value = json_object(&input).unwrap();
let parent_key = Register::OwnedValue(OwnedValue::build_text("parent_key"));
let parent_value = Register::OwnedValue(json_object(&input).unwrap());
let parent_input = vec![parent_key, parent_value];
let result = json_object(&parent_input).unwrap();
@@ -1145,8 +1145,8 @@ mod tests {
#[test]
fn test_json_object_duplicated_keys() {
let key = OwnedValue::build_text("key");
let value = OwnedValue::build_text("value");
let key = Register::OwnedValue(OwnedValue::build_text("key"));
let value = Register::OwnedValue(OwnedValue::build_text("value"));
let input = vec![key.clone(), value.clone(), key, value];
let result = json_object(&input).unwrap();
@@ -1169,8 +1169,8 @@ mod tests {
#[test]
fn test_json_object_non_text_key() {
let key = OwnedValue::Integer(1);
let value = OwnedValue::build_text("value");
let key = Register::OwnedValue(OwnedValue::Integer(1));
let value = Register::OwnedValue(OwnedValue::build_text("value"));
let input = vec![key, value];
match json_object(&input) {
@@ -1181,8 +1181,8 @@ mod tests {
#[test]
fn test_json_odd_number_of_values() {
let key = OwnedValue::build_text("key");
let value = OwnedValue::build_text("value");
let key = Register::OwnedValue(OwnedValue::build_text("key"));
let value = Register::OwnedValue(OwnedValue::build_text("value"));
let input = vec![key.clone(), value, key];
assert!(json_object(&input).is_err());
@@ -1320,9 +1320,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("{}"),
OwnedValue::build_text("$.field"),
OwnedValue::build_text("value"),
Register::OwnedValue(OwnedValue::build_text("{}")),
Register::OwnedValue(OwnedValue::build_text("$.field")),
Register::OwnedValue(OwnedValue::build_text("value")),
],
&json_cache,
);
@@ -1337,9 +1337,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text(r#"{"field":"old_value"}"#),
OwnedValue::build_text("$.field"),
OwnedValue::build_text("new_value"),
Register::OwnedValue(OwnedValue::build_text(r#"{"field":"old_value"}"#)),
Register::OwnedValue(OwnedValue::build_text("$.field")),
Register::OwnedValue(OwnedValue::build_text("new_value")),
],
&json_cache,
);
@@ -1357,9 +1357,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("{}"),
OwnedValue::build_text("$.object.doesnt.exist"),
OwnedValue::build_text("value"),
Register::OwnedValue(OwnedValue::build_text("{}")),
Register::OwnedValue(OwnedValue::build_text("$.object.doesnt.exist")),
Register::OwnedValue(OwnedValue::build_text("value")),
],
&json_cache,
);
@@ -1377,9 +1377,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("[]"),
OwnedValue::build_text("$[0]"),
OwnedValue::build_text("value"),
Register::OwnedValue(OwnedValue::build_text("[]")),
Register::OwnedValue(OwnedValue::build_text("$[0]")),
Register::OwnedValue(OwnedValue::build_text("value")),
],
&json_cache,
);
@@ -1394,9 +1394,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("{}"),
OwnedValue::build_text("$.some_array[0]"),
OwnedValue::Integer(123),
Register::OwnedValue(OwnedValue::build_text("{}")),
Register::OwnedValue(OwnedValue::build_text("$.some_array[0]")),
Register::OwnedValue(OwnedValue::Integer(123)),
],
&json_cache,
);
@@ -1414,9 +1414,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("[123]"),
OwnedValue::build_text("$[1]"),
OwnedValue::Integer(456),
Register::OwnedValue(OwnedValue::build_text("[123]")),
Register::OwnedValue(OwnedValue::build_text("$[1]")),
Register::OwnedValue(OwnedValue::Integer(456)),
],
&json_cache,
);
@@ -1431,9 +1431,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("[123]"),
OwnedValue::build_text("$[200]"),
OwnedValue::Integer(456),
Register::OwnedValue(OwnedValue::build_text("[123]")),
Register::OwnedValue(OwnedValue::build_text("$[200]")),
Register::OwnedValue(OwnedValue::Integer(456)),
],
&json_cache,
);
@@ -1448,9 +1448,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("[123]"),
OwnedValue::build_text("$[0]"),
OwnedValue::Integer(456),
Register::OwnedValue(OwnedValue::build_text("[123]")),
Register::OwnedValue(OwnedValue::build_text("$[0]")),
Register::OwnedValue(OwnedValue::Integer(456)),
],
&json_cache,
);
@@ -1465,9 +1465,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("{}"),
OwnedValue::Null,
OwnedValue::Integer(456),
Register::OwnedValue(OwnedValue::build_text("{}")),
Register::OwnedValue(OwnedValue::Null),
Register::OwnedValue(OwnedValue::Integer(456)),
],
&json_cache,
);
@@ -1482,11 +1482,11 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("[123]"),
OwnedValue::build_text("$[0]"),
OwnedValue::Integer(456),
OwnedValue::build_text("$[1]"),
OwnedValue::Integer(789),
Register::OwnedValue(OwnedValue::build_text("[123]")),
Register::OwnedValue(OwnedValue::build_text("$[0]")),
Register::OwnedValue(OwnedValue::Integer(456)),
Register::OwnedValue(OwnedValue::build_text("$[1]")),
Register::OwnedValue(OwnedValue::Integer(789)),
],
&json_cache,
);
@@ -1501,9 +1501,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("{}"),
OwnedValue::build_text("$.object[0].field"),
OwnedValue::Integer(123),
Register::OwnedValue(OwnedValue::build_text("{}")),
Register::OwnedValue(OwnedValue::build_text("$.object[0].field")),
Register::OwnedValue(OwnedValue::Integer(123)),
],
&json_cache,
);
@@ -1521,9 +1521,9 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("{}"),
OwnedValue::build_text("$.object[0][0]"),
OwnedValue::Integer(123),
Register::OwnedValue(OwnedValue::build_text("{}")),
Register::OwnedValue(OwnedValue::build_text("$.object[0][0]")),
Register::OwnedValue(OwnedValue::Integer(123)),
],
&json_cache,
);
@@ -1538,11 +1538,11 @@ mod tests {
let json_cache = JsonCacheCell::new();
let result = json_set(
&[
OwnedValue::build_text("{}"),
OwnedValue::build_text("$.object[123].another"),
OwnedValue::build_text("value"),
OwnedValue::build_text("$.field"),
OwnedValue::build_text("value"),
Register::OwnedValue(OwnedValue::build_text("{}")),
Register::OwnedValue(OwnedValue::build_text("$.object[123].another")),
Register::OwnedValue(OwnedValue::build_text("value")),
Register::OwnedValue(OwnedValue::build_text("$.field")),
Register::OwnedValue(OwnedValue::build_text("value")),
],
&json_cache,
);

View File

@@ -76,8 +76,6 @@ pub enum OwnedValue {
Float(f64),
Text(Text),
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(Record),
}
#[derive(Debug, Clone, PartialEq)]
@@ -130,8 +128,6 @@ impl OwnedValue {
OwnedValue::Float(_) => OwnedValueType::Float,
OwnedValue::Text(_) => OwnedValueType::Text,
OwnedValue::Blob(_) => OwnedValueType::Blob,
OwnedValue::Agg(_) => OwnedValueType::Null, // Map Agg to Null for FFI
OwnedValue::Record(_) => OwnedValueType::Null, // Map Record to Null for FFI
}
}
}
@@ -160,18 +156,6 @@ impl Display for OwnedValue {
Self::Float(fl) => write!(f, "{:?}", fl),
Self::Text(s) => write!(f, "{}", s.as_str()),
Self::Blob(b) => write!(f, "{}", String::from_utf8_lossy(b)),
Self::Agg(a) => match a.as_ref() {
AggContext::Avg(acc, _count) => write!(f, "{}", acc),
AggContext::Sum(acc) => write!(f, "{}", acc),
AggContext::Count(count) => write!(f, "{}", count),
AggContext::Max(max) => write!(f, "{}", max.as_ref().unwrap_or(&Self::Null)),
AggContext::Min(min) => write!(f, "{}", min.as_ref().unwrap_or(&Self::Null)),
AggContext::GroupConcat(s) => write!(f, "{}", s),
AggContext::External(v) => {
write!(f, "{}", v.finalized_value.as_ref().unwrap_or(&Self::Null))
}
},
Self::Record(r) => write!(f, "{:?}", r),
}
}
}
@@ -184,8 +168,6 @@ impl OwnedValue {
Self::Float(fl) => ExtValue::from_float(*fl),
Self::Text(text) => ExtValue::from_text(text.as_str().to_string()),
Self::Blob(blob) => ExtValue::from_blob(blob.to_vec()),
Self::Agg(_) => todo!(),
Self::Record(_) => todo!("Record values not yet supported"),
}
}
@@ -290,9 +272,6 @@ impl PartialEq<OwnedValue> for OwnedValue {
}
(Self::Blob(blob_left), Self::Blob(blob_right)) => blob_left.eq(blob_right),
(Self::Null, Self::Null) => true,
(Self::Agg(a), Self::Agg(b)) => a.eq(b),
(Self::Agg(a), other) => a.final_value().eq(other),
(other, Self::Agg(b)) => other.eq(b.final_value()),
_ => false,
}
}
@@ -335,9 +314,6 @@ impl PartialOrd<OwnedValue> for OwnedValue {
(Self::Null, Self::Null) => Some(std::cmp::Ordering::Equal),
(Self::Null, _) => Some(std::cmp::Ordering::Less),
(_, Self::Null) => Some(std::cmp::Ordering::Greater),
(Self::Agg(a), Self::Agg(b)) => a.partial_cmp(b),
(Self::Agg(a), other) => a.final_value().partial_cmp(other),
(other, Self::Agg(b)) => other.partial_cmp(b.final_value()),
other => todo!("{:?}", other),
}
}
@@ -836,8 +812,6 @@ impl From<&OwnedValue> for SerialType {
OwnedValue::Blob(b) => SerialType::Blob {
content_size: b.len(),
},
OwnedValue::Agg(_) => unreachable!(),
OwnedValue::Record(_) => unreachable!(),
}
}
}
@@ -896,9 +870,6 @@ impl Record {
OwnedValue::Float(f) => buf.extend_from_slice(&f.to_be_bytes()),
OwnedValue::Text(t) => buf.extend_from_slice(&t.value),
OwnedValue::Blob(b) => buf.extend_from_slice(b),
// non serializable
OwnedValue::Agg(_) => unreachable!(),
OwnedValue::Record(_) => unreachable!(),
};
}

View File

@@ -5,18 +5,6 @@ use crate::storage::wal::CheckpointMode;
use crate::types::{OwnedValue, Record};
use limbo_macros::Description;
macro_rules! final_agg_values {
($var:ident) => {
if let OwnedValue::Agg(agg) = $var {
$var = agg.final_value();
}
};
($lhs:ident, $rhs:ident) => {
final_agg_values!($lhs);
final_agg_values!($rhs);
};
}
/// Flags provided to comparison instructions (e.g. Eq, Ne) which determine behavior related to NULL values.
#[derive(Clone, Copy, Debug, Default)]
pub struct CmpInsFlags(usize);
@@ -738,8 +726,7 @@ pub enum Cookie {
UserVersion = 6,
}
pub fn exec_add(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_add(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Integer(lhs), OwnedValue::Integer(rhs)) => {
let result = lhs.overflowing_add(*rhs);
@@ -764,8 +751,7 @@ pub fn exec_add(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_subtract(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_subtract(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Integer(lhs), OwnedValue::Integer(rhs)) => {
let result = lhs.overflowing_sub(*rhs);
@@ -793,8 +779,7 @@ pub fn exec_subtract(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_multiply(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_multiply(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Integer(lhs), OwnedValue::Integer(rhs)) => {
let result = lhs.overflowing_mul(*rhs);
@@ -820,8 +805,7 @@ pub fn exec_multiply(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_divide(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_divide(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(_, OwnedValue::Integer(0)) | (_, OwnedValue::Float(0.0)) => OwnedValue::Null,
(OwnedValue::Integer(lhs), OwnedValue::Integer(rhs)) => {
@@ -846,8 +830,7 @@ pub fn exec_divide(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_bit_and(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_bit_and(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null,
(_, OwnedValue::Integer(0))
@@ -871,8 +854,7 @@ pub fn exec_bit_and(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_bit_or(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_bit_or(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null,
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => OwnedValue::Integer(lh | rh),
@@ -892,8 +874,7 @@ pub fn exec_bit_or(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_remainder(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_remainder(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Null, _)
| (_, OwnedValue::Null)
@@ -933,8 +914,7 @@ pub fn exec_remainder(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue
}
}
pub fn exec_bit_not(mut reg: &OwnedValue) -> OwnedValue {
final_agg_values!(reg);
pub fn exec_bit_not(reg: &OwnedValue) -> OwnedValue {
match reg {
OwnedValue::Null => OwnedValue::Null,
OwnedValue::Integer(i) => OwnedValue::Integer(!i),
@@ -944,8 +924,7 @@ pub fn exec_bit_not(mut reg: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_shift_left(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_shift_left(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null,
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
@@ -998,8 +977,7 @@ fn compute_shl(lhs: i64, rhs: i64) -> i64 {
}
}
pub fn exec_shift_right(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_shift_right(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null,
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
@@ -1054,8 +1032,7 @@ fn compute_shr(lhs: i64, rhs: i64) -> i64 {
}
}
pub fn exec_boolean_not(mut reg: &OwnedValue) -> OwnedValue {
final_agg_values!(reg);
pub fn exec_boolean_not(reg: &OwnedValue) -> OwnedValue {
match reg {
OwnedValue::Null => OwnedValue::Null,
OwnedValue::Integer(i) => OwnedValue::Integer((*i == 0) as i64),
@@ -1064,8 +1041,7 @@ pub fn exec_boolean_not(mut reg: &OwnedValue) -> OwnedValue {
_ => todo!(),
}
}
pub fn exec_concat(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_concat(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Text(lhs_text), OwnedValue::Text(rhs_text)) => {
OwnedValue::build_text(&(lhs_text.as_str().to_string() + rhs_text.as_str()))
@@ -1098,15 +1074,10 @@ pub fn exec_concat(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
(OwnedValue::Blob(_), _) | (_, OwnedValue::Blob(_)) => {
todo!("TODO: Handle Blob conversion to String")
}
(OwnedValue::Record(_), _)
| (_, OwnedValue::Record(_))
| (OwnedValue::Agg(_), _)
| (_, OwnedValue::Agg(_)) => unreachable!(),
}
}
pub fn exec_and(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_and(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(_, OwnedValue::Integer(0))
| (OwnedValue::Integer(0), _)
@@ -1124,8 +1095,7 @@ pub fn exec_and(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
}
}
pub fn exec_or(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
final_agg_values!(lhs, rhs);
pub fn exec_or(lhs: &OwnedValue, rhs: &OwnedValue) -> OwnedValue {
match (lhs, rhs) {
(OwnedValue::Null, OwnedValue::Null)
| (OwnedValue::Null, OwnedValue::Float(0.0))

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,12 @@
use crate::types::OwnedValue;
use crate::vdbe::Register;
use crate::LimboError;
use crate::Result;
pub mod vector_types;
use vector_types::*;
pub fn vector32(args: &[OwnedValue]) -> Result<OwnedValue> {
pub fn vector32(args: &[Register]) -> Result<OwnedValue> {
if args.len() != 1 {
return Err(LimboError::ConversionError(
"vector32 requires exactly one argument".to_string(),
@@ -22,7 +23,7 @@ pub fn vector32(args: &[OwnedValue]) -> Result<OwnedValue> {
}
}
pub fn vector64(args: &[OwnedValue]) -> Result<OwnedValue> {
pub fn vector64(args: &[Register]) -> Result<OwnedValue> {
if args.len() != 1 {
return Err(LimboError::ConversionError(
"vector64 requires exactly one argument".to_string(),
@@ -39,14 +40,14 @@ pub fn vector64(args: &[OwnedValue]) -> Result<OwnedValue> {
}
}
pub fn vector_extract(args: &[OwnedValue]) -> Result<OwnedValue> {
pub fn vector_extract(args: &[Register]) -> Result<OwnedValue> {
if args.len() != 1 {
return Err(LimboError::ConversionError(
"vector_extract requires exactly one argument".to_string(),
));
}
let blob = match &args[0] {
let blob = match &args[0].get_owned_value() {
OwnedValue::Blob(b) => b,
_ => {
return Err(LimboError::ConversionError(
@@ -64,7 +65,7 @@ pub fn vector_extract(args: &[OwnedValue]) -> Result<OwnedValue> {
Ok(OwnedValue::build_text(&vector_to_text(&vector)))
}
pub fn vector_distance_cos(args: &[OwnedValue]) -> Result<OwnedValue> {
pub fn vector_distance_cos(args: &[Register]) -> Result<OwnedValue> {
if args.len() != 2 {
return Err(LimboError::ConversionError(
"vector_distance_cos requires exactly two arguments".to_string(),

View File

@@ -1,4 +1,5 @@
use crate::types::{OwnedValue, OwnedValueType};
use crate::vdbe::Register;
use crate::{LimboError, Result};
#[derive(Debug, Clone, PartialEq)]
@@ -103,11 +104,14 @@ pub fn parse_string_vector(vector_type: VectorType, value: &OwnedValue) -> Resul
})
}
pub fn parse_vector(value: &OwnedValue, vec_ty: Option<VectorType>) -> Result<Vector> {
match value.value_type() {
OwnedValueType::Text => parse_string_vector(vec_ty.unwrap_or(VectorType::Float32), value),
pub fn parse_vector(value: &Register, vec_ty: Option<VectorType>) -> Result<Vector> {
match value.get_owned_value().value_type() {
OwnedValueType::Text => parse_string_vector(
vec_ty.unwrap_or(VectorType::Float32),
value.get_owned_value(),
),
OwnedValueType::Blob => {
let Some(blob) = value.to_blob() else {
let Some(blob) = value.get_owned_value().to_blob() else {
return Err(LimboError::ConversionError(
"Invalid vector value".to_string(),
));

View File

@@ -501,7 +501,6 @@ impl Interaction {
Value::Text(t.as_str().to_string())
}
limbo_core::OwnedValue::Blob(b) => Value::Blob(b.to_vec()),
_ => unreachable!(),
};
r.push(v);
}

View File

@@ -572,7 +572,6 @@ pub unsafe extern "C" fn sqlite3_value_type(value: *mut ffi::c_void) -> ffi::c_i
limbo_core::OwnedValue::Float(_) => 2,
limbo_core::OwnedValue::Text(_) => 3,
limbo_core::OwnedValue::Blob(_) => 4,
_ => unreachable!(),
}
}