Skip to content

Commit

Permalink
fix: type cast bugs found by sqlness (GreptimeTeam#2438)
Browse files Browse the repository at this point in the history
* update valid results

Signed-off-by: Ruihang Xia <[email protected]>

* accomplish datatype

Signed-off-by: Ruihang Xia <[email protected]>

* cast null

Signed-off-by: Ruihang Xia <[email protected]>

* fix unit tests

Signed-off-by: Ruihang Xia <[email protected]>

---------

Signed-off-by: Ruihang Xia <[email protected]>
  • Loading branch information
waynexia authored and paomian committed Oct 19, 2023
1 parent f7e2963 commit fcf6f9b
Show file tree
Hide file tree
Showing 14 changed files with 90 additions and 92 deletions.
23 changes: 18 additions & 5 deletions src/api/src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 6 additions & 1 deletion src/datatypes/src/types/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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(),
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/datatypes/src/types/date_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Expand Down
11 changes: 10 additions & 1 deletion src/sql/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 },

Expand Down Expand Up @@ -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(),
Expand Down
19 changes: 15 additions & 4 deletions src/sql/src/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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,
};

Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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> {
Expand Down
4 changes: 2 additions & 2 deletions tests/cases/standalone/common/alter/rename_table.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 0 additions & 2 deletions tests/cases/standalone/common/catalog/schema.result
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ SHOW TABLES FROM public;
| Tables |
+---------+
| numbers |
| scripts |
+---------+

INSERT INTO hello VALUES (2), (3), (4);
Expand Down Expand Up @@ -103,7 +102,6 @@ SHOW TABLES FROM public;
| Tables |
+---------+
| numbers |
| scripts |
+---------+

SHOW TABLES FROM public WHERE Tables='numbers';
Expand Down
29 changes: 2 additions & 27 deletions tests/cases/standalone/common/select/range_select.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion tests/cases/standalone/common/select/range_select.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;
41 changes: 17 additions & 24 deletions tests/cases/standalone/common/system/information_schema.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion tests/cases/standalone/create/recover_created.result
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ show tables;
| Tables |
+---------+
| numbers |
| scripts |
+---------+

create table t3 (c timestamp time index);
Expand Down
28 changes: 8 additions & 20 deletions tests/cases/standalone/optimizer/filter_push_down.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;

+---+---+
Expand Down Expand Up @@ -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.
Expand Down
12 changes: 8 additions & 4 deletions tests/cases/standalone/optimizer/filter_push_down.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions tests/cases/standalone/show/show_create.result
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ SHOW CREATE TABLE system_metrics;
| | TIME INDEX ("ts"), |
| | PRIMARY KEY ("id", "host") |
| | ) |
| | |
| | ENGINE=mito |
| | WITH( |
| | regions = 1, |
Expand Down

0 comments on commit fcf6f9b

Please sign in to comment.