diff --git a/src/datatypes/src/value.rs b/src/datatypes/src/value.rs index cfce230c498f..2dbda7c9e6e4 100644 --- a/src/datatypes/src/value.rs +++ b/src/datatypes/src/value.rs @@ -756,7 +756,7 @@ impl TryFrom for serde_json::Value { Value::Float32(v) => serde_json::Value::from(v.0), Value::Float64(v) => serde_json::Value::from(v.0), Value::String(bytes) => serde_json::Value::String(bytes.into_string()), - Value::Binary(bytes) | Value::Json(bytes) => serde_json::to_value(bytes)?, + Value::Binary(bytes) => serde_json::to_value(bytes)?, Value::Date(v) => serde_json::Value::Number(v.val().into()), Value::DateTime(v) => serde_json::Value::Number(v.val().into()), Value::List(v) => serde_json::to_value(v)?, @@ -765,6 +765,7 @@ impl TryFrom for serde_json::Value { Value::Interval(v) => serde_json::to_value(v.to_i128())?, Value::Duration(v) => serde_json::to_value(v.value())?, Value::Decimal128(v) => serde_json::to_value(v.to_string())?, + Value::Json(bytes) => jsonb::from_slice(&bytes).unwrap_or_default().into(), }; Ok(json_value) @@ -970,7 +971,7 @@ impl From> for Value { ValueRef::Float32(v) => Value::Float32(v), ValueRef::Float64(v) => Value::Float64(v), ValueRef::String(v) => Value::String(v.into()), - ValueRef::Binary(v) | ValueRef::Json(v) => Value::Binary(v.into()), + ValueRef::Binary(v) => Value::Binary(v.into()), ValueRef::Date(v) => Value::Date(v), ValueRef::DateTime(v) => Value::DateTime(v), ValueRef::Timestamp(v) => Value::Timestamp(v), @@ -979,6 +980,7 @@ impl From> for Value { ValueRef::Duration(v) => Value::Duration(v), ValueRef::List(v) => v.to_value(), ValueRef::Decimal128(v) => Value::Decimal128(v), + ValueRef::Json(v) => Value::Json(v.into()), } } } @@ -1834,6 +1836,18 @@ mod tests { &ConcreteDataType::duration_nanosecond_datatype(), &Value::Duration(Duration::new_nanosecond(1)), ); + check_type_and_value( + &ConcreteDataType::decimal128_datatype(38, 10), + &Value::Decimal128(Decimal128::new(1, 38, 10)), + ); + + let jsonb_value = jsonb::parse_value(r#"{"key": "value"}"#.as_bytes()) + .unwrap() + .to_vec(); + check_type_and_value( + &ConcreteDataType::json_datatype(), + &Value::Json(jsonb_value.into()), + ); } #[test] @@ -1947,6 +1961,15 @@ mod tests { datatype: ConcreteDataType::int32_datatype(), })) ); + + let jsonb_value = + jsonb::parse_value(r#"{"items":[{"Int32":123}],"datatype":{"Int32":{}}}"#.as_bytes()) + .unwrap(); + let json_value: serde_json::Value = jsonb_value.clone().into(); + assert_eq!( + json_value, + to_json(Value::Json(jsonb_value.to_vec().into())) + ); } #[test] @@ -2018,6 +2041,14 @@ mod tests { ValueRef::List(ListValueRef::Ref { val: &list }), Value::List(list.clone()).as_value_ref() ); + + let jsonb_value = jsonb::parse_value(r#"{"key": "value"}"#.as_bytes()) + .unwrap() + .to_vec(); + assert_eq!( + ValueRef::Json(jsonb_value.clone().as_slice()), + Value::Json(jsonb_value.into()).as_value_ref() + ); } #[test] @@ -2231,6 +2262,16 @@ mod tests { .try_to_scalar_value(&ConcreteDataType::binary_datatype()) .unwrap() ); + + let jsonb_value = jsonb::parse_value(r#"{"key": "value"}"#.as_bytes()) + .unwrap() + .to_vec(); + assert_eq!( + ScalarValue::Binary(Some(jsonb_value.clone())), + Value::Json(jsonb_value.into()) + .try_to_scalar_value(&ConcreteDataType::json_datatype()) + .unwrap() + ); } #[test] @@ -2363,6 +2404,12 @@ mod tests { .try_to_scalar_value(&ConcreteDataType::duration_nanosecond_datatype()) .unwrap() ); + assert_eq!( + ScalarValue::Binary(None), + Value::Null + .try_to_scalar_value(&ConcreteDataType::json_datatype()) + .unwrap() + ); } #[test] diff --git a/src/mito2/src/row_converter.rs b/src/mito2/src/row_converter.rs index 875d0cec3a61..60824cc6882f 100644 --- a/src/mito2/src/row_converter.rs +++ b/src/mito2/src/row_converter.rs @@ -119,8 +119,7 @@ impl SortField { } ConcreteDataType::List(_) | ConcreteDataType::Dictionary(_) | - ConcreteDataType::Null(_) | - ConcreteDataType::Json(_) => { + ConcreteDataType::Null(_) => { return error::NotSupportedFieldSnafu { data_type: $self.data_type.clone() }.fail() @@ -147,7 +146,8 @@ impl SortField { Time, time, Interval, interval, Duration, duration, - Decimal128, decimal128 + Decimal128, decimal128, + Json, binary ); Ok(()) @@ -242,7 +242,7 @@ impl SortField { ConcreteDataType::Int64(_) | ConcreteDataType::UInt64(_) => 9, ConcreteDataType::Float32(_) => 5, ConcreteDataType::Float64(_) => 9, - ConcreteDataType::Binary(_) => { + ConcreteDataType::Binary(_) | ConcreteDataType::Json(_) => { // Now the encoder encode binary as a list of bytes so we can't use // skip bytes. let pos_before = deserializer.position(); @@ -271,8 +271,7 @@ impl SortField { ConcreteDataType::Decimal128(_) => 19, ConcreteDataType::Null(_) | ConcreteDataType::List(_) - | ConcreteDataType::Dictionary(_) - | ConcreteDataType::Json(_) => 0, + | ConcreteDataType::Dictionary(_) => 0, }; deserializer.advance(to_skip); Ok(to_skip) diff --git a/src/servers/src/mysql/writer.rs b/src/servers/src/mysql/writer.rs index 1aacda569011..b5351bed7f3f 100644 --- a/src/servers/src/mysql/writer.rs +++ b/src/servers/src/mysql/writer.rs @@ -210,7 +210,7 @@ impl<'a, W: AsyncWrite + Unpin> MysqlResultWriter<'a, W> { Value::Float32(v) => row_writer.write_col(v.0)?, Value::Float64(v) => row_writer.write_col(v.0)?, Value::String(v) => row_writer.write_col(v.as_utf8())?, - Value::Binary(v) => match column.coltype { + Value::Binary(v) | Value::Json(v) => match column.coltype { ColumnType::MYSQL_TYPE_JSON => { row_writer.write_col(jsonb::to_string(&v))?; } @@ -228,7 +228,7 @@ impl<'a, W: AsyncWrite + Unpin> MysqlResultWriter<'a, W> { )?, Value::Interval(v) => row_writer.write_col(v.to_iso8601_string())?, Value::Duration(v) => row_writer.write_col(v.to_std_duration())?, - Value::List(_) | Value::Json(_) => { + Value::List(_) => { return Err(Error::Internal { err_msg: format!( "cannot write value {:?} in mysql protocol: unimplemented", diff --git a/src/servers/src/postgres/types.rs b/src/servers/src/postgres/types.rs index 7953018cc9e7..d6a3ce43d35a 100644 --- a/src/servers/src/postgres/types.rs +++ b/src/servers/src/postgres/types.rs @@ -78,7 +78,7 @@ pub(super) fn encode_value( Value::Float32(v) => builder.encode_field(&v.0), Value::Float64(v) => builder.encode_field(&v.0), Value::String(v) => builder.encode_field(&v.as_utf8()), - Value::Binary(v) => match datatype { + Value::Binary(v) | Value::Json(v) => match datatype { ConcreteDataType::Json(_) => builder.encode_field(&jsonb::to_string(v)), _ => { let bytea_output = query_ctx.configuration_parameter().postgres_bytea_output(); @@ -131,8 +131,7 @@ pub(super) fn encode_value( } Value::Interval(v) => builder.encode_field(&PgInterval::from(*v)), Value::Decimal128(v) => builder.encode_field(&v.to_string()), - // Value of json type is represented as Value::Binary(_) - Value::List(_) | Value::Duration(_) | Value::Json(_) => { + Value::List(_) | Value::Duration(_) => { Err(PgWireError::ApiError(Box::new(Error::Internal { err_msg: format!( "cannot write value {:?} in postgres protocol: unimplemented", diff --git a/tests/cases/standalone/common/insert/merge_mode.result b/tests/cases/standalone/common/insert/merge_mode.result index eb7029068fc3..0e27c5f0ad40 100644 --- a/tests/cases/standalone/common/insert/merge_mode.result +++ b/tests/cases/standalone/common/insert/merge_mode.result @@ -92,6 +92,7 @@ DROP TABLE last_row_table; Affected Rows: 0 +-- SQLNESS REPLACE (line\s\d+\scolumn\s\d+) PLACE create table if not exists invalid_merge_mode( host string, ts timestamp, @@ -103,7 +104,7 @@ create table if not exists invalid_merge_mode( engine=mito with('merge_mode'='first_row'); -Error: 1004(InvalidArguments), Invalid options: Matching variant not found at line 1 column 76 +Error: 1004(InvalidArguments), Invalid options: Matching variant not found at PLACE create table if not exists invalid_merge_mode( host string, diff --git a/tests/cases/standalone/common/insert/merge_mode.sql b/tests/cases/standalone/common/insert/merge_mode.sql index 967f94933311..17e464f26cb6 100644 --- a/tests/cases/standalone/common/insert/merge_mode.sql +++ b/tests/cases/standalone/common/insert/merge_mode.sql @@ -44,6 +44,7 @@ SELECT * from last_row_table ORDER BY host, ts; DROP TABLE last_row_table; +-- SQLNESS REPLACE (line\s\d+\scolumn\s\d+) PLACE create table if not exists invalid_merge_mode( host string, ts timestamp,