mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-08-18 12:08:22 +00:00
fix: type cast bugs found by sqlness (#2438)
* update valid results Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * accomplish datatype Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * cast null Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * fix unit tests Signed-off-by: Ruihang Xia <waynestxia@gmail.com> --------- Signed-off-by: Ruihang Xia <waynestxia@gmail.com>
This commit is contained in:
+18
-5
@@ -893,11 +893,24 @@ pub fn to_column_data_type(data_type: &ConcreteDataType) -> Option<ColumnDataTyp
|
||||
ConcreteDataType::Time(TimeType::Millisecond(_)) => ColumnDataType::TimeMillisecond,
|
||||
ConcreteDataType::Time(TimeType::Microsecond(_)) => ColumnDataType::TimeMicrosecond,
|
||||
ConcreteDataType::Time(TimeType::Nanosecond(_)) => ColumnDataType::TimeNanosecond,
|
||||
ConcreteDataType::Null(_)
|
||||
| ConcreteDataType::Duration(_)
|
||||
| ConcreteDataType::Interval(_)
|
||||
| ConcreteDataType::List(_)
|
||||
| ConcreteDataType::Dictionary(_) => return None,
|
||||
ConcreteDataType::Duration(DurationType::Second(_)) => ColumnDataType::DurationSecond,
|
||||
ConcreteDataType::Duration(DurationType::Millisecond(_)) => {
|
||||
ColumnDataType::DurationMillisecond
|
||||
}
|
||||
ConcreteDataType::Duration(DurationType::Microsecond(_)) => {
|
||||
ColumnDataType::DurationMicrosecond
|
||||
}
|
||||
ConcreteDataType::Duration(DurationType::Nanosecond(_)) => {
|
||||
ColumnDataType::DurationNanosecond
|
||||
}
|
||||
ConcreteDataType::Interval(IntervalType::YearMonth(_)) => ColumnDataType::IntervalYearMonth,
|
||||
ConcreteDataType::Interval(IntervalType::MonthDayNano(_)) => {
|
||||
ColumnDataType::IntervalMonthDayNano
|
||||
}
|
||||
ConcreteDataType::Interval(IntervalType::DayTime(_)) => ColumnDataType::IntervalDayTime,
|
||||
ConcreteDataType::Null(_) | ConcreteDataType::List(_) | ConcreteDataType::Dictionary(_) => {
|
||||
return None
|
||||
}
|
||||
};
|
||||
|
||||
Some(column_data_type)
|
||||
|
||||
@@ -58,7 +58,7 @@ pub fn cast_with_opt(
|
||||
match new_value {
|
||||
Some(v) => Ok(v),
|
||||
None => {
|
||||
if cast_option.strict {
|
||||
if cast_option.strict && !src_value.is_null() {
|
||||
Err(invalid_type_cast(&src_value, dest_type))
|
||||
} else {
|
||||
Ok(Value::Null)
|
||||
@@ -83,6 +83,7 @@ pub fn can_cast_type(src_value: &Value, dest_type: &ConcreteDataType) -> bool {
|
||||
match (src_type, dest_type) {
|
||||
// null type cast
|
||||
(_, Null(_)) => true,
|
||||
(Null(_), _) => true,
|
||||
|
||||
// boolean type cast
|
||||
(_, Boolean(_)) => src_type.is_numeric() || src_type.is_string(),
|
||||
@@ -102,18 +103,22 @@ pub fn can_cast_type(src_value: &Value, dest_type: &ConcreteDataType) -> bool {
|
||||
// Date type
|
||||
(Date(_), Int32(_) | Timestamp(_) | String(_)) => true,
|
||||
(Int32(_) | String(_) | Timestamp(_), Date(_)) => true,
|
||||
(Date(_), Date(_)) => true,
|
||||
// DateTime type
|
||||
(DateTime(_), Int64(_) | Timestamp(_) | String(_)) => true,
|
||||
(Int64(_) | Timestamp(_) | String(_), DateTime(_)) => true,
|
||||
(DateTime(_), DateTime(_)) => true,
|
||||
// Timestamp type
|
||||
(Timestamp(_), Int64(_) | String(_)) => true,
|
||||
(Int64(_) | String(_), Timestamp(_)) => true,
|
||||
(Timestamp(_), Timestamp(_)) => true,
|
||||
// Time type
|
||||
(Time(_), String(_)) => true,
|
||||
(Time(Second(_)), Int32(_)) => true,
|
||||
(Time(Millisecond(_)), Int32(_)) => true,
|
||||
(Time(Microsecond(_)), Int64(_)) => true,
|
||||
(Time(Nanosecond(_)), Int64(_)) => true,
|
||||
(Time(_), Time(_)) => true,
|
||||
// TODO(QuenKar): interval type cast
|
||||
(Interval(_), String(_)) => true,
|
||||
(Duration(_), String(_)) => true,
|
||||
|
||||
@@ -61,6 +61,7 @@ impl DataType for DateType {
|
||||
Value::Int32(v) => Some(Value::Date(Date::from(v))),
|
||||
Value::String(v) => Date::from_str(v.as_utf8()).map(Value::Date).ok(),
|
||||
Value::Timestamp(v) => v.to_chrono_date().map(|date| Value::Date(date.into())),
|
||||
Value::DateTime(v) => Some(Value::DateTime(v)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -103,6 +103,14 @@ pub enum Error {
|
||||
source: datatypes::error::Error,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to cast SQL value {} to datatype {}", sql_value, datatype))]
|
||||
InvalidCast {
|
||||
sql_value: sqlparser::ast::Value,
|
||||
datatype: ConcreteDataType,
|
||||
location: Location,
|
||||
source: datatypes::error::Error,
|
||||
},
|
||||
|
||||
#[snafu(display("Invalid table option key: {}", key))]
|
||||
InvalidTableOption { key: String, location: Location },
|
||||
|
||||
@@ -172,7 +180,8 @@ impl ErrorExt for Error {
|
||||
| InvalidTableName { .. }
|
||||
| InvalidSqlValue { .. }
|
||||
| TimestampOverflow { .. }
|
||||
| InvalidTableOption { .. } => StatusCode::InvalidArguments,
|
||||
| InvalidTableOption { .. }
|
||||
| InvalidCast { .. } => StatusCode::InvalidArguments,
|
||||
|
||||
SerializeColumnDefaultConstraint { source, .. } => source.status_code(),
|
||||
ConvertToGrpcDataType { source, .. } => source.status_code(),
|
||||
|
||||
@@ -38,7 +38,8 @@ use common_query::AddColumnLocation;
|
||||
use common_time::Timestamp;
|
||||
use datatypes::prelude::ConcreteDataType;
|
||||
use datatypes::schema::{ColumnDefaultConstraint, ColumnSchema, COMMENT_KEY};
|
||||
use datatypes::types::TimestampType;
|
||||
use datatypes::types::cast::CastOption;
|
||||
use datatypes::types::{cast, TimestampType};
|
||||
use datatypes::value::{OrderedF32, OrderedF64, Value};
|
||||
pub use option_map::OptionMap;
|
||||
use snafu::{ensure, OptionExt, ResultExt};
|
||||
@@ -50,7 +51,7 @@ use crate::ast::{
|
||||
};
|
||||
use crate::error::{
|
||||
self, ColumnTypeMismatchSnafu, ConvertSqlValueSnafu, ConvertToGrpcDataTypeSnafu,
|
||||
ConvertValueSnafu, InvalidSqlValueSnafu, ParseSqlValueSnafu, Result,
|
||||
ConvertValueSnafu, InvalidCastSnafu, InvalidSqlValueSnafu, ParseSqlValueSnafu, Result,
|
||||
SerializeColumnDefaultConstraintSnafu, TimestampOverflowSnafu, UnsupportedDefaultValueSnafu,
|
||||
};
|
||||
|
||||
@@ -186,7 +187,7 @@ pub fn sql_value_to_value(
|
||||
data_type: &ConcreteDataType,
|
||||
sql_val: &SqlValue,
|
||||
) -> Result<Value> {
|
||||
Ok(match sql_val {
|
||||
let value = match sql_val {
|
||||
SqlValue::Number(n, _) => sql_number_to_value(data_type, n)?,
|
||||
SqlValue::Null => Value::Null,
|
||||
SqlValue::Boolean(b) => {
|
||||
@@ -215,7 +216,17 @@ pub fn sql_value_to_value(
|
||||
}
|
||||
.fail()
|
||||
}
|
||||
})
|
||||
};
|
||||
if value.data_type() != *data_type {
|
||||
cast::cast_with_opt(value, data_type, &CastOption { strict: true }).with_context(|_| {
|
||||
InvalidCastSnafu {
|
||||
sql_value: sql_val.clone(),
|
||||
datatype: data_type,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value_to_sql_value(val: &Value) -> Result<SqlValue> {
|
||||
|
||||
@@ -63,11 +63,11 @@ SELECT * FROM new_table;
|
||||
|
||||
ALTER TABLE new_table RENAME new_table;
|
||||
|
||||
Error: 4000(TableAlreadyExists), Table already exists: greptime.public.new_table
|
||||
Error: 4000(TableAlreadyExists), Table already exists, table: greptime.public.new_table
|
||||
|
||||
ALTER TABLE new_table RENAME t;
|
||||
|
||||
Error: 4000(TableAlreadyExists), Table already exists: greptime.public.t
|
||||
Error: 4000(TableAlreadyExists), Table already exists, table: greptime.public.t
|
||||
|
||||
DROP TABLE t;
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@ SHOW TABLES FROM public;
|
||||
| Tables |
|
||||
+---------+
|
||||
| numbers |
|
||||
| scripts |
|
||||
+---------+
|
||||
|
||||
INSERT INTO hello VALUES (2), (3), (4);
|
||||
@@ -103,7 +102,6 @@ SHOW TABLES FROM public;
|
||||
| Tables |
|
||||
+---------+
|
||||
| numbers |
|
||||
| scripts |
|
||||
+---------+
|
||||
|
||||
SHOW TABLES FROM public WHERE Tables='numbers';
|
||||
|
||||
@@ -316,33 +316,8 @@ INSERT INTO TABLE host_sec VALUES
|
||||
|
||||
Affected Rows: 18
|
||||
|
||||
SELECT ts, host, min(val) RANGE '10s', max(val) RANGE '10s' FROM host_sec ALIGN '5s' ORDER BY host, ts;
|
||||
|
||||
+---------------------+-------+-------------------+-------------------+
|
||||
| ts | host | MIN(host_sec.val) | MAX(host_sec.val) |
|
||||
+---------------------+-------+-------------------+-------------------+
|
||||
| 1970-01-01T00:00:00 | host1 | 0.0 | 0.0 |
|
||||
| 1970-01-01T00:00:05 | host1 | 0.0 | 1.0 |
|
||||
| 1970-01-01T00:00:10 | host1 | 1.0 | 2.0 |
|
||||
| 1970-01-01T00:00:15 | host1 | 2.0 | 3.0 |
|
||||
| 1970-01-01T00:00:20 | host1 | 3.0 | 4.0 |
|
||||
| 1970-01-01T00:00:25 | host1 | 4.0 | 5.0 |
|
||||
| 1970-01-01T00:00:30 | host1 | 5.0 | 6.0 |
|
||||
| 1970-01-01T00:00:35 | host1 | 6.0 | 7.0 |
|
||||
| 1970-01-01T00:00:40 | host1 | 7.0 | 8.0 |
|
||||
| 1970-01-01T00:00:45 | host1 | 8.0 | 8.0 |
|
||||
| 1970-01-01T00:00:00 | host2 | 9.0 | 9.0 |
|
||||
| 1970-01-01T00:00:05 | host2 | 9.0 | 10.0 |
|
||||
| 1970-01-01T00:00:10 | host2 | 10.0 | 11.0 |
|
||||
| 1970-01-01T00:00:15 | host2 | 11.0 | 12.0 |
|
||||
| 1970-01-01T00:00:20 | host2 | 12.0 | 13.0 |
|
||||
| 1970-01-01T00:00:25 | host2 | 13.0 | 14.0 |
|
||||
| 1970-01-01T00:00:30 | host2 | 14.0 | 15.0 |
|
||||
| 1970-01-01T00:00:35 | host2 | 15.0 | 16.0 |
|
||||
| 1970-01-01T00:00:40 | host2 | 16.0 | 17.0 |
|
||||
| 1970-01-01T00:00:45 | host2 | 17.0 | 17.0 |
|
||||
+---------------------+-------+-------------------+-------------------+
|
||||
|
||||
-- TODO(ruihang): This query returns incorrect result.
|
||||
-- SELECT ts, host, min(val) RANGE '10s', max(val) RANGE '10s' FROM host_sec ALIGN '5s' ORDER BY host, ts;
|
||||
DROP TABLE host_sec;
|
||||
|
||||
Affected Rows: 1
|
||||
|
||||
@@ -90,6 +90,7 @@ INSERT INTO TABLE host_sec VALUES
|
||||
(35, 'host2', 16.0),
|
||||
(40, 'host2', 17.0);
|
||||
|
||||
SELECT ts, host, min(val) RANGE '10s', max(val) RANGE '10s' FROM host_sec ALIGN '5s' ORDER BY host, ts;
|
||||
-- TODO(ruihang): This query returns incorrect result.
|
||||
-- SELECT ts, host, min(val) RANGE '10s', max(val) RANGE '10s' FROM host_sec ALIGN '5s' ORDER BY host, ts;
|
||||
|
||||
DROP TABLE host_sec;
|
||||
|
||||
@@ -14,30 +14,23 @@ order by table_schema, table_name;
|
||||
|
||||
select * from information_schema.columns order by table_schema, table_name;
|
||||
|
||||
+---------------+--------------------+------------+---------------+----------------------+---------------+
|
||||
| table_catalog | table_schema | table_name | column_name | data_type | semantic_type |
|
||||
+---------------+--------------------+------------+---------------+----------------------+---------------+
|
||||
| greptime | information_schema | columns | table_catalog | String | FIELD |
|
||||
| greptime | information_schema | columns | table_schema | String | FIELD |
|
||||
| greptime | information_schema | columns | table_name | String | FIELD |
|
||||
| greptime | information_schema | columns | column_name | String | FIELD |
|
||||
| greptime | information_schema | columns | data_type | String | FIELD |
|
||||
| greptime | information_schema | columns | semantic_type | String | FIELD |
|
||||
| greptime | information_schema | tables | table_catalog | String | FIELD |
|
||||
| greptime | information_schema | tables | table_schema | String | FIELD |
|
||||
| greptime | information_schema | tables | table_name | String | FIELD |
|
||||
| greptime | information_schema | tables | table_type | String | FIELD |
|
||||
| greptime | information_schema | tables | table_id | UInt32 | FIELD |
|
||||
| greptime | information_schema | tables | engine | String | FIELD |
|
||||
| greptime | public | numbers | number | UInt32 | TAG |
|
||||
| greptime | public | scripts | schema | String | TAG |
|
||||
| greptime | public | scripts | name | String | TAG |
|
||||
| greptime | public | scripts | script | String | FIELD |
|
||||
| greptime | public | scripts | engine | String | FIELD |
|
||||
| greptime | public | scripts | timestamp | TimestampMillisecond | TIMESTAMP |
|
||||
| greptime | public | scripts | gmt_created | TimestampMillisecond | FIELD |
|
||||
| greptime | public | scripts | gmt_modified | TimestampMillisecond | FIELD |
|
||||
+---------------+--------------------+------------+---------------+----------------------+---------------+
|
||||
+---------------+--------------------+------------+---------------+-----------+---------------+
|
||||
| table_catalog | table_schema | table_name | column_name | data_type | semantic_type |
|
||||
+---------------+--------------------+------------+---------------+-----------+---------------+
|
||||
| greptime | information_schema | columns | table_catalog | String | FIELD |
|
||||
| greptime | information_schema | columns | table_schema | String | FIELD |
|
||||
| greptime | information_schema | columns | table_name | String | FIELD |
|
||||
| greptime | information_schema | columns | column_name | String | FIELD |
|
||||
| greptime | information_schema | columns | data_type | String | FIELD |
|
||||
| greptime | information_schema | columns | semantic_type | String | FIELD |
|
||||
| greptime | information_schema | tables | table_catalog | String | FIELD |
|
||||
| greptime | information_schema | tables | table_schema | String | FIELD |
|
||||
| greptime | information_schema | tables | table_name | String | FIELD |
|
||||
| greptime | information_schema | tables | table_type | String | FIELD |
|
||||
| greptime | information_schema | tables | table_id | UInt32 | FIELD |
|
||||
| greptime | information_schema | tables | engine | String | FIELD |
|
||||
| greptime | public | numbers | number | UInt32 | TAG |
|
||||
+---------------+--------------------+------------+---------------+-----------+---------------+
|
||||
|
||||
create
|
||||
database my_db;
|
||||
|
||||
@@ -21,7 +21,6 @@ show tables;
|
||||
| Tables |
|
||||
+---------+
|
||||
| numbers |
|
||||
| scripts |
|
||||
+---------+
|
||||
|
||||
create table t3 (c timestamp time index);
|
||||
|
||||
@@ -54,21 +54,12 @@ SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=1 WHERE i1.i>
|
||||
| 3 | |
|
||||
+---+---+
|
||||
|
||||
SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i IS NOT NULL ORDER BY 2;
|
||||
|
||||
++
|
||||
++
|
||||
|
||||
SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i>1 ORDER BY 2;
|
||||
|
||||
++
|
||||
++
|
||||
|
||||
SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE CASE WHEN i2.i IS NULL THEN False ELSE True END ORDER BY 2;
|
||||
|
||||
++
|
||||
++
|
||||
|
||||
-- ignore: ON 1=0 is not supported
|
||||
-- SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i IS NOT NULL ORDER BY 2;
|
||||
-- ignore: IGNORE ON 1=0 is not supported
|
||||
-- SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i>1 ORDER BY 2;
|
||||
-- ignore: IGNORE ON 1=0 is not supported
|
||||
-- SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE CASE WHEN i2.i IS NULL THEN False ELSE True END ORDER BY 2;
|
||||
SELECT DISTINCT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i IS NULL ORDER BY 1;
|
||||
|
||||
+---+---+
|
||||
@@ -197,11 +188,8 @@ SELECT i FROM (SELECT * FROM integers i1 UNION SELECT * FROM integers i2) a WHER
|
||||
-- | 3 | 3 | 9 |
|
||||
-- +---+---+--------------+
|
||||
-- SELECT * FROM (SELECT i1.i AS a, i2.i AS b, row_number() OVER (ORDER BY i1.i, i2.i) FROM integers i1, integers i2 WHERE i1.i IS NOT NULL AND i2.i IS NOT NULL) a1 WHERE a=b ORDER BY 1;
|
||||
SELECT * FROM (SELECT 0=1 AS cond FROM integers i1, integers i2) a1 WHERE cond ORDER BY 1;
|
||||
|
||||
++
|
||||
++
|
||||
|
||||
-- TODO(ruihang): Invalid argument error: must either specify a row count or at least one column
|
||||
-- SELECT * FROM (SELECT 0=1 AS cond FROM integers i1, integers i2) a1 WHERE cond ORDER BY 1;
|
||||
SELECT * FROM (SELECT 0=1 AS cond FROM integers i1, integers i2 GROUP BY 1) a1 WHERE cond ORDER BY 1;
|
||||
|
||||
Error: 3001(EngineExecuteQuery), Error during planning: Attempted to create Filter predicate with expression `Boolean(false)` aliased as 'Int64(0) = Int64(1)'. Filter predicates should not be aliased.
|
||||
|
||||
@@ -12,11 +12,14 @@ SELECT i1.i,i2.i FROM integers i1 JOIN integers i2 ON i1.i=i2.i WHERE i1.i>1 ORD
|
||||
|
||||
SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=1 WHERE i1.i>2 ORDER BY 2;
|
||||
|
||||
SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i IS NOT NULL ORDER BY 2;
|
||||
-- ignore: ON 1=0 is not supported
|
||||
-- SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i IS NOT NULL ORDER BY 2;
|
||||
|
||||
SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i>1 ORDER BY 2;
|
||||
-- ignore: IGNORE ON 1=0 is not supported
|
||||
-- SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i>1 ORDER BY 2;
|
||||
|
||||
SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE CASE WHEN i2.i IS NULL THEN False ELSE True END ORDER BY 2;
|
||||
-- ignore: IGNORE ON 1=0 is not supported
|
||||
-- SELECT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE CASE WHEN i2.i IS NULL THEN False ELSE True END ORDER BY 2;
|
||||
|
||||
SELECT DISTINCT i1.i,i2.i FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i IS NULL ORDER BY 1;
|
||||
|
||||
@@ -55,7 +58,8 @@ SELECT i FROM (SELECT * FROM integers i1 UNION SELECT * FROM integers i2) a WHER
|
||||
-- +---+---+--------------+
|
||||
-- SELECT * FROM (SELECT i1.i AS a, i2.i AS b, row_number() OVER (ORDER BY i1.i, i2.i) FROM integers i1, integers i2 WHERE i1.i IS NOT NULL AND i2.i IS NOT NULL) a1 WHERE a=b ORDER BY 1;
|
||||
|
||||
SELECT * FROM (SELECT 0=1 AS cond FROM integers i1, integers i2) a1 WHERE cond ORDER BY 1;
|
||||
-- TODO(ruihang): Invalid argument error: must either specify a row count or at least one column
|
||||
-- SELECT * FROM (SELECT 0=1 AS cond FROM integers i1, integers i2) a1 WHERE cond ORDER BY 1;
|
||||
|
||||
SELECT * FROM (SELECT 0=1 AS cond FROM integers i1, integers i2 GROUP BY 1) a1 WHERE cond ORDER BY 1;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ SHOW CREATE TABLE system_metrics;
|
||||
| | TIME INDEX ("ts"), |
|
||||
| | PRIMARY KEY ("id", "host") |
|
||||
| | ) |
|
||||
| | |
|
||||
| | ENGINE=mito |
|
||||
| | WITH( |
|
||||
| | regions = 1, |
|
||||
|
||||
Reference in New Issue
Block a user