mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-10-02 18:15:36 +00:00
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:
@@ -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}"),
|
||||
|
||||
@@ -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 {},
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user