Skip to content

Commit b12f2ec

Browse files
mamcxCentril
authored andcommitted
Forbid unsupported syntax in SELECT & improve sql test suite (#5)
* Forbid unsupported syntax in SELECT (like ORDER BY) & improve accuracy of sql test suite * Update crates/sqltest/src/main.rs Co-authored-by: Mazdak Farrokhzad <[email protected]> Signed-off-by: Mario Montoya <[email protected]> --------- Signed-off-by: Mario Montoya <[email protected]> Co-authored-by: Mazdak Farrokhzad <[email protected]>
1 parent 4e7da2c commit b12f2ec

File tree

5 files changed

+92
-20
lines changed

5 files changed

+92
-20
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,4 @@ new.json
204204

205205
# Keys
206206
*.pem
207+
.ok.sql

crates/core/src/sql/ast.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,31 @@ fn compile_select(db: &RelationalDB, select: Select) -> Result<SqlAst, PlanError
546546
}
547547

548548
fn compile_query(db: &RelationalDB, query: Query) -> Result<SqlAst, PlanError> {
549+
unsupported!(
550+
"SELECT",
551+
query.order_by,
552+
query.fetch,
553+
query.limit,
554+
query.offset,
555+
query.lock,
556+
query.with
557+
);
558+
549559
match *query.body {
550-
SetExpr::Select(select) => compile_select(db, *select),
560+
SetExpr::Select(select) => {
561+
unsupported!(
562+
"SELECT",
563+
select.distinct,
564+
select.top,
565+
select.into,
566+
select.lateral_views,
567+
select.group_by,
568+
select.having,
569+
select.sort_by
570+
);
571+
572+
compile_select(db, *select)
573+
}
551574
SetExpr::Query(_) => Err(PlanError::Unsupported {
552575
feature: "Query".into(),
553576
}),

crates/sqltest/src/main.rs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,20 @@ async fn run_serial(test_suite: &mut TestSuite, files: Vec<PathBuf>, engine: DbT
135135

136136
for file in files {
137137
let engine = open_db(&engine).await?;
138+
let db_name = engine.engine_name().to_string();
138139
let runner = Runner::new(engine);
139140
let filename = file.to_string_lossy().to_string();
140141
let test_case_name = filename.replace(['/', ' ', '.', '-'], "_");
141-
let case = match run_test_file(&mut std::io::stdout(), runner, &file).await {
142-
Ok(duration) => {
143-
let mut case = TestCase::new(test_case_name, TestCaseStatus::success());
142+
let case = match run_test_file(&mut std::io::stdout(), runner, &file, &db_name).await {
143+
Ok((skipped, duration)) => {
144+
let status = if skipped {
145+
TestCaseStatus::skipped()
146+
} else {
147+
TestCaseStatus::success()
148+
};
149+
150+
let mut case = TestCase::new(test_case_name, status);
151+
144152
case.set_time(duration);
145153
case.set_timestamp(Local::now());
146154
case.set_classname(TEST_NAME);
@@ -169,10 +177,11 @@ async fn run_serial(test_suite: &mut TestSuite, files: Vec<PathBuf>, engine: DbT
169177
}
170178
println!();
171179

172-
let total = test_suite.tests;
180+
let total = test_suite.tests - test_suite.disabled;
173181
let failed = test_suite.failures + test_suite.errors;
174-
let ok = test_suite.tests - failed;
182+
let ok = total - failed;
175183
println!("{}: {}", style("[FAILED]").red().bold(), failed);
184+
println!("{}: {}", style("[SKIP ]").yellow().bold(), test_suite.disabled);
176185
println!("{}: {}", style("[OK ]").green().bold(), ok);
177186
println!("{}: {}%", style("[PASS ]").blue().bold(), (ok * 100) / total);
178187
println!("{}: {:?}", style("[Elapsed]").reverse().bold(), start.elapsed());
@@ -186,12 +195,15 @@ async fn run_test_file<T: std::io::Write, D: AsyncDB>(
186195
out: &mut T,
187196
mut runner: Runner<D>,
188197
filename: impl AsRef<Path>,
189-
) -> anyhow::Result<Duration> {
198+
db_name: &str,
199+
) -> anyhow::Result<(bool, Duration)> {
190200
let filename = filename.as_ref();
191201
let records = sqllogictest::parse_file(filename).map_err(|e| anyhow!("{:?}", e))?;
192202

193203
let mut begin_times = vec![];
194204
let mut did_pop = false;
205+
let mut skipped = 0;
206+
let mut total = 0;
195207

196208
writeln!(out, "{: <60} .. ", filename.to_string_lossy())?;
197209
flush(out).await?;
@@ -212,11 +224,23 @@ async fn run_test_file<T: std::io::Write, D: AsyncDB>(
212224
flush(out).await?;
213225
}
214226
Record::Injected(Injected::EndInclude(file)) => {
215-
finish_test_file(out, &mut begin_times, &mut did_pop, file).await?;
227+
finish_test_file(out, &mut begin_times, &mut did_pop, file, total - skipped == 0).await?;
216228
}
217229
_ => {}
218230
}
219231

232+
let will_skip = match &record {
233+
Record::Statement { conditions, .. } | Record::Query { conditions, .. } => {
234+
total += 1;
235+
conditions.iter().any(|c| c.should_skip(db_name))
236+
}
237+
_ => false,
238+
};
239+
240+
if will_skip {
241+
skipped += 1;
242+
}
243+
220244
runner
221245
.run(record)
222246
.map_err(|e| anyhow!("{}", e.display(console::colors_enabled())))
@@ -225,20 +249,35 @@ async fn run_test_file<T: std::io::Write, D: AsyncDB>(
225249

226250
let duration = begin_times[0].elapsed();
227251

228-
finish_test_file(out, &mut begin_times, &mut did_pop, &filename.to_string_lossy()).await?;
252+
let skipped = total - skipped == 0;
253+
254+
finish_test_file(
255+
out,
256+
&mut begin_times,
257+
&mut did_pop,
258+
&filename.to_string_lossy(),
259+
skipped,
260+
)
261+
.await?;
229262

230263
writeln!(out)?;
231264

232-
Ok(duration)
265+
Ok((skipped, duration))
233266
}
234267

235268
async fn finish_test_file<T: std::io::Write>(
236269
out: &mut T,
237270
time_stack: &mut Vec<Instant>,
238271
did_pop: &mut bool,
239272
file: &str,
273+
skipped: bool,
240274
) -> anyhow::Result<()> {
241275
let begin_time = time_stack.pop().unwrap();
276+
let result = if skipped {
277+
style("[SKIP]").yellow().strikethrough().bold()
278+
} else {
279+
style("[OK]").green().bold()
280+
};
242281

243282
if *did_pop {
244283
// start a new line if the result is not immediately after the item
@@ -248,17 +287,12 @@ async fn finish_test_file<T: std::io::Write>(
248287
"| ".repeat(time_stack.len()),
249288
style("[END]").blue().bold(),
250289
file,
251-
style("[OK]").green().bold(),
290+
result,
252291
begin_time.elapsed().as_millis()
253292
)?;
254293
} else {
255294
// otherwise, append time to the previous line
256-
write!(
257-
out,
258-
"{} in {} ms",
259-
style("[OK]").green().bold(),
260-
begin_time.elapsed().as_millis()
261-
)?;
295+
write!(out, "{} in {} ms", result, begin_time.elapsed().as_millis())?;
262296
}
263297

264298
*did_pop = true;
@@ -392,7 +426,7 @@ async fn update_test_file<T: std::io::Write, D: AsyncDB>(
392426
Record::Injected(Injected::EndInclude(file)) => {
393427
override_with_outfile(filename, outfilename, outfile)?;
394428
stack.pop();
395-
finish_test_file(out, &mut begin_times, &mut did_pop, file).await?;
429+
finish_test_file(out, &mut begin_times, &mut did_pop, file, false).await?;
396430
}
397431
_ => {
398432
if *halt {
@@ -424,7 +458,7 @@ async fn update_test_file<T: std::io::Write, D: AsyncDB>(
424458
}
425459
}
426460

427-
finish_test_file(out, &mut begin_times, &mut did_pop, &filename.to_string_lossy()).await?;
461+
finish_test_file(out, &mut begin_times, &mut did_pop, &filename.to_string_lossy(), false).await?;
428462

429463
let Item {
430464
filename,

crates/sqltest/src/space.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use spacetimedb_sats::relation::MemTable;
77
use spacetimedb_sats::satn::Satn;
88
use spacetimedb_sats::{AlgebraicType, AlgebraicValue, BuiltinType, BuiltinValue};
99
use sqllogictest::{AsyncDB, ColumnType, DBOutput};
10+
use std::fs;
11+
use std::io::Write;
1012
use tempdir::TempDir;
1113

1214
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
@@ -46,6 +48,15 @@ impl ColumnType for Kind {
4648
}
4749
}
4850

51+
#[allow(dead_code)]
52+
fn append_file(to: &std::path::Path, content: &str) -> anyhow::Result<()> {
53+
let mut f = fs::OpenOptions::new().create(true).append(true).write(true).open(to)?;
54+
55+
f.write_all(format!("{content}\n").as_bytes())?;
56+
57+
Ok(())
58+
}
59+
4960
pub struct SpaceDb {
5061
pub(crate) conn: RelationalDB,
5162
#[allow(dead_code)]
@@ -62,7 +73,8 @@ impl SpaceDb {
6273
pub(crate) fn run_sql(&self, sql: &str) -> anyhow::Result<Vec<MemTable>> {
6374
let ast = compile_sql(&self.conn, sql)?;
6475
let result = execute_sql(&self.conn, ast)?;
65-
76+
//remove comments to see which SQL worked. Can't collect it outside from lack of a hook in the external `sqllogictest` crate... :(
77+
//append_file(&std::path::PathBuf::from(".ok.sql"), sql)?;
6678
Ok(result)
6779
}
6880

crates/sqltest/test/sql_2016/E101_03.slt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ CREATE TABLE TABLE_E101_03_01_01 ( A INT, B INT );
55
INSERT INTO TABLE_E101_03_01_01 VALUES ( 1, 2 );
66
UPDATE TABLE_E101_03_01_01 SET A = 3, B = 4
77

8+
# Cause panic for Space
9+
onlyif Postgres
810
statement ok
911
CREATE TABLE TABLE_E101_03_01_02 ( A INT, B INT );
1012
INSERT INTO TABLE_E101_03_01_02 VALUES ( 1, 2 );

0 commit comments

Comments
 (0)