should be it
This commit is contained in:
129
external/duckdb/test/api/test_read_only.cpp
vendored
Normal file
129
external/duckdb/test/api/test_read_only.cpp
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "catch.hpp"
|
||||
#include "duckdb/common/file_system.hpp"
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
using namespace duckdb;
|
||||
using namespace std;
|
||||
|
||||
TEST_CASE("Test connection using a read only database", "[readonly]") {
|
||||
auto dbdir = TestCreatePath("read_only_test");
|
||||
duckdb::unique_ptr<DuckDB> db, db2;
|
||||
duckdb::unique_ptr<Connection> con;
|
||||
// make sure the database does not exist
|
||||
DeleteDatabase(dbdir);
|
||||
|
||||
DBConfig readonly_config;
|
||||
readonly_config.options.use_temporary_directory = false;
|
||||
readonly_config.options.access_mode = AccessMode::READ_ONLY;
|
||||
|
||||
// cannot create read-only memory database
|
||||
REQUIRE_THROWS(db = make_uniq<DuckDB>(nullptr, &readonly_config));
|
||||
// cannot create a read-only database in a new directory
|
||||
REQUIRE_THROWS(db = make_uniq<DuckDB>(dbdir, &readonly_config));
|
||||
|
||||
// create the database file and initialize it with data
|
||||
db = make_uniq<DuckDB>(dbdir);
|
||||
con = make_uniq<Connection>(*db);
|
||||
REQUIRE_NO_FAIL(con->Query("CREATE TABLE integers(i INTEGER)"));
|
||||
REQUIRE_NO_FAIL(con->Query("INSERT INTO integers VALUES (1), (2), (3), (4), (5)"));
|
||||
con.reset();
|
||||
db.reset();
|
||||
|
||||
// now connect in read-only mode
|
||||
REQUIRE_NOTHROW(db = make_uniq<DuckDB>(dbdir, &readonly_config));
|
||||
con = make_uniq<Connection>(*db);
|
||||
|
||||
// we can query the database
|
||||
auto result = con->Query("SELECT * FROM integers ORDER BY i");
|
||||
REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 4, 5}));
|
||||
// however, we can't perform DDL statements
|
||||
REQUIRE_FAIL(con->Query("CREATE TABLE integers2(i INTEGER)"));
|
||||
REQUIRE_FAIL(con->Query("ALTER TABLE integers RENAME COLUMN i TO k"));
|
||||
REQUIRE_FAIL(con->Query("DROP TABLE integers"));
|
||||
REQUIRE_FAIL(con->Query("CREATE SEQUENCE seq"));
|
||||
REQUIRE_FAIL(con->Query("CREATE VIEW v1 AS SELECT * FROM integers"));
|
||||
// neither can we insert/update/delete data
|
||||
REQUIRE_FAIL(con->Query("INSERT INTO integers VALUES (3)"));
|
||||
REQUIRE_FAIL(con->Query("UPDATE integers SET i=5"));
|
||||
REQUIRE_FAIL(con->Query("DELETE FROM integers"));
|
||||
// we can run explain queries
|
||||
REQUIRE_NO_FAIL(con->Query("EXPLAIN SELECT * FROM integers"));
|
||||
// and run prepared statements
|
||||
REQUIRE_NO_FAIL(con->Query("PREPARE v1 AS SELECT * FROM integers"));
|
||||
REQUIRE_NO_FAIL(con->Query("EXECUTE v1"));
|
||||
REQUIRE_NO_FAIL(con->Query("DEALLOCATE v1"));
|
||||
// we can also prepare a DDL/update statement
|
||||
REQUIRE_NO_FAIL(con->Query("PREPARE v1 AS INSERT INTO integers VALUES ($1)"));
|
||||
// however, executing it fails then!
|
||||
REQUIRE_FAIL(con->Query("EXECUTE v1(3)"));
|
||||
|
||||
// we can create, alter and query temporary tables however
|
||||
REQUIRE_NO_FAIL(con->Query("CREATE TEMPORARY TABLE integers2(i INTEGER)"));
|
||||
REQUIRE_NO_FAIL(con->Query("INSERT INTO integers2 VALUES (1), (2), (3), (4), (5)"));
|
||||
REQUIRE_NO_FAIL(con->Query("UPDATE integers2 SET i=i+1"));
|
||||
result = con->Query("DELETE FROM integers2 WHERE i=3");
|
||||
REQUIRE(CHECK_COLUMN(result, 0, {1}));
|
||||
|
||||
REQUIRE_NO_FAIL(con->Query("ALTER TABLE integers2 RENAME COLUMN i TO k"));
|
||||
result = con->Query("SELECT k FROM integers2 ORDER BY 1");
|
||||
REQUIRE(CHECK_COLUMN(result, 0, {2, 4, 5, 6}));
|
||||
REQUIRE_NO_FAIL(con->Query("DROP TABLE integers2"));
|
||||
|
||||
// also temporary views and sequences
|
||||
REQUIRE_NO_FAIL(con->Query("CREATE TEMPORARY SEQUENCE seq"));
|
||||
result = con->Query("SELECT nextval('seq')");
|
||||
REQUIRE(CHECK_COLUMN(result, 0, {1}));
|
||||
REQUIRE_NO_FAIL(con->Query("DROP SEQUENCE seq"));
|
||||
|
||||
REQUIRE_NO_FAIL(con->Query("CREATE TEMPORARY VIEW v1 AS SELECT 42"));
|
||||
result = con->Query("SELECT * FROM v1");
|
||||
REQUIRE(CHECK_COLUMN(result, 0, {42}));
|
||||
REQUIRE_NO_FAIL(con->Query("DROP VIEW v1"));
|
||||
|
||||
con.reset();
|
||||
db.reset();
|
||||
// FIXME: these tests currently don't work as we don't do any locking of the database directory
|
||||
// this should be fixed with the new storage
|
||||
// we can connect multiple read only databases to the same dbdir
|
||||
// REQUIRE_NOTHROW(db = make_uniq<DuckDB>(dbdir, true));
|
||||
// REQUIRE_NOTHROW(db2 = make_uniq<DuckDB>(dbdir, true));
|
||||
// db.reset();
|
||||
// db2.reset();
|
||||
|
||||
// // however, if there is read-only database, we can't connect a read-write database
|
||||
// REQUIRE_NOTHROW(db = make_uniq<DuckDB>(dbdir, true));
|
||||
// REQUIRE_THROWS(db2 = make_uniq<DuckDB>(dbdir));
|
||||
// db.reset();
|
||||
// db2.reset();
|
||||
|
||||
// // if we add a read-write database first, we can't add a reading database afterwards either
|
||||
// REQUIRE_NOTHROW(db = make_uniq<DuckDB>(dbdir));
|
||||
// REQUIRE_THROWS(db2 = make_uniq<DuckDB>(dbdir, true));
|
||||
// db.reset();
|
||||
// db2.reset();
|
||||
DeleteDatabase(dbdir);
|
||||
}
|
||||
|
||||
TEST_CASE("Test view creation using a read only database", "[readonly]") {
|
||||
auto dbdir = TestCreatePath("read_only_view_test");
|
||||
duckdb::unique_ptr<DuckDB> db;
|
||||
duckdb::unique_ptr<Connection> con;
|
||||
// make sure the database does not exist
|
||||
DeleteDatabase(dbdir);
|
||||
|
||||
DBConfig readonly_config;
|
||||
readonly_config.options.use_temporary_directory = false;
|
||||
readonly_config.options.access_mode = AccessMode::READ_ONLY;
|
||||
|
||||
// create db in first place
|
||||
{ auto db_rw = DuckDB(dbdir); }
|
||||
db = make_uniq<DuckDB>(dbdir, &readonly_config);
|
||||
// create the database file and initialize it with data
|
||||
con = make_uniq<Connection>(*db);
|
||||
|
||||
REQUIRE_NOTHROW(con->TableFunction("duckdb_tables")->CreateView("boo", true, true));
|
||||
con.reset();
|
||||
db.reset();
|
||||
|
||||
DeleteDatabase(dbdir);
|
||||
}
|
||||
Reference in New Issue
Block a user