fix(json2): restrict JSON2 type hints (#9316)

* fix(sql): restrict JSON2 type hints

Signed-off-by: fys <fengys1996@gmail.com>

* fix(sql): allow equivalent 64-bit aliases in JSON2 type hints

Signed-off-by: fys <fengys1996@gmail.com>

* fix(sql): support UInt64 conversion and preserve JSON2 hint aliases

Signed-off-by: fys <fengys1996@gmail.com>

* refactor(sql): remove redundant JSON2 type hint normalization

Signed-off-by: fys <fengys1996@gmail.com>

* fix(datatypes): restrict JSON2 hint types in JsonSettings::try_new

Signed-off-by: fys <fengys1996@gmail.com>

---------

Signed-off-by: fys <fengys1996@gmail.com>
This commit is contained in:
fys
2026-09-23 09:19:18 +00:00
committed by GitHub
parent bc80071409
commit 5a78e07be6
14 changed files with 300 additions and 132 deletions
+1 -10
View File
@@ -237,19 +237,10 @@ fn validate_type_hints(type_hints: &[JsonTypeHint]) -> Result<()> {
}
let data_type = match &hint.data_type {
ConcreteDataType::Boolean(_)
| ConcreteDataType::UInt8(_)
| ConcreteDataType::UInt16(_)
| ConcreteDataType::UInt32(_)
| ConcreteDataType::UInt64(_)
| ConcreteDataType::Int8(_)
| ConcreteDataType::Int16(_)
| ConcreteDataType::Int32(_)
| ConcreteDataType::Int64(_)
| ConcreteDataType::Float32(_)
| ConcreteDataType::Float64(_)
| ConcreteDataType::String(_)
| ConcreteDataType::List(_)
| ConcreteDataType::Struct(_) => (&hint.data_type).into(),
| ConcreteDataType::String(_) => (&hint.data_type).into(),
data_type => {
return InvalidJson2SettingsSnafu {
reason: format!("unsupported JSON2 type hint data type: {data_type}"),
+95 -67
View File
@@ -25,7 +25,6 @@ use crate::dialect::GreptimeDbDialect;
use crate::error::{InvalidSqlSnafu, Result, SyntaxSnafu};
use crate::parsers::create_parser::{INVERTED, SKIPPING};
use crate::statements::create::{Json2Options, JsonTypeHint};
use crate::statements::transform::type_alias::get_type_by_alias;
const JSON2_TYPE_NAME: &str = "JSON2";
const MAX_AUTO_EXPANDED_PATHS: &str = "max_auto_expanded_paths";
@@ -155,7 +154,7 @@ fn parse_json2_type_hint(parser: &mut Parser<'_>) -> Result<JsonTypeHint> {
}
);
let data_type = parser.parse_data_type().context(SyntaxSnafu)?;
let data_type = normalize_json2_type_hint_type(data_type)?;
let data_type = validate_json2_type_hint_type(data_type)?;
let mut inverted_index = false;
@@ -238,35 +237,23 @@ fn parse_json2_path(parser: &mut Parser<'_>) -> Result<Vec<String>> {
Ok(path)
}
fn normalize_json2_type_hint_type(data_type: DataType) -> Result<DataType> {
let data_type = get_type_by_alias(&data_type).unwrap_or(data_type);
let normalized = match data_type {
DataType::String(_) | DataType::Text | DataType::Varchar(_) | DataType::Char(_) => {
DataType::String(None)
fn validate_json2_type_hint_type(data_type: DataType) -> Result<DataType> {
match data_type {
DataType::Int64
| DataType::UInt64
| DataType::Float64
| DataType::String(None)
| DataType::BigInt(None)
| DataType::BigIntUnsigned(None)
| DataType::Double(ExactNumberInfo::None)
| DataType::Boolean => Ok(data_type),
_ => InvalidSqlSnafu {
msg: format!(
"unsupported JSON2 type hint data type: {data_type}; supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64"
),
}
DataType::TinyInt(_)
| DataType::SmallInt(_)
| DataType::Int(_)
| DataType::Integer(_)
| DataType::BigInt(_) => DataType::BigInt(None),
DataType::TinyIntUnsigned(_)
| DataType::SmallIntUnsigned(_)
| DataType::IntUnsigned(_)
| DataType::UnsignedInteger
| DataType::BigIntUnsigned(_) => DataType::BigIntUnsigned(None),
DataType::Float(_) | DataType::Real | DataType::Double(_) => {
DataType::Double(ExactNumberInfo::None)
}
DataType::Boolean => DataType::Boolean,
_ => {
return InvalidSqlSnafu {
msg: format!("unsupported JSON2 type hint data type: {data_type}"),
}
.fail();
}
};
Ok(normalized)
.fail(),
}
}
fn ensure_no_path_conflict(hints: &[JsonTypeHint], path: &[String]) -> Result<()> {
@@ -330,7 +317,7 @@ CREATE TABLE traces (
log_json_data JSON2 (
"service.name" STRING INVERTED INDEX,
http.method STRING,
status_code INT64,
status_code BIGINT,
comment STRING,
),
ts TIMESTAMP TIME INDEX,
@@ -463,40 +450,81 @@ CREATE TABLE traces (
}
#[test]
fn test_parse_json2_type_hint_normalizes_numeric_types() {
let column = parse_json2_column(
r#"
CREATE TABLE traces (
log_json_data JSON2 (
tinyint_value TINYINT,
smallint_value SMALLINT,
int_value INT,
integer_value INTEGER,
bigint_value BIGINT,
int64_value INT64,
tinyuint_value TINYINT UNSIGNED,
smalluint_value SMALLINT UNSIGNED,
uint_value INT UNSIGNED,
uint64_value UINT64,
float_value FLOAT,
real_value REAL,
double_value DOUBLE,
float64_value FLOAT64
),
ts TIMESTAMP TIME INDEX,
)"#,
);
fn test_parse_json2_type_hint_supported_types() {
for (sql_type, expected) in [
("STRING", DataType::String(None)),
("BIGINT", DataType::BigInt(None)),
("BIGINT UNSIGNED", DataType::BigIntUnsigned(None)),
("DOUBLE", DataType::Double(ExactNumberInfo::None)),
("BOOLEAN", DataType::Boolean),
("INT64", DataType::Int64),
("UINT64", DataType::UInt64),
("FLOAT64", DataType::Float64),
] {
for sql_type in [sql_type.to_string(), sql_type.to_lowercase()] {
let column = parse_json2_column(&format!(
"CREATE TABLE traces (j JSON2 (value {sql_type}), ts TIMESTAMP TIME INDEX)"
));
let options = column.extensions.json2_options.unwrap();
let settings = options.build_json_settings().unwrap();
assert_eq!(settings.type_hints().len(), 1);
let hints = options.type_hints;
assert_eq!(hints[0].data_type, expected);
}
}
}
let hints = column.extensions.json2_options.unwrap().type_hints;
assert_eq!(hints.len(), 14);
for hint in hints.iter().take(6) {
assert_eq!(hint.data_type, DataType::BigInt(None));
}
for hint in hints.iter().skip(6).take(4) {
assert_eq!(hint.data_type, DataType::BigIntUnsigned(None));
}
for hint in hints.iter().skip(10) {
assert_eq!(hint.data_type, DataType::Double(ExactNumberInfo::None));
#[test]
fn test_parse_json2_type_hint_rejects_unsupported_types() {
for sql_type in [
"INT2",
"INT4",
"INT8",
"INT16",
"INT32",
"TINYINT",
"SMALLINT",
"INT",
"INTEGER",
"UINT8",
"UINT16",
"UINT32",
"TINYINT UNSIGNED",
"SMALLINT UNSIGNED",
"INT UNSIGNED",
"FLOAT",
"REAL",
"FLOAT4",
"FLOAT8",
"FLOAT32",
"BOOL",
"TEXT",
"VARCHAR(10)",
"CHAR(10)",
"TIMESTAMP",
"DECIMAL(10, 2)",
"STRING(10)",
"BIGINT(10)",
] {
for sql in [
format!(
"CREATE TABLE traces (j JSON2 (value {sql_type}), ts TIMESTAMP TIME INDEX)"
),
format!("ALTER TABLE traces MODIFY COLUMN j JSON2 (value {sql_type})"),
] {
let err = ParserContext::create_with_dialect(
&sql,
&GreptimeDbDialect {},
ParseOptions::default(),
)
.unwrap_err();
assert!(
err.to_string().contains(
"supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64"
),
"{sql}: {err}"
);
}
}
}
@@ -504,7 +532,7 @@ CREATE TABLE traces (
fn test_parse_json2_type_hint_rejects_default() {
for default in ["-5", "abs(-1)"] {
let sql = format!(
"CREATE TABLE traces (log_json_data JSON2 (status_code INT64 DEFAULT {default}), ts TIMESTAMP TIME INDEX)"
"CREATE TABLE traces (log_json_data JSON2 (status_code BIGINT DEFAULT {default}), ts TIMESTAMP TIME INDEX)"
);
let err = ParserContext::create_with_dialect(
&sql,
@@ -521,7 +549,7 @@ CREATE TABLE traces (
let result = ParserContext::create_with_dialect(
r#"
CREATE TABLE traces (
log_json_data JSON2 (a.b STRING, a.b INT64),
log_json_data JSON2 (a.b STRING, a.b BIGINT),
ts TIMESTAMP TIME INDEX,
)"#,
&GreptimeDbDialect {},
@@ -537,7 +565,7 @@ CREATE TABLE traces (
let result = ParserContext::create_with_dialect(
r#"
CREATE TABLE traces (
log_json_data JSON2 (a STRING, a.b INT64),
log_json_data JSON2 (a STRING, a.b BIGINT),
ts TIMESTAMP TIME INDEX,
)"#,
&GreptimeDbDialect {},
+4 -1
View File
@@ -225,7 +225,9 @@ pub fn sql_column_def_to_grpc_column_def(
pub fn sql_data_type_to_concrete_data_type(data_type: &SqlDataType) -> Result<ConcreteDataType> {
match data_type {
SqlDataType::BigInt(_) | SqlDataType::Int64 => Ok(ConcreteDataType::int64_datatype()),
SqlDataType::BigIntUnsigned(_) => Ok(ConcreteDataType::uint64_datatype()),
SqlDataType::BigIntUnsigned(_) | SqlDataType::UInt64 => {
Ok(ConcreteDataType::uint64_datatype())
}
SqlDataType::Int(_) | SqlDataType::Integer(_) => Ok(ConcreteDataType::int32_datatype()),
SqlDataType::IntUnsigned(_) | SqlDataType::UnsignedInteger => {
Ok(ConcreteDataType::uint32_datatype())
@@ -422,6 +424,7 @@ mod tests {
SqlDataType::BigIntUnsigned(None),
ConcreteDataType::uint64_datatype(),
);
check_type(SqlDataType::UInt64, ConcreteDataType::uint64_datatype());
check_type(
SqlDataType::IntUnsigned(None),
ConcreteDataType::uint32_datatype(),
+17 -45
View File
@@ -165,7 +165,7 @@ impl Json2Options {
.map(|hint| {
Ok(datatypes::json::JsonTypeHint {
path: hint.path.clone(),
data_type: json_type_hint_concrete_data_type(&hint.data_type)?,
data_type: sql_data_type_to_concrete_data_type(&hint.data_type)?,
inverted_index: hint.inverted_index,
})
})
@@ -396,47 +396,19 @@ impl ColumnExtensions {
}
}
fn json_type_hint_concrete_data_type(data_type: &DataType) -> Result<ConcreteDataType> {
let data_type = sql_data_type_to_concrete_data_type(data_type)?;
normalize_json_type_hint_concrete_data_type(&data_type)
}
fn normalize_json_type_hint_concrete_data_type(
data_type: &ConcreteDataType,
) -> Result<ConcreteDataType> {
let normalized = match data_type {
ConcreteDataType::String(_) => ConcreteDataType::string_datatype(),
ConcreteDataType::Int8(_)
| ConcreteDataType::Int16(_)
| ConcreteDataType::Int32(_)
| ConcreteDataType::Int64(_) => ConcreteDataType::int64_datatype(),
ConcreteDataType::UInt8(_)
| ConcreteDataType::UInt16(_)
| ConcreteDataType::UInt32(_)
| ConcreteDataType::UInt64(_) => ConcreteDataType::uint64_datatype(),
ConcreteDataType::Float32(_) | ConcreteDataType::Float64(_) => {
ConcreteDataType::float64_datatype()
}
ConcreteDataType::Boolean(_) => ConcreteDataType::boolean_datatype(),
_ => {
return InvalidSqlSnafu {
msg: format!("unsupported JSON2 type hint data type: {data_type}"),
}
.fail();
}
};
Ok(normalized)
}
fn json_type_hint_sql_data_type(data_type: &ConcreteDataType) -> Result<DataType> {
let data_type = normalize_json_type_hint_concrete_data_type(data_type)?;
let sql_type = match data_type {
ConcreteDataType::String(_) => DataType::String(None),
ConcreteDataType::Int64(_) => DataType::BigInt(None),
ConcreteDataType::UInt64(_) => DataType::BigIntUnsigned(None),
ConcreteDataType::Float64(_) => DataType::Double(sqlparser::ast::ExactNumberInfo::None),
ConcreteDataType::Boolean(_) => DataType::Boolean,
_ => unreachable!("JSON2 type hint data type should have been normalized"),
_ => {
return InvalidSqlSnafu {
msg: format!("unsupported JSON2 type hint data type: {data_type}"),
}
.fail();
}
};
Ok(sql_type)
}
@@ -933,7 +905,7 @@ ENGINE=mito
let sql = r#"CREATE TABLE traces (
log_json_data JSON2 (
"service.name" STRING,
"a.b"."c" INT64,
"a.b"."c" BIGINT,
a."b.c" STRING
),
ts TIMESTAMP TIME INDEX
@@ -977,7 +949,7 @@ ENGINE=mito
fn test_parse_json2_max_auto_expanded_paths_option() -> Result<()> {
let sql = r#"CREATE TABLE traces (
log_json_data JSON2 (
status_code INT64,
status_code BIGINT,
max_auto_expanded_paths = 1
),
ts TIMESTAMP TIME INDEX
@@ -1003,7 +975,7 @@ ENGINE=mito
let sql = r#"CREATE TABLE traces (
log_json_data JSON2 (
"1abc" STRING,
a."2b" INT64
a."2b" BIGINT
),
ts TIMESTAMP TIME INDEX
)"#;
@@ -1045,8 +1017,8 @@ ENGINE=mito
fn test_json2_type_hint_rejects_default() {
let sql = r#"CREATE TABLE traces (
log_json_data JSON2 (
status_code INT64 DEFAULT -5,
duration FLOAT64 DEFAULT +1.5,
status_code BIGINT DEFAULT -5,
duration DOUBLE DEFAULT +1.5,
error BOOLEAN DEFAULT false,
message STRING DEFAULT 'unknown'
),
@@ -1062,7 +1034,7 @@ ENGINE=mito
fn test_json2_type_hint_rejects_not_null() {
let sql = r#"CREATE TABLE traces (
log_json_data JSON2 (
status_code INT64 NOT NULL DEFAULT NULL
status_code BIGINT NOT NULL DEFAULT NULL
),
ts TIMESTAMP TIME INDEX
)"#;
@@ -1073,23 +1045,23 @@ ENGINE=mito
}
#[test]
fn test_set_json_settings_normalizes_type_hint_sql_types() -> Result<()> {
fn test_set_json_settings_preserves_type_hint_sql_types() -> Result<()> {
let mut extensions = super::ColumnExtensions::default();
let settings = JsonSettings::try_new(
vec![
DatatypeJsonTypeHint {
path: vec!["i".to_string()],
data_type: ConcreteDataType::int32_datatype(),
data_type: ConcreteDataType::int64_datatype(),
inverted_index: false,
},
DatatypeJsonTypeHint {
path: vec!["f".to_string()],
data_type: ConcreteDataType::float32_datatype(),
data_type: ConcreteDataType::float64_datatype(),
inverted_index: false,
},
DatatypeJsonTypeHint {
path: vec!["u".to_string()],
data_type: ConcreteDataType::uint32_datatype(),
data_type: ConcreteDataType::uint64_datatype(),
inverted_index: false,
},
DatatypeJsonTypeHint {
@@ -18,7 +18,7 @@ ALTER TABLE application_logs
MODIFY COLUMN attrs JSON2 (
max_auto_expanded_paths = 2000,
service STRING,
duration INT64,
duration BIGINT,
trace_id STRING
);
@@ -14,7 +14,7 @@ ALTER TABLE application_logs
MODIFY COLUMN attrs JSON2 (
max_auto_expanded_paths = 2000,
service STRING,
duration INT64,
duration BIGINT,
trace_id STRING
);
@@ -24,7 +24,7 @@ ADMIN FLUSH_TABLE('json2_alter_type_hints_compaction');
ALTER TABLE json2_alter_type_hints_compaction
MODIFY COLUMN attrs JSON2 (
kind INT64
kind BIGINT
);
Affected Rows: 0
@@ -14,7 +14,7 @@ ADMIN FLUSH_TABLE('json2_alter_type_hints_compaction');
ALTER TABLE json2_alter_type_hints_compaction
MODIFY COLUMN attrs JSON2 (
kind INT64
kind BIGINT
);
INSERT INTO json2_alter_type_hints_compaction VALUES
@@ -24,7 +24,7 @@ ADMIN FLUSH_TABLE('json2_alter_type_hints_compaction_conversion');
ALTER TABLE json2_alter_type_hints_compaction_conversion
MODIFY COLUMN attrs JSON2 (
to_string STRING,
to_int INT64
to_int BIGINT
);
Affected Rows: 0
@@ -14,7 +14,7 @@ ADMIN FLUSH_TABLE('json2_alter_type_hints_compaction_conversion');
ALTER TABLE json2_alter_type_hints_compaction_conversion
MODIFY COLUMN attrs JSON2 (
to_string STRING,
to_int INT64
to_int BIGINT
);
INSERT INTO json2_alter_type_hints_compaction_conversion VALUES
@@ -24,7 +24,7 @@ ADMIN FLUSH_TABLE('json2_compaction_null_type_hint_mismatch');
ALTER TABLE json2_compaction_null_type_hint_mismatch
MODIFY COLUMN attrs JSON2 (
kind INT64
kind BIGINT
);
Affected Rows: 0
@@ -14,7 +14,7 @@ ADMIN FLUSH_TABLE('json2_compaction_null_type_hint_mismatch');
ALTER TABLE json2_compaction_null_type_hint_mismatch
MODIFY COLUMN attrs JSON2 (
kind INT64
kind BIGINT
);
INSERT INTO json2_compaction_null_type_hint_mismatch VALUES
@@ -71,7 +71,7 @@ CREATE TABLE json2_type_hints_timestamp (
)
);
Error: 2000(InvalidSyntax), Invalid SQL, error: unsupported JSON2 type hint data type: TIMESTAMP
Error: 2000(InvalidSyntax), Invalid SQL, error: unsupported JSON2 type hint data type: TIMESTAMP; supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64
-- A type hint at the maximum supported depth is accepted.
CREATE TABLE json2_type_hint_depth_50 (
@@ -105,3 +105,132 @@ DROP TABLE json2_type_hint_depth_50;
Affected Rows: 0
-- Type hints reject unsupported types and aliases.
CREATE TABLE json2_hint_int8 (ts TIMESTAMP TIME INDEX, j JSON2 (value INT8));
Error: 2000(InvalidSyntax), Invalid SQL, error: unsupported JSON2 type hint data type: INT8; supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64
CREATE TABLE json2_hint_tinyint (ts TIMESTAMP TIME INDEX, j JSON2 (value TINYINT));
Error: 2000(InvalidSyntax), Invalid SQL, error: unsupported JSON2 type hint data type: TINYINT; supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64
CREATE TABLE json2_hint_uint8 (ts TIMESTAMP TIME INDEX, j JSON2 (value UINT8));
Error: 2000(InvalidSyntax), Invalid SQL, error: unsupported JSON2 type hint data type: UInt8; supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64
CREATE TABLE json2_hint_float (ts TIMESTAMP TIME INDEX, j JSON2 (value FLOAT));
Error: 2000(InvalidSyntax), Invalid SQL, error: unsupported JSON2 type hint data type: FLOAT; supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64
CREATE TABLE json2_hint_text (ts TIMESTAMP TIME INDEX, j JSON2 (value TEXT));
Error: 2000(InvalidSyntax), Invalid SQL, error: unsupported JSON2 type hint data type: TEXT; supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64
CREATE TABLE json2_hint_unsigned (
ts TIMESTAMP TIME INDEX,
j JSON2 (value BIGINT UNSIGNED)
) WITH ('append_mode' = 'true');
Affected Rows: 0
INSERT INTO json2_hint_unsigned VALUES (1, '{"value":18446744073709551615}');
Affected Rows: 1
SELECT j.value FROM json2_hint_unsigned;
+--------------------------------------------------------------+
| json_get(json2_hint_unsigned.j,Utf8("$.value"),UInt64(NULL)) |
+--------------------------------------------------------------+
| 18446744073709551615 |
+--------------------------------------------------------------+
ALTER TABLE json2_hint_unsigned MODIFY COLUMN j JSON2 (value INT8);
Error: 2000(InvalidSyntax), Invalid SQL, error: unsupported JSON2 type hint data type: INT8; supported types: STRING, BIGINT, BIGINT UNSIGNED, DOUBLE, BOOLEAN; supported aliases: INT64, UINT64, FLOAT64
DROP TABLE json2_hint_unsigned;
Affected Rows: 0
-- These aliases preserve the exact type and are displayed using canonical names.
CREATE TABLE json2_hint_aliases (
ts TIMESTAMP TIME INDEX,
j JSON2 (i INT64, u UINT64, f FLOAT64)
) WITH ('append_mode' = 'true');
Affected Rows: 0
SHOW CREATE TABLE json2_hint_aliases;
+--------------------+---------------------------------------------------+
| Table | Create Table |
+--------------------+---------------------------------------------------+
| json2_hint_aliases | CREATE TABLE IF NOT EXISTS "json2_hint_aliases" ( |
| | "ts" TIMESTAMP(3) NOT NULL, |
| | "j" JSON2( |
| | max_auto_expanded_paths = 100, |
| | "i" BIGINT, |
| | "u" BIGINT UNSIGNED, |
| | "f" DOUBLE |
| | ) NULL, |
| | TIME INDEX ("ts") |
| | ) |
| | |
| | ENGINE=mito |
| | WITH( |
| | append_mode = 'true' |
| | ) |
+--------------------+---------------------------------------------------+
INSERT INTO json2_hint_aliases VALUES
(1, '{"i":-9223372036854775808,"u":18446744073709551615,"f":1.5}');
Affected Rows: 1
SELECT j.i AS i, j.u AS u, j.f AS f FROM json2_hint_aliases;
+----------------------+----------------------+-----+
| i | u | f |
+----------------------+----------------------+-----+
| -9223372036854775808 | 18446744073709551615 | 1.5 |
+----------------------+----------------------+-----+
ALTER TABLE json2_hint_aliases MODIFY COLUMN j JSON2 (i INT64, u UINT64, f FLOAT64);
Affected Rows: 0
SHOW CREATE TABLE json2_hint_aliases;
+--------------------+---------------------------------------------------+
| Table | Create Table |
+--------------------+---------------------------------------------------+
| json2_hint_aliases | CREATE TABLE IF NOT EXISTS "json2_hint_aliases" ( |
| | "ts" TIMESTAMP(3) NOT NULL, |
| | "j" JSON2( |
| | max_auto_expanded_paths = 100, |
| | "i" BIGINT, |
| | "u" BIGINT UNSIGNED, |
| | "f" DOUBLE |
| | ) NULL, |
| | TIME INDEX ("ts") |
| | ) |
| | |
| | ENGINE=mito |
| | WITH( |
| | append_mode = 'true' |
| | ) |
+--------------------+---------------------------------------------------+
SELECT j.i AS i, j.u AS u, j.f AS f FROM json2_hint_aliases;
+----------------------+----------------------+-----+
| i | u | f |
+----------------------+----------------------+-----+
| -9223372036854775808 | 18446744073709551615 | 1.5 |
+----------------------+----------------------+-----+
DROP TABLE json2_hint_aliases;
Affected Rows: 0
@@ -59,3 +59,48 @@ CREATE TABLE json2_type_hint_depth_51 (
DROP TABLE json2_type_hints;
DROP TABLE json2_type_hint_depth_50;
-- Type hints reject unsupported types and aliases.
CREATE TABLE json2_hint_int8 (ts TIMESTAMP TIME INDEX, j JSON2 (value INT8));
CREATE TABLE json2_hint_tinyint (ts TIMESTAMP TIME INDEX, j JSON2 (value TINYINT));
CREATE TABLE json2_hint_uint8 (ts TIMESTAMP TIME INDEX, j JSON2 (value UINT8));
CREATE TABLE json2_hint_float (ts TIMESTAMP TIME INDEX, j JSON2 (value FLOAT));
CREATE TABLE json2_hint_text (ts TIMESTAMP TIME INDEX, j JSON2 (value TEXT));
CREATE TABLE json2_hint_unsigned (
ts TIMESTAMP TIME INDEX,
j JSON2 (value BIGINT UNSIGNED)
) WITH ('append_mode' = 'true');
INSERT INTO json2_hint_unsigned VALUES (1, '{"value":18446744073709551615}');
SELECT j.value FROM json2_hint_unsigned;
ALTER TABLE json2_hint_unsigned MODIFY COLUMN j JSON2 (value INT8);
DROP TABLE json2_hint_unsigned;
-- These aliases preserve the exact type and are displayed using canonical names.
CREATE TABLE json2_hint_aliases (
ts TIMESTAMP TIME INDEX,
j JSON2 (i INT64, u UINT64, f FLOAT64)
) WITH ('append_mode' = 'true');
SHOW CREATE TABLE json2_hint_aliases;
INSERT INTO json2_hint_aliases VALUES
(1, '{"i":-9223372036854775808,"u":18446744073709551615,"f":1.5}');
SELECT j.i AS i, j.u AS u, j.f AS f FROM json2_hint_aliases;
ALTER TABLE json2_hint_aliases MODIFY COLUMN j JSON2 (i INT64, u UINT64, f FLOAT64);
SHOW CREATE TABLE json2_hint_aliases;
SELECT j.i AS i, j.u AS u, j.f AS f FROM json2_hint_aliases;
DROP TABLE json2_hint_aliases;