Skip to content

Commit

Permalink
refactor: validate constraints eagerly (#3472)
Browse files Browse the repository at this point in the history
* chore: validate constraints eagerly

Signed-off-by: tison <wander4096@gmail.com>

* use timestamp column

Signed-off-by: tison <wander4096@gmail.com>

* fixup

Signed-off-by: tison <wander4096@gmail.com>

* lint

Signed-off-by: tison <wander4096@gmail.com>

* compile

Signed-off-by: tison <wander4096@gmail.com>

---------

Signed-off-by: tison <wander4096@gmail.com>
  • Loading branch information
tisonkun committed Mar 12, 2024
1 parent 7c895e2 commit cafb470
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 26 deletions.
44 changes: 20 additions & 24 deletions src/sql/src/parsers/create_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,21 @@ impl<'a> ParserContext<'a> {
let _ = self.parser.next_token();
self.parser
.expect_keyword(Keyword::TABLE)
.context(error::SyntaxSnafu)?;
.context(SyntaxSnafu)?;
let if_not_exists =
self.parser
.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
let table_name = self.intern_parse_table_name()?;
let (columns, constraints) = self.parse_columns()?;
if !columns.is_empty() {
validate_time_index(&columns, &constraints)?;
}

let engine = self.parse_table_engine(common_catalog::consts::FILE_ENGINE)?;
let options = self
.parser
.parse_options(Keyword::WITH)
.context(error::SyntaxSnafu)?
.context(SyntaxSnafu)?
.into_iter()
.filter_map(|option| {
if let Some(v) = parse_option_string(option.value) {
Expand Down Expand Up @@ -140,8 +144,12 @@ impl<'a> ParserContext<'a> {
}

let (columns, constraints) = self.parse_columns()?;
validate_time_index(&columns, &constraints)?;

let partitions = self.parse_partitions()?;
if let Some(partitions) = &partitions {
validate_partitions(&columns, partitions)?;
}

let engine = self.parse_table_engine(default_engine())?;
let options = self
Expand All @@ -168,7 +176,6 @@ impl<'a> ParserContext<'a> {
table_id: 0, // table id is assigned by catalog manager
partitions,
};
validate_create(&create_table)?;

Ok(Statement::CreateTable(create_table))
}
Expand Down Expand Up @@ -553,18 +560,8 @@ impl<'a> ParserContext<'a> {
}
}

fn validate_create(create_table: &CreateTable) -> Result<()> {
if let Some(partitions) = &create_table.partitions {
validate_partitions(&create_table.columns, partitions)?;
}
validate_time_index(create_table)?;

Ok(())
}

fn validate_time_index(create_table: &CreateTable) -> Result<()> {
let time_index_constraints: Vec<_> = create_table
.constraints
fn validate_time_index(columns: &[ColumnDef], constraints: &[TableConstraint]) -> Result<()> {
let time_index_constraints: Vec<_> = constraints
.iter()
.filter_map(|c| {
if let TableConstraint::Unique {
Expand Down Expand Up @@ -605,8 +602,7 @@ fn validate_time_index(create_table: &CreateTable) -> Result<()> {
// It's safe to use time_index_constraints[0][0],
// we already check the bound above.
let time_index_column_ident = &time_index_constraints[0][0];
let time_index_column = create_table
.columns
let time_index_column = columns
.iter()
.find(|c| c.name.value == *time_index_column_ident.value)
.with_context(|| InvalidTimeIndexSnafu {
Expand Down Expand Up @@ -753,7 +749,7 @@ mod tests {
fn test_validate_external_table_options() {
let sql = "CREATE EXTERNAL TABLE city (
host string,
ts int64,
ts timestamp,
cpu float64 default 0,
memory float64,
TIME INDEX (ts),
Expand Down Expand Up @@ -836,7 +832,7 @@ mod tests {
fn test_parse_create_external_table_with_schema() {
let sql = "CREATE EXTERNAL TABLE city (
host string,
ts int64,
ts timestamp,
cpu float32 default 0,
memory float64,
TIME INDEX (ts),
Expand All @@ -859,7 +855,7 @@ mod tests {

let columns = &c.columns;
assert_column_def(&columns[0], "host", "STRING");
assert_column_def(&columns[1], "ts", "BIGINT");
assert_column_def(&columns[1], "ts", "TIMESTAMP");
assert_column_def(&columns[2], "cpu", "FLOAT");
assert_column_def(&columns[3], "memory", "DOUBLE");

Expand Down Expand Up @@ -938,7 +934,7 @@ ENGINE=mito";
let _ = result.unwrap();

let sql = r"
CREATE TABLE rcx ( a INT, b STRING, c INT )
CREATE TABLE rcx ( ts TIMESTAMP TIME INDEX, a INT, b STRING, c INT )
PARTITION ON COLUMNS(x) ()
ENGINE=mito";
let result =
Expand Down Expand Up @@ -1326,7 +1322,7 @@ ENGINE=mito";
#[test]
fn test_parse_partitions_with_error_syntax() {
let sql = r"
CREATE TABLE rcx ( a INT, b STRING, c INT )
CREATE TABLE rcx ( ts TIMESTAMP TIME INDEX, a INT, b STRING, c INT )
PARTITION COLUMNS(c, a) (
a < 10,
a > 10 AND a < 20,
Expand Down Expand Up @@ -1355,7 +1351,7 @@ ENGINE=mito";
#[test]
fn test_parse_partitions_unreferenced_column() {
let sql = r"
CREATE TABLE rcx ( a INT, b STRING, c INT )
CREATE TABLE rcx ( ts TIMESTAMP TIME INDEX, a INT, b STRING, c INT )
PARTITION ON COLUMNS(c, a) (
b = 'foo'
)
Expand All @@ -1371,7 +1367,7 @@ ENGINE=mito";
#[test]
fn test_parse_partitions_not_binary_expr() {
let sql = r"
CREATE TABLE rcx ( a INT, b STRING, c INT )
CREATE TABLE rcx ( ts TIMESTAMP TIME INDEX, a INT, b STRING, c INT )
PARTITION ON COLUMNS(c, a) (
b
)
Expand Down
4 changes: 3 additions & 1 deletion src/sql/src/statements/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ pub struct CreateTableLike {

#[cfg(test)]
mod tests {
use std::assert_matches::assert_matches;

use crate::dialect::GreptimeDbDialect;
use crate::error::Error;
use crate::parser::{ParseOptions, ParserContext};
Expand Down Expand Up @@ -378,6 +380,6 @@ ENGINE=mito
";
let result =
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
assert!(matches!(result, Err(Error::InvalidTableOption { .. })));
assert_matches!(result, Err(Error::InvalidTableOption { .. }))
}
}
1 change: 1 addition & 0 deletions tests-integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(assert_matches)]
pub mod cluster;
mod grpc;
mod influxdb;
Expand Down
3 changes: 2 additions & 1 deletion tests-integration/src/tests/instance_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::assert_matches::assert_matches;
use std::env;
use std::sync::Arc;

Expand Down Expand Up @@ -639,7 +640,7 @@ async fn test_execute_external_create_without_ts(instance: Arc<dyn MockInstance>
),
)
.await;
assert!(matches!(result, Err(Error::TableOperation { .. })));
assert_matches!(result, Err(Error::ParseSql { .. }));
}

#[apply(both_instances_cases)]
Expand Down

0 comments on commit cafb470

Please sign in to comment.