Repository: duckdb/duckdb
File: test/appender/test_appender.cpp (C++)

Code before:
	appender.Append(42);
	appender.Append(43);
	appender.EndRow();

	appender.Append(Value());
	appender.Append(44);
	appender.EndRow();
	appender.Close();

	result = con.Query("SELECT i, j, k, l, m FROM tbl");
	REQUIRE(CHECK_COLUMN(result, 0, {4, 4}));
	REQUIRE(CHECK_COLUMN(result, 1, {42, Value()}));
	REQUIRE(CHECK_COLUMN(result, 2, {30, 30}));
	REQUIRE(CHECK_COLUMN(result, 3, {84, Value()}));
	REQUIRE(CHECK_COLUMN(result, 4, {43, 44}));
}

TEST_CASE("Appender::Clear() clears the data", "[appender]") {
	DuckDB db(nullptr);
	Connection con(db);

	REQUIRE_NO_FAIL(con.Query("CREATE TABLE ints(i INTEGER)"));
	Appender appender(con, "main", "ints");

	// Those should be flushed due to the max chunk size trigger
	for (idx_t i = 0; i < BaseAppender::DEFAULT_FLUSH_COUNT; i++) {
		appender.AppendRow(i);
	}

	// This one should be cleared, and not flushed
	appender.AppendRow(BaseAppender::DEFAULT_FLUSH_COUNT + 1);
	appender.Clear();

	// This one should be also flushed as it's right after the Clear
	appender.AppendRow(BaseAppender::DEFAULT_FLUSH_COUNT + 2);
	appender.Close();

	// the expected results are {0...2047, 2049}
	duckdb::vector<duckdb::Value> expected;
	for (idx_t i = 0; i < BaseAppender::DEFAULT_FLUSH_COUNT; i++) {
		expected.push_back(duckdb::Value::INTEGER((int32_t)i));
	}
	expected.push_back(duckdb::Value::INTEGER((int32_t)(BaseAppender::DEFAULT_FLUSH_COUNT + 2)));

	// We expect the result to be just the second row, after we cleared the appender
	duckdb::unique_ptr<QueryResult> result = con.Query("SELECT * FROM ints");
	REQUIRE(CHECK_COLUMN(result, 0, expected));
}

TEST_CASE("Interrupted QueryAppender flow: interrupt -> clear -> close finishes", "[appender]") {
	DuckDB db(nullptr);

Review comment (suggestion):
We can use `DEFAULT_FLUSH_COUNT` here, but it might be a bit misleading. `DEFAULT_FLUSH_COUNT` is the number of rows that have to be **inside** the column data collection for the data to be auto-flushed **to the table**. I.e., this will trigger a flush to the storage.

What I meant with my previous comment is that the appender always has one active chunk that it is currently filling (the `chunk` field). Once that is full, the next `AppendRow` will append/add that chunk to the column data collection and then reset `chunk`. So any value over `2048` should achieve that.

Code after:
	appender.Append(42);
	appender.Append(43);
	appender.EndRow();

	appender.Append(Value());
	appender.Append(44);
	appender.EndRow();
	appender.Close();

	result = con.Query("SELECT i, j, k, l, m FROM tbl");
	REQUIRE(CHECK_COLUMN(result, 0, {4, 4}));
	REQUIRE(CHECK_COLUMN(result, 1, {42, Value()}));
	REQUIRE(CHECK_COLUMN(result, 2, {30, 30}));
	REQUIRE(CHECK_COLUMN(result, 3, {84, Value()}));
	REQUIRE(CHECK_COLUMN(result, 4, {43, 44}));
}

TEST_CASE("Appender::Clear() clears the data", "[appender]") {
	DuckDB db(nullptr);
	Connection con(db);

	REQUIRE_NO_FAIL(con.Query("CREATE TABLE ints(i INTEGER)"));
	Appender appender(con, "main", "ints");

	// We will append rows to reach more than the maximum chunk size
	// (DEFAULT_FLUSH_COUNT will always be more than a chunk size),
	// so we will make sure that also the collection is being cleared.
	// We use the DEFAULT_FLUSH_COUNT so we won't flush before calling the `Clear`
	constexpr auto rows_to_append = BaseAppender::DEFAULT_FLUSH_COUNT - 10;

	for (idx_t i = 0; i < rows_to_append; i++) {
		appender.AppendRow(i);
	}

	// We're clearing, which means we're expecting to have only the `1` appended after the clear.
	appender.Clear();
	appender.AppendRow(1);
	appender.Close();

	duckdb::unique_ptr<QueryResult> result = con.Query("SELECT * FROM ints");
	REQUIRE(CHECK_COLUMN(result, 0, {1}));
}

TEST_CASE("Interrupted QueryAppender flow: interrupt -> clear -> close finishes", "[appender]") {
	DuckDB db(nullptr);
	Connection con(db);

	REQUIRE_NO_FAIL(con.Query("CREATE TABLE ints(i INTEGER)"));

	// Prepare a long time running QueryAppender
	duckdb::vector<LogicalType> types = {LogicalType::INTEGER};