| 1 | #include "catch.hpp" | 
|---|
| 2 | #include "duckdb/common/file_system.hpp" | 
|---|
| 3 | #include "test_helpers.hpp" | 
|---|
| 4 |  | 
|---|
| 5 | using namespace std; | 
|---|
| 6 |  | 
|---|
| 7 | namespace duckdb { | 
|---|
| 8 |  | 
|---|
| 9 | class ReadOnlyFileSystem : public FileSystem { | 
|---|
| 10 | unique_ptr<FileHandle> OpenFile(const char *path, uint8_t flags, FileLockType lock_type) override { | 
|---|
| 11 | if (flags & FileFlags::WRITE) { | 
|---|
| 12 | throw Exception( "RO file system"); | 
|---|
| 13 | } | 
|---|
| 14 | return FileSystem::OpenFile(path, flags, lock_type); | 
|---|
| 15 | } | 
|---|
| 16 |  | 
|---|
| 17 | void CreateDirectory(const string &directory) override { | 
|---|
| 18 | throw Exception( "RO file system"); | 
|---|
| 19 | } | 
|---|
| 20 | void RemoveDirectory(const string &directory) override { | 
|---|
| 21 | throw Exception( "RO file system"); | 
|---|
| 22 | } | 
|---|
| 23 | void MoveFile(const string &source, const string &target) override { | 
|---|
| 24 | throw Exception( "RO file system"); | 
|---|
| 25 | } | 
|---|
| 26 | void RemoveFile(const string &filename) override { | 
|---|
| 27 | throw Exception( "RO file system"); | 
|---|
| 28 | } | 
|---|
| 29 | }; | 
|---|
| 30 |  | 
|---|
| 31 | TEST_CASE( "Test read only storage", "[storage]") { | 
|---|
| 32 | unique_ptr<QueryResult> result; | 
|---|
| 33 | auto storage_database = TestCreatePath( "storage_test"); | 
|---|
| 34 | DeleteDatabase(storage_database); | 
|---|
| 35 |  | 
|---|
| 36 | { | 
|---|
| 37 | DuckDB db(storage_database); | 
|---|
| 38 | Connection con(db); | 
|---|
| 39 | REQUIRE_NO_FAIL(con.Query( "CREATE TABLE test (a INTEGER)")); | 
|---|
| 40 | REQUIRE_NO_FAIL(con.Query( "INSERT INTO test VALUES (42)")); | 
|---|
| 41 | } | 
|---|
| 42 | { | 
|---|
| 43 | DBConfig config; | 
|---|
| 44 | config.file_system = make_unique_base<FileSystem, ReadOnlyFileSystem>(); | 
|---|
| 45 | config.access_mode = AccessMode::READ_ONLY; | 
|---|
| 46 | config.use_temporary_directory = false; | 
|---|
| 47 | DuckDB db(storage_database, &config); | 
|---|
| 48 | Connection con(db); | 
|---|
| 49 | result = con.Query( "SELECT * FROM test ORDER BY a"); | 
|---|
| 50 | REQUIRE(CHECK_COLUMN(result, 0, {42})); | 
|---|
| 51 |  | 
|---|
| 52 | REQUIRE_FAIL(con.Query( "INSERT INTO test VALUES (43)")); | 
|---|
| 53 | REQUIRE_FAIL(con.Query( "UPDATE test SET a = 43")); | 
|---|
| 54 | REQUIRE_FAIL(con.Query( "DROP TABLE test")); | 
|---|
| 55 | // temporary tables | 
|---|
| 56 | REQUIRE_NO_FAIL(con.Query( "CREATE TEMPORARY TABLE test2(i INTEGER)")); | 
|---|
| 57 | REQUIRE_NO_FAIL(con.Query( "INSERT INTO test2 VALUES (22), (23)")); | 
|---|
| 58 | REQUIRE_NO_FAIL(con.Query( "UPDATE test2 SET i=i+1")); | 
|---|
| 59 | REQUIRE_NO_FAIL(con.Query( "DELETE FROM test2 WHERE i=23")); | 
|---|
| 60 |  | 
|---|
| 61 | result = con.Query( "SELECT * FROM test2"); | 
|---|
| 62 | REQUIRE(CHECK_COLUMN(result, 0, {24})); | 
|---|
| 63 | } | 
|---|
| 64 | DeleteDatabase(storage_database); | 
|---|
| 65 | } | 
|---|
| 66 |  | 
|---|
| 67 | } // namespace duckdb | 
|---|
| 68 |  | 
|---|