From d4789d0a05bb3f8746cdadc053424b8703b2b1f9 Mon Sep 17 00:00:00 2001 From: meteorgan Date: Mon, 16 Jun 2025 22:31:06 +0800 Subject: [PATCH] add tests --- Makefile | 4 +++ core/translate/compound_select.rs | 38 ++++++++++++++++----- core/translate/select.rs | 5 +-- testing/select.test | 57 +++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 51dbdc052..3a93b4434 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,10 @@ test-compat: SQLITE_EXEC=$(SQLITE_EXEC) ./testing/all.test .PHONY: test-compat +test-select: + SQLITE_EXEC=$(SQLITE_EXEC) ./testing/select.test +.PHONY: test-select + test-vector: SQLITE_EXEC=$(SQLITE_EXEC) ./testing/vector.test .PHONY: test-vector diff --git a/core/translate/compound_select.rs b/core/translate/compound_select.rs index f9bfa018b..244bd663e 100644 --- a/core/translate/compound_select.rs +++ b/core/translate/compound_select.rs @@ -361,7 +361,7 @@ fn read_intersect_rows( left_cursor_id: usize, index: &Index, right_cursor_id: usize, - target_cursor_id: Option, + target_cursor: Option, ) { let label_close = program.allocate_label(); let label_loop_start = program.allocate_label(); @@ -372,8 +372,10 @@ fn read_intersect_rows( program.preassign_label_to_next_insn(label_loop_start); let row_content_reg = program.alloc_register(); - // we need to emit opcode RowData here - + program.emit_insn(Insn::RowData { + cursor_id: left_cursor_id, + dest: row_content_reg, + }); let label_next = program.allocate_label(); program.emit_insn(Insn::NotFound { cursor_id: right_cursor_id, @@ -381,18 +383,36 @@ fn read_intersect_rows( record_reg: row_content_reg, num_regs: 0, }); - let cols_start_reg = program.alloc_registers(index.columns.len()); - for i in 0..index.columns.len() { + let column_count = index.columns.len(); + let cols_start_reg = program.alloc_registers(column_count); + for i in 0..column_count { program.emit_insn(Insn::Column { cursor_id: left_cursor_id, column: i, dest: cols_start_reg + i, + default: None, + }); + } + if let Some(target_cursor_id) = target_cursor { + program.emit_insn(Insn::MakeRecord { + start_reg: cols_start_reg, + count: column_count, + dest_reg: row_content_reg, + index_name: None, + }); + program.emit_insn(Insn::IdxInsert { + cursor_id: target_cursor_id, + record_reg: row_content_reg, + unpacked_start: Some(cols_start_reg), + unpacked_count: Some(column_count as u16), + flags: Default::default(), + }); + } else { + program.emit_insn(Insn::ResultRow { + start_reg: cols_start_reg, + count: column_count, }); } - program.emit_insn(Insn::ResultRow { - start_reg: cols_start_reg, - count: index.columns.len(), - }); program.preassign_label_to_next_insn(label_next); program.emit_insn(Insn::Next { cursor_id: left_cursor_id, diff --git a/core/translate/select.rs b/core/translate/select.rs index 0a43f20cc..c08e597b0 100644 --- a/core/translate/select.rs +++ b/core/translate/select.rs @@ -127,12 +127,13 @@ pub fn prepare_select_plan( let mut left = Vec::with_capacity(compounds.len()); for CompoundSelect { select, operator } in compounds { - // TODO: add support for EXCEPT and INTERSECT + // TODO: add support for INTERSECT if operator != ast::CompoundOperator::UnionAll && operator != ast::CompoundOperator::Union + && operator != ast::CompoundOperator::Intersect { crate::bail_parse_error!( - "only UNION ALL and UNION are supported for compound SELECTs" + "only UNION ALL, UNION and INTERSECT are supported for compound SELECTs" ); } left.push((last, operator)); diff --git a/testing/select.test b/testing/select.test index 636058e23..1d1c5afb4 100755 --- a/testing/select.test +++ b/testing/select.test @@ -361,3 +361,60 @@ if {[info exists ::env(SQLITE_EXEC)] && ($::env(SQLITE_EXEC) eq "scripts/limbo-s y|y} } +select * from t UNION select * from u UNION select * from v UNION ALL select * from t; +} {x|x +y|y +x|x +y|y} + +do_execsql_test_on_specific_db {:memory:} select-intersect-1 { + CREATE TABLE t(x TEXT, y TEXT); + CREATE TABLE u(x TEXT, y TEXT); + INSERT INTO t VALUES('x','x'),('y','y'); + INSERT INTO u VALUES('x','x'),('z','y'); + + select * from t INTERSECT select * from u; +} {x|x} + +do_execsql_test_on_specific_db {:memory:} select-intersect-2 { + CREATE TABLE t(x TEXT, y TEXT); + CREATE TABLE u(x TEXT, y TEXT); + CREATE TABLE v(x TEXT, y TEXT); + INSERT INTO t VALUES('x','x'),('y','y'); + INSERT INTO u VALUES('x','x'),('y','y'); + INSERT INTO v VALUES('a','x'),('y','y'); + + select * from t INTERSECT select * from u INTERSECT select * from v INTERSECT select * from t; +} {y|y} + +do_execsql_test_on_specific_db {:memory:} select-intersect-union { + CREATE TABLE t(x TEXT, y TEXT); + CREATE TABLE u(x TEXT, y TEXT); + CREATE TABLE v(x TEXT, y TEXT); + INSERT INTO t VALUES('x','x'),('y','y'); + INSERT INTO u VALUES('x','x'),('z','y'); + INSERT INTO v VALUES('x','x'),('z','z'); + + select * from t INTERSECT select * from u UNION select * from v; +} {x|x +z|z} + +do_execsql_test_on_specific_db {:memory:} select-union-intersect { + CREATE TABLE t(x TEXT, y TEXT); + CREATE TABLE u(x TEXT, y TEXT); + CREATE TABLE v(x TEXT, y TEXT); + INSERT INTO t VALUES('x','x'),('y','y'); + INSERT INTO u VALUES('x','x'),('z','y'); + INSERT INTO v VALUES('x','x'),('z','z'); + + select * from t UNION select * from u INTERSECT select * from v; +} {x|x} + +#do_execsql_test_on_specific_db {:memory:} select-intersect-with-limit { +# CREATE TABLE t(x TEXT, y TEXT); +# CREATE TABLE u(x TEXT, y TEXT); +# INSERT INTO t VALUES('x','x'),('y','y'), ('z','z'); +# INSERT INTO u VALUES('x','x'),('y','y'), ('z','z'); + +# select * from t INTERSECT select * from u limit 2; +#} {x|x} \ No newline at end of file