mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-10-22 03:42:32 +00:00
feat(json2): support altering JSON2 settings (#9029)
* feat(sql): support alter syntax for JSON2 columns Signed-off-by: fys <fengys1996@gmail.com> * fix(json2): preserve rows on type hint mismatch during compaction * refactor(json2): simplify alter settings handling * fix(json2): preserve coerced values during compaction * chore: remove unnecessary clone * chor: reduce memory allocations * fix: cargo clippy * chore: update greptime-proto to main branch * refactor(datatypes): unify string handling with other JSON type hints * fix: cr --------- Signed-off-by: fys <fengys1996@gmail.com>
This commit is contained in:
@@ -24,9 +24,10 @@ use api::v1::column_def::{options_from_column_schema, try_as_column_schema};
|
||||
use api::v1::{
|
||||
AddColumn, AddColumns, AlterDatabaseExpr, AlterTableExpr, Analyzer, ColumnDataType,
|
||||
ColumnDataTypeExtension, CreateFlowExpr, CreateTableExpr, CreateViewExpr, DropColumn,
|
||||
DropColumns, DropDefaults, ExpireAfter, FulltextBackend as PbFulltextBackend, ModifyColumnType,
|
||||
DropColumns, DropDefaults, ExpireAfter, FulltextBackend as PbFulltextBackend,
|
||||
JsonSettings as PbJsonSettings, JsonTypeHint as PbJsonTypeHint, ModifyColumnType,
|
||||
ModifyColumnTypes, RenameTable, SemanticType, SetDatabaseOptions, SetDefaults, SetFulltext,
|
||||
SetIndex, SetIndexes, SetInverted, SetSkipping, SetTableOptions,
|
||||
SetIndex, SetIndexes, SetInverted, SetJsonSettings, SetSkipping, SetTableOptions,
|
||||
SkippingIndexType as PbSkippingIndexType, TableName, UnsetDatabaseOptions, UnsetFulltext,
|
||||
UnsetIndex, UnsetIndexes, UnsetInverted, UnsetSkipping, UnsetTableOptions, set_index,
|
||||
unset_index,
|
||||
@@ -36,6 +37,7 @@ use common_error::ext::BoxedError;
|
||||
use common_grpc_expr::util::ColumnExpr;
|
||||
use common_time::Timezone;
|
||||
use datafusion::sql::planner::object_name_to_table_reference;
|
||||
use datatypes::json::JsonSettings;
|
||||
use datatypes::prelude::ConcreteDataType;
|
||||
use datatypes::schema::{
|
||||
COLUMN_FULLTEXT_OPT_KEY_ANALYZER, COLUMN_FULLTEXT_OPT_KEY_BACKEND,
|
||||
@@ -782,6 +784,29 @@ pub(crate) fn to_repartition_request(
|
||||
})
|
||||
}
|
||||
|
||||
fn json_settings_to_proto(settings: JsonSettings) -> Result<PbJsonSettings> {
|
||||
let (type_hints, max_auto_expanded_paths) = settings.into_parts();
|
||||
let type_hints = type_hints
|
||||
.into_iter()
|
||||
.map(|hint| {
|
||||
let (data_type, datatype_extension) = ColumnDataTypeWrapper::try_from(hint.data_type)
|
||||
.map(|w| w.to_parts())
|
||||
.context(ColumnDataTypeSnafu)?;
|
||||
|
||||
Ok(PbJsonTypeHint {
|
||||
path: hint.path,
|
||||
data_type: data_type as i32,
|
||||
datatype_extension,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
Ok(PbJsonSettings {
|
||||
type_hints,
|
||||
max_auto_expanded_paths,
|
||||
})
|
||||
}
|
||||
|
||||
/// Converts a SQL alter table statement into a gRPC alter table expression.
|
||||
pub(crate) fn to_alter_table_expr(
|
||||
alter_table: AlterTable,
|
||||
@@ -830,12 +855,15 @@ pub(crate) fn to_alter_table_expr(
|
||||
} => {
|
||||
let target_type =
|
||||
sql_data_type_to_concrete_data_type(&target_type).context(ParseSqlSnafu)?;
|
||||
|
||||
// Currently disallow modify column type to json2.
|
||||
if target_type.is_json2() {
|
||||
return NotSupportedSnafu {
|
||||
feat: "ALTER TABLE MODIFY COLUMN to JSON2 type",
|
||||
}
|
||||
.fail();
|
||||
}
|
||||
|
||||
let (target_type, target_type_extension) = ColumnDataTypeWrapper::try_from(target_type)
|
||||
.map(|w| w.to_parts())
|
||||
.context(ColumnDataTypeSnafu)?;
|
||||
@@ -853,6 +881,20 @@ pub(crate) fn to_alter_table_expr(
|
||||
}],
|
||||
})
|
||||
}
|
||||
AlterTableOperation::SetJsonSettings {
|
||||
column_name,
|
||||
json2_options,
|
||||
} => {
|
||||
let settings = match json2_options {
|
||||
Some(options) => options.build_json_settings().context(ParseSqlSnafu)?,
|
||||
None => datatypes::json::JsonSettings::new_v2(),
|
||||
};
|
||||
|
||||
AlterTableKind::SetJsonSettings(SetJsonSettings {
|
||||
column_name: column_name.value,
|
||||
settings: Some(json_settings_to_proto(settings)?),
|
||||
})
|
||||
}
|
||||
AlterTableOperation::DropColumn { name } => AlterTableKind::DropColumns(DropColumns {
|
||||
drop_columns: vec![DropColumn {
|
||||
name: name.value.clone(),
|
||||
@@ -1752,31 +1794,48 @@ SELECT max(c1), min(c2) FROM schema_2.table_2;";
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alter_json2_is_not_supported() {
|
||||
for sql in [
|
||||
"ALTER TABLE monitor MODIFY COLUMN payload JSON2;",
|
||||
"ALTER TABLE monitor MODIFY COLUMN payload JSON2 (service STRING);",
|
||||
] {
|
||||
let stmt = ParserContext::create_with_dialect(
|
||||
sql,
|
||||
&GreptimeDbDialect {},
|
||||
ParseOptions::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap();
|
||||
fn test_to_alter_set_json_settings_expr() {
|
||||
let sql = "ALTER TABLE monitor MODIFY COLUMN payload JSON2 (service STRING);";
|
||||
let stmt =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap();
|
||||
|
||||
let Statement::AlterTable(alter_table) = stmt else {
|
||||
unreachable!()
|
||||
};
|
||||
let err = to_alter_table_expr(alter_table, &QueryContext::arc()).unwrap_err();
|
||||
let Statement::AlterTable(alter_table) = stmt else {
|
||||
unreachable!()
|
||||
};
|
||||
let expr = to_alter_table_expr(alter_table, &QueryContext::arc()).unwrap();
|
||||
let kind = expr.kind.unwrap();
|
||||
|
||||
assert!(matches!(err, crate::error::Error::NotSupported { .. }));
|
||||
assert_eq!(
|
||||
"Not supported: ALTER TABLE MODIFY COLUMN to JSON2 type",
|
||||
err.to_string()
|
||||
);
|
||||
}
|
||||
let AlterTableKind::SetJsonSettings(modify) = kind else {
|
||||
unreachable!()
|
||||
};
|
||||
assert_eq!("payload", modify.column_name);
|
||||
let settings = modify.settings.as_ref().unwrap();
|
||||
assert_eq!(Some(100), settings.max_auto_expanded_paths);
|
||||
assert_eq!(1, settings.type_hints.len());
|
||||
assert_eq!(["service"], &settings.type_hints[0].path[..]);
|
||||
|
||||
let sql = "ALTER TABLE monitor MODIFY COLUMN payload JSON2;";
|
||||
let stmt =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap();
|
||||
|
||||
let Statement::AlterTable(alter_table) = stmt else {
|
||||
unreachable!()
|
||||
};
|
||||
let expr = to_alter_table_expr(alter_table, &QueryContext::arc()).unwrap();
|
||||
let kind = expr.kind.unwrap();
|
||||
|
||||
let AlterTableKind::SetJsonSettings(modify) = kind else {
|
||||
unreachable!()
|
||||
};
|
||||
let settings = modify.settings.as_ref().unwrap();
|
||||
assert_eq!(Some(100), settings.max_auto_expanded_paths);
|
||||
assert!(settings.type_hints.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user