1#include "catch.hpp"
2#include "test_helpers.hpp"
3
4using namespace duckdb;
5using namespace std;
6
7TEST_CASE("Insert big varchar strings", "[varchar]") {
8 unique_ptr<QueryResult> result;
9 DuckDB db(nullptr);
10 Connection con(db);
11
12 REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a VARCHAR);"));
13 // insert a big varchar
14 REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES ('aaaaaaaaaa')"));
15 // sizes: 10, 100, 1000, 10000
16 for (idx_t i = 0; i < 3; i++) {
17 REQUIRE_NO_FAIL(con.Query("INSERT INTO test SELECT a||a||a||a||a||a||a||a||a||a FROM test WHERE "
18 "LENGTH(a)=(SELECT MAX(LENGTH(a)) FROM test)"));
19 }
20
21 result = con.Query("SELECT LENGTH(a) FROM test ORDER BY 1");
22 REQUIRE(CHECK_COLUMN(result, 0, {10, 100, 1000, 10000}));
23}
24
25TEST_CASE("Test scanning many big varchar strings with limited memory", "[varchar][.]") {
26 auto temp_dir = TestCreatePath("temp_buf");
27
28 auto config = GetTestConfig();
29 config->maximum_memory = 100000000;
30 config->temporary_directory = temp_dir;
31
32 unique_ptr<QueryResult> result;
33 DuckDB db(nullptr, config.get());
34 Connection con(db);
35
36 REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a VARCHAR);"));
37 // create a big varchar (10K characters)
38 REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES ('aaaaaaaaaa')"));
39 // sizes: 10, 100, 1000, 10000
40 for (idx_t i = 0; i < 3; i++) {
41 REQUIRE_NO_FAIL(con.Query("INSERT INTO test SELECT a||a||a||a||a||a||a||a||a||a FROM test WHERE "
42 "LENGTH(a)=(SELECT MAX(LENGTH(a)) FROM test)"));
43 }
44 // now create a second table, we only insert the big varchar string in there
45 REQUIRE_NO_FAIL(con.Query("CREATE TABLE bigtable (a VARCHAR);"));
46 REQUIRE_NO_FAIL(
47 con.Query("INSERT INTO bigtable SELECT a FROM test WHERE LENGTH(a)=(SELECT MAX(LENGTH(a)) FROM test)"));
48
49 idx_t entries = 1;
50
51 // verify that the append worked
52 result = con.Query("SELECT COUNT(*), COUNT(a), MAX(LENGTH(a)), SUM(LENGTH(a)) FROM bigtable");
53 REQUIRE(CHECK_COLUMN(result, 0, {Value::BIGINT(entries)}));
54 REQUIRE(CHECK_COLUMN(result, 1, {Value::BIGINT(entries)}));
55 REQUIRE(CHECK_COLUMN(result, 2, {10000}));
56 REQUIRE(CHECK_COLUMN(result, 3, {Value::BIGINT(entries * 10000)}));
57 // we create a total of 16K entries in the big table
58 // the total size of this table is 16K*10K = 160MB
59 // we then scan the table at every step, as our buffer pool is limited to 100MB not all strings fit in memory
60 while (entries < 10000) {
61 REQUIRE_NO_FAIL(con.Query("INSERT INTO bigtable SELECT * FROM bigtable"));
62 entries *= 2;
63
64 result = con.Query("SELECT COUNT(*), COUNT(a), MAX(LENGTH(a)), SUM(LENGTH(a)) FROM bigtable");
65 REQUIRE(CHECK_COLUMN(result, 0, {Value::BIGINT(entries)}));
66 REQUIRE(CHECK_COLUMN(result, 1, {Value::BIGINT(entries)}));
67 REQUIRE(CHECK_COLUMN(result, 2, {10000}));
68 REQUIRE(CHECK_COLUMN(result, 3, {Value::BIGINT(entries * 10000)}));
69 }
70
71 TestDeleteDirectory(temp_dir);
72}
73