Files
email-tracker/external/duckdb/test/api/test_plan_serialization.cpp
2025-10-24 19:21:19 -05:00

157 lines
4.8 KiB
C++

#include "catch.hpp"
#include "duckdb/execution/physical_plan_generator.hpp"
#include "duckdb/optimizer/optimizer.hpp"
#include "duckdb/parallel/thread_context.hpp"
#include "duckdb/planner/planner.hpp"
#include "test_helpers.hpp"
#include "duckdb/parser/parser.hpp"
#include <map>
#include <set>
using namespace duckdb;
using namespace std;
static void test_helper(string sql, duckdb::vector<string> fixtures = duckdb::vector<string>()) {
DuckDB db;
Connection con(db);
for (const auto &fixture : fixtures) {
con.SendQuery(fixture);
}
Parser p;
p.ParseQuery(sql);
for (auto &statement : p.statements) {
con.context->transaction.BeginTransaction();
// Should that be the default "ToString"?
string statement_sql(statement->query.c_str() + statement->stmt_location, statement->stmt_length);
Planner planner(*con.context);
planner.CreatePlan(std::move(statement));
auto plan = std::move(planner.plan);
Optimizer optimizer(*planner.binder, *con.context);
plan = optimizer.Optimize(std::move(plan));
// LogicalOperator's copy utilizes its serialize and deserialize methods
auto new_plan = plan->Copy(*con.context);
auto optimized_plan = optimizer.Optimize(std::move(new_plan));
con.context->transaction.Commit();
}
}
static void test_helper_multi_db(string sql, duckdb::vector<string> fixtures = duckdb::vector<string>()) {
DuckDB db;
Connection con(db);
REQUIRE_NO_FAIL(con.Query("ATTACH DATABASE ':memory:' AS new_db;"));
for (const auto &fixture : fixtures) {
con.SendQuery(fixture);
}
Parser p;
p.ParseQuery(sql);
for (auto &statement : p.statements) {
con.context->transaction.BeginTransaction();
// Should that be the default "ToString"?
string statement_sql(statement->query.c_str() + statement->stmt_location, statement->stmt_length);
Planner planner(*con.context);
planner.CreatePlan(std::move(statement));
auto plan = std::move(planner.plan);
Optimizer optimizer(*planner.binder, *con.context);
plan = optimizer.Optimize(std::move(plan));
// LogicalOperator's copy utilizes its serialize and deserialize methods
auto new_plan = plan->Copy(*con.context);
auto optimized_plan = optimizer.Optimize(std::move(new_plan));
con.context->transaction.Commit();
}
}
TEST_CASE("Test logical_set", "[serialization]") {
test_helper("SET memory_limit='10GB'");
}
TEST_CASE("Test logical_show", "[serialization]") {
test_helper("SHOW SELECT 42");
}
TEST_CASE("Test logical_explain", "[serialization]") {
test_helper("EXPLAIN SELECT 42");
}
TEST_CASE("Test logical_empty_result", "[serialization]") {
test_helper("SELECT * FROM (SELECT 42) WHERE 1>2");
}
TEST_CASE("Test create_table", "[serialization]") {
test_helper("CREATE TABLE tbl (foo INTEGER)");
}
TEST_CASE("Test insert_into", "[serialization]") {
test_helper("INSERT INTO tbl VALUES(1)", {"CREATE TABLE tbl (foo INTEGER)"});
}
TEST_CASE("Test logical_delete", "[serialization]") {
test_helper("DELETE FROM tbl", {"CREATE TABLE tbl (foo INTEGER)"});
}
// TODO: only select for now
// TEST_CASE("Test logical_create_index", "[serialization]") {
// test_helper("CREATE INDEX idx ON tbl (foo)", {"CREATE TABLE tbl (foo INTEGER)"});
//}
// TODO: only select for now
// TEST_CASE("Test logical_create_schema", "[serialization]") {
// test_helper("CREATE SCHEMA test");
//}
// TODO: only select for now
// TEST_CASE("Test logical_create_view", "[serialization]") {
// test_helper("CREATE VIEW test_view AS (SELECT 42)");
//}
TEST_CASE("Test logical_update", "[serialization]") {
test_helper("UPDATE tbl SET foo=42", {"CREATE TABLE tbl (foo INTEGER)"});
}
// TODO(stephwang): revisit this later since it doesn't work yet
// TEST_CASE("Test logical_copy_to_file", "[serialization]") {
// test_helper("COPY tbl TO 'test_table.csv' ( DELIMITER '|', HEADER )", {"CREATE TABLE tbl (foo INTEGER)"});
//}
// TODO(stephwang): revisit this later since it doesn't work yet
// TEST_CASE("Test logical_prepare", "[serialization]") {
// test_helper("PREPARE v1 AS SELECT 42");
//}
TEST_CASE("Test logical_simple with DROP", "[serialization]") {
test_helper("DROP TABLE tbl", {"CREATE TABLE tbl (foo INTEGER)"});
}
TEST_CASE("Test logical_simple with ALTER", "[serialization]") {
test_helper("ALTER TABLE tbl ADD COLUMN bar INTEGER", {"CREATE TABLE tbl (foo INTEGER)"});
}
TEST_CASE("Test logical_simple with LOAD", "[serialization]") {
test_helper("LOAD foo");
}
// below test cases are oriented towards multi-databases
TEST_CASE("Test create_table with catalog", "[serialization]") {
test_helper_multi_db("CREATE TABLE new_db.main.tbl(i INTEGER);");
}
TEST_CASE("Test logical_insert with catalog", "[serialization]") {
test_helper_multi_db("INSERT INTO new_db.main.tbl VALUES(1)", {"CREATE TABLE new_db.main.tbl (foo INTEGER)"});
}
TEST_CASE("Test logical_update with catalog", "[serialization]") {
test_helper_multi_db("UPDATE new_db.main.tbl SET foo=42", {"CREATE TABLE new_db.main.tbl (foo INTEGER)"});
}