feat: introducing "JSON2" type (#7965)

Signed-off-by: luofucong <luofc@foxmail.com>
This commit is contained in:
LFC
2026-04-15 11:38:01 +08:00
committed by GitHub
parent 00d67d6fa1
commit 43225a8eee
17 changed files with 252 additions and 473 deletions

View File

@@ -63,6 +63,7 @@ pub use crate::statements::option_map::OptionMap;
pub(crate) use crate::statements::transform::transform_statements;
const VECTOR_TYPE_NAME: &str = "VECTOR";
const JSON2_TYPE_NAME: &str = "JSON2";
pub fn value_to_sql_value(val: &Value) -> Result<SqlValue> {
Ok(match val {
@@ -153,7 +154,16 @@ pub fn column_to_schema(
column_schema.set_inverted_index(column.extensions.inverted_index_options.is_some());
if matches!(column.data_type(), SqlDataType::JSON) {
let is_json2_column = if let SqlDataType::Custom(object_name, _) = column.data_type() {
object_name
.0
.first()
.map(|x| x.to_string_unquoted().eq_ignore_ascii_case(JSON2_TYPE_NAME))
.unwrap_or_default()
} else {
false
};
if is_json2_column || matches!(column.data_type(), SqlDataType::JSON) {
let settings = column
.extensions
.build_json_structure_settings()?
@@ -273,39 +283,42 @@ pub fn sql_data_type_to_concrete_data_type(
Ok(ConcreteDataType::decimal128_datatype(*p as u8, *s as i8))
}
},
SqlDataType::JSON => {
let format = if let Some(x) = column_extensions.build_json_structure_settings()? {
if let Some(fields) = match x {
JsonStructureSettings::Structured(fields) => fields,
JsonStructureSettings::UnstructuredRaw => None,
JsonStructureSettings::PartialUnstructuredByKey { fields, .. } => fields,
} {
let datatype = &ConcreteDataType::Struct(fields);
JsonFormat::Native(Box::new(datatype.into()))
} else {
JsonFormat::Native(Box::new(JsonNativeType::Null))
SqlDataType::JSON => Ok(ConcreteDataType::Json(JsonType::new(JsonFormat::Jsonb))),
// Vector type and JSON2 type
SqlDataType::Custom(name, args) if name.0.len() == 1 => {
let name = name.0[0].to_string_unquoted().to_ascii_uppercase();
match name.as_str() {
VECTOR_TYPE_NAME if args.len() == 1 => {
let dim = &args[0];
let dim = dim.parse().map_err(|e| {
error::ParseSqlValueSnafu {
msg: format!("Failed to parse vector dimension '{}': {}", dim, e),
}
.build()
})?;
Ok(ConcreteDataType::vector_datatype(dim))
}
} else {
JsonFormat::Jsonb
};
Ok(ConcreteDataType::Json(JsonType::new(format)))
}
// Vector type
SqlDataType::Custom(name, d)
if name.0.as_slice().len() == 1
&& name.0.as_slice()[0]
.to_string_unquoted()
.to_ascii_uppercase()
== VECTOR_TYPE_NAME
&& d.len() == 1 =>
{
let dim = d[0].parse().map_err(|e| {
error::ParseSqlValueSnafu {
msg: format!("Failed to parse vector dimension: {}", e),
JSON2_TYPE_NAME if args.is_empty() => {
let native_type = column_extensions
.build_json_structure_settings()?
.and_then(|x| match x {
JsonStructureSettings::Structured(Some(fields))
| JsonStructureSettings::PartialUnstructuredByKey {
fields: Some(fields),
..
} => Some(JsonNativeType::from(&ConcreteDataType::Struct(fields))),
JsonStructureSettings::UnstructuredRaw => Some(JsonNativeType::Variant),
_ => None,
})
.unwrap_or(JsonNativeType::Null);
let format = JsonFormat::Json2(Box::new(native_type));
Ok(ConcreteDataType::Json(JsonType::new(format)))
}
.build()
})?;
Ok(ConcreteDataType::vector_datatype(dim))
_ => error::SqlTypeNotSupportedSnafu {
t: data_type.clone(),
}
.fail(),
}
}
_ => error::SqlTypeNotSupportedSnafu {
t: data_type.clone(),

View File

@@ -377,32 +377,35 @@ impl ColumnExtensions {
None
};
options
let format = options
.get(JSON_OPT_FORMAT)
.map(|format| match format {
JSON_FORMAT_FULL_STRUCTURED => Ok(JsonStructureSettings::Structured(fields)),
JSON_FORMAT_PARTIAL => {
let fields = fields.map(|fields| {
let mut fields = Arc::unwrap_or_clone(fields.fields());
fields.push(datatypes::types::StructField::new(
JsonStructureSettings::RAW_FIELD.to_string(),
ConcreteDataType::string_datatype(),
true,
));
StructType::new(Arc::new(fields))
});
Ok(JsonStructureSettings::PartialUnstructuredByKey {
fields,
unstructured_keys,
})
.unwrap_or(JSON_FORMAT_FULL_STRUCTURED);
let settings = match format {
JSON_FORMAT_FULL_STRUCTURED => JsonStructureSettings::Structured(fields),
JSON_FORMAT_PARTIAL => {
let fields = fields.map(|fields| {
let mut fields = Arc::unwrap_or_clone(fields.fields());
fields.push(datatypes::types::StructField::new(
JsonStructureSettings::RAW_FIELD.to_string(),
ConcreteDataType::string_datatype(),
true,
));
StructType::new(Arc::new(fields))
});
JsonStructureSettings::PartialUnstructuredByKey {
fields,
unstructured_keys,
}
JSON_FORMAT_RAW => Ok(JsonStructureSettings::UnstructuredRaw),
_ => InvalidSqlSnafu {
}
JSON_FORMAT_RAW => JsonStructureSettings::UnstructuredRaw,
_ => {
return InvalidSqlSnafu {
msg: format!("unknown JSON datatype 'format': {format}"),
}
.fail(),
})
.transpose()
.fail();
}
};
Ok(Some(settings))
}
pub fn set_json_structure_settings(&mut self, settings: JsonStructureSettings) {