From af8a7b73f514ded9fde0ea629c7cf3c43553da1e Mon Sep 17 00:00:00 2001 From: Denis Smirnov <sd@picodata.io> Date: Mon, 6 Mar 2023 14:50:42 +0700 Subject: [PATCH] fix: explicitly cast typle types when populate virtual tables --- .../test/integration/groupby_test.lua | 7 +- sbroad-core/src/backend/sql/space.rs | 13 +- sbroad-core/src/ir/value.rs | 137 ++++++++++++++++++ 3 files changed, 147 insertions(+), 10 deletions(-) diff --git a/sbroad-cartridge/test_app/test/integration/groupby_test.lua b/sbroad-cartridge/test_app/test/integration/groupby_test.lua index a2c6d25ce6..de2383d250 100644 --- a/sbroad-cartridge/test_app/test/integration/groupby_test.lua +++ b/sbroad-cartridge/test_app/test/integration/groupby_test.lua @@ -798,13 +798,12 @@ groupby_queries.test_count_works = function() }) end --- todo: this test fails if we remove the devision by 8, see issue 351 groupby_queries.test_count = function() local api = cluster:server("api-1").net_box local r, err = api:call("sbroad.execute", { [[ select cs, count("d") from ( - SELECT "d", cast(count("e") + count("e" + "d") as double) / 8 as cs from "arithmetic_space" + SELECT "d", count("e") + count("e" + "d") as cs from "arithmetic_space" group by "d" ) as t where t."d" > 1 @@ -814,12 +813,12 @@ groupby_queries.test_count = function() t.assert_equals(err, nil) t.assert_equals(r.metadata, { - { name = "CS", type = "double" }, + { name = "CS", type = "decimal" }, { name = "COL_1" , type = "decimal" } }) t.assert_items_equals(r.rows, { - {0.5, 1} + {4, 1} }) end diff --git a/sbroad-core/src/backend/sql/space.rs b/sbroad-core/src/backend/sql/space.rs index 6beca9f5e6..a41e6fea00 100644 --- a/sbroad-core/src/backend/sql/space.rs +++ b/sbroad-core/src/backend/sql/space.rs @@ -7,6 +7,7 @@ use crate::ir::relation::SpaceEngine; mod prod_imports { pub use crate::error; pub use crate::errors::{Action, Entity}; + pub use crate::ir::relation::Column; pub use crate::ir::value::EncodedValue; pub use tarantool::index::{FieldType, IndexOptions, IndexType, Part}; pub use tarantool::space::{Field, Space, SpaceCreateOptions}; @@ -96,12 +97,12 @@ impl TmpSpace { } } for (idx, values) in vtable.get_tuples_with_buckets(buckets).iter().enumerate() { - let extended_value = values - .iter() - .cloned() - .map(EncodedValue::from) - .chain(std::iter::once(EncodedValue::Unsigned(idx as u64))) - .collect::<Vec<EncodedValue>>(); + let mut extended_value: Vec<EncodedValue> = Vec::with_capacity(values.len() + 1); + for (v, c) in values.iter().zip(vtable.get_columns().iter()) { + let casted_value = v.cast(&c.r#type)?; + extended_value.push(EncodedValue::from(casted_value)); + } + extended_value.push(EncodedValue::Unsigned(idx as u64)); let data = match rmp_serde::to_vec(&extended_value) { Ok(data) => data, Err(e) => { diff --git a/sbroad-core/src/ir/value.rs b/sbroad-core/src/ir/value.rs index 2389397b5b..0b8cc17643 100644 --- a/sbroad-core/src/ir/value.rs +++ b/sbroad-core/src/ir/value.rs @@ -10,7 +10,9 @@ use tarantool::decimal::Decimal; use tarantool::tlua::{self, LuaRead}; use crate::error; +use crate::errors::{Action, Entity, SbroadError}; use crate::executor::hash::ToHashString; +use crate::ir::relation::Type; use crate::ir::value::double::Double; #[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Clone)] @@ -314,6 +316,141 @@ impl Value { }, } } + + pub fn cast(&self, column_type: &Type) -> Result<Value, SbroadError> { + match column_type { + Type::Array => match self { + Value::Null => Ok(Value::Null), + _ => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into array"), + )), + }, + Type::Boolean => match self { + Value::Boolean(_) => Ok(self.clone()), + Value::Null => Ok(Value::Null), + _ => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into boolean"), + )), + }, + Type::Decimal => match self { + Value::Decimal(_) => Ok(self.clone()), + Value::Double(v) => Ok(Value::Decimal( + Decimal::from_str(&format!("{v}")).map_err(|e| { + SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{e:?}"), + ) + })?, + )), + Value::Integer(v) => Ok(Value::Decimal(Decimal::from(*v))), + Value::Unsigned(v) => Ok(Value::Decimal(Decimal::from(*v))), + Value::Null => Ok(Value::Null), + _ => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into decimal"), + )), + }, + Type::Double => match self { + Value::Double(_) => Ok(self.clone()), + Value::Decimal(v) => Ok(Value::Double(Double::from_str(&format!("{v}"))?)), + Value::Integer(v) => Ok(Value::Double(Double::from(*v))), + Value::Unsigned(v) => Ok(Value::Double(Double::from(*v))), + Value::Null => Ok(Value::Null), + _ => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into double"), + )), + }, + Type::Integer => match self { + Value::Integer(_) => Ok(self.clone()), + Value::Decimal(v) => Ok(Value::Integer(v.to_i64().ok_or_else(|| { + SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into integer"), + ) + })?)), + Value::Double(v) => v + .to_string() + .parse::<i64>() + .map(Value::Integer) + .map_err(|e| { + SbroadError::FailedTo(Action::Serialize, Some(Entity::Value), e.to_string()) + }), + Value::Unsigned(v) => Ok(Value::Integer(*v as i64)), + Value::Null => Ok(Value::Null), + _ => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into integer"), + )), + }, + Type::Scalar => match self { + Value::Tuple(_) => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into scalar"), + )), + _ => Ok(self.clone()), + }, + Type::String => match self { + Value::String(_) => Ok(self.clone()), + Value::Null => Ok(Value::Null), + _ => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into string"), + )), + }, + Type::Number => match self { + Value::Integer(_) | Value::Decimal(_) | Value::Double(_) | Value::Unsigned(_) => { + Ok(self.clone()) + } + Value::Null => Ok(Value::Null), + _ => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into number"), + )), + }, + Type::Unsigned => match self { + Value::Unsigned(_) => Ok(self.clone()), + Value::Integer(v) => Ok(Value::Unsigned(*v as u64)), + Value::Decimal(v) => Ok(Value::Unsigned(v.to_u64().ok_or_else(|| { + SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into unsigned"), + ) + })?)), + Value::Double(v) => { + v.to_string() + .parse::<u64>() + .map(Value::Unsigned) + .map_err(|_| { + SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into unsigned"), + ) + }) + } + Value::Null => Ok(Value::Null), + _ => Err(SbroadError::FailedTo( + Action::Serialize, + Some(Entity::Value), + format!("{self:?} into unsigned"), + )), + }, + } + } } impl ToHashString for Value { -- GitLab