1#include "catch.hpp"
2#include "duckdb/common/file_system.hpp"
3#include "test_helpers.hpp"
4
5using namespace std;
6
7namespace duckdb {
8
9class 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
31TEST_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