Skip to content

Commit b16b82f

Browse files
committedDec 8, 2022
test against sqlite's test suite
Signed-off-by: xxchan <[email protected]>
1 parent 6f8b7de commit b16b82f

File tree

8 files changed

+144550
-9
lines changed

8 files changed

+144550
-9
lines changed
 

‎sqllogictest/src/runner.rs

+33-8
Original file line numberDiff line numberDiff line change
@@ -500,15 +500,30 @@ impl<D: AsyncDB> Runner<D> {
500500
}
501501
};
502502

503+
let mut value_sort = false;
503504
match sort_mode.as_ref().or(self.sort_mode.as_ref()) {
504505
None | Some(SortMode::NoSort) => {}
505506
Some(SortMode::RowSort) => {
506507
rows.sort_unstable();
507508
}
508-
Some(SortMode::ValueSort) => todo!("value sort"),
509+
Some(SortMode::ValueSort) => {
510+
rows = rows
511+
.iter()
512+
.flat_map(|row| row.iter())
513+
.map(|s| vec![s.to_owned()])
514+
.collect();
515+
rows.sort_unstable();
516+
value_sort = true;
517+
}
509518
};
510519

511-
if self.hash_threshold > 0 && rows.len() * types.len() > self.hash_threshold {
520+
let num_values = if value_sort {
521+
rows.len()
522+
} else {
523+
rows.len() * types.len()
524+
};
525+
526+
if self.hash_threshold > 0 && num_values > self.hash_threshold {
512527
let mut md5 = md5::Context::new();
513528
for line in &rows {
514529
for value in line {
@@ -692,17 +707,27 @@ impl<D: AsyncDB> Runner<D> {
692707
}
693708

694709
// We compare normalized results. Whitespace characters are ignored.
695-
let normalized_rows = rows
696-
.into_iter()
697-
.map(|strs| strs.iter().map(normalize_string).join(" "))
698-
.collect_vec();
699710

700711
let expected_results = expected_results.iter().map(normalize_string).collect_vec();
701-
if !(self.validator)(&normalized_rows, &expected_results) {
712+
713+
let actual_results =
714+
if types.len() > 1 && rows.len() * types.len() == expected_results.len() {
715+
// value-wise mode
716+
rows.into_iter()
717+
.flat_map(|strs| strs.iter().map(normalize_string).collect_vec())
718+
.collect_vec()
719+
} else {
720+
// row-wise mode
721+
rows.into_iter()
722+
.map(|strs| strs.iter().map(normalize_string).join(" "))
723+
.collect_vec()
724+
};
725+
726+
if !(self.validator)(&actual_results, &expected_results) {
702727
return Err(TestErrorKind::QueryResultMismatch {
703728
sql,
704729
expected: expected_results.join("\n"),
705-
actual: normalized_rows.join("\n"),
730+
actual: actual_results.join("\n"),
706731
}
707732
.at(loc));
708733
}

‎tests/Cargo.toml

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@ publish = false
66

77
[dependencies]
88
sqllogictest = { path = "../sqllogictest" }
9+
rusqlite = { version = "0.28", features = ["bundled"] }
910

1011
[[test]]
1112
name = "harness"
1213
path = "./harness.rs"
13-
harness = false
14+
harness = false
15+
16+
[[test]]
17+
name = "sqlite"
18+
path = "./sqlite.rs"
19+
harness = false

‎tests/sqlite.rs

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use rusqlite::{types::ValueRef, Connection, Error};
2+
3+
use sqllogictest::{harness, ColumnType, DBOutput, Runner, DB};
4+
5+
fn hash_threshold(filename: &str) -> usize {
6+
match filename {
7+
"sqlite/select1.test" => 8,
8+
"sqlite/select4.test" => 8,
9+
"sqlite/select5.test" => 8,
10+
_ => 0,
11+
}
12+
}
13+
14+
fn main() {
15+
let paths = harness::glob("sqlite/**/*.test").unwrap();
16+
let mut tests = vec![];
17+
for entry in paths {
18+
let path = entry.unwrap();
19+
let filename = path.to_str().unwrap().to_string();
20+
tests.push(harness::Trial::test(filename.clone(), move || {
21+
let mut tester = Runner::new(db_fn());
22+
tester.with_hash_threshold(hash_threshold(&filename));
23+
tester.run_file(path)?;
24+
Ok(())
25+
}));
26+
}
27+
harness::run(&harness::Arguments::from_args(), tests).exit();
28+
}
29+
30+
struct ConnectionWrapper(Connection);
31+
32+
fn db_fn() -> ConnectionWrapper {
33+
let c = Connection::open_in_memory().unwrap();
34+
ConnectionWrapper(c)
35+
}
36+
37+
fn value_to_string(v: ValueRef) -> String {
38+
match v {
39+
ValueRef::Null => "NULL".to_string(),
40+
ValueRef::Integer(i) => i.to_string(),
41+
ValueRef::Real(r) => r.to_string(),
42+
ValueRef::Text(s) => std::str::from_utf8(s).unwrap().to_string(),
43+
ValueRef::Blob(_) => todo!(),
44+
}
45+
}
46+
47+
impl DB for ConnectionWrapper {
48+
type Error = Error;
49+
50+
fn run(&mut self, sql: &str) -> Result<DBOutput, Self::Error> {
51+
let mut output = vec![];
52+
53+
let is_query_sql = {
54+
let lower_sql = sql.trim_start().to_ascii_lowercase();
55+
lower_sql.starts_with("select")
56+
|| lower_sql.starts_with("values")
57+
|| lower_sql.starts_with("show")
58+
|| lower_sql.starts_with("with")
59+
|| lower_sql.starts_with("describe")
60+
};
61+
62+
if is_query_sql {
63+
let mut stmt = self.0.prepare(sql)?;
64+
let column_count = stmt.column_count();
65+
let mut rows = stmt.query([])?;
66+
while let Some(row) = rows.next()? {
67+
let mut row_output = vec![];
68+
for i in 0..column_count {
69+
let row = row.get_ref(i)?;
70+
row_output.push(value_to_string(row));
71+
}
72+
output.push(row_output);
73+
}
74+
Ok(DBOutput::Rows {
75+
types: vec![ColumnType::Any; column_count],
76+
rows: output,
77+
})
78+
} else {
79+
let cnt = self.0.execute(sql, [])?;
80+
Ok(DBOutput::StatementComplete(cnt as u64))
81+
}
82+
}
83+
84+
fn engine_name(&self) -> &str {
85+
"sqlite"
86+
}
87+
}

0 commit comments

Comments
 (0)
Please sign in to comment.