From b0f0af7caa969eae3263ade14ea299d00ab69195 Mon Sep 17 00:00:00 2001 From: Alex Kasko Date: Mon, 16 Mar 2026 20:11:16 +0000 Subject: [PATCH] Add an option to force single-threaded scans This PR is a follow-up to the #179 PR. It adds an option: ```sql SET sqlite_disable_multithreaded_scans = FALSE; ``` When enabled, it has the same effect on SQLite scans as the setting `threads = 1`; Testing: basic check added that the option can be set. --- src/sqlite_extension.cpp | 3 +++ src/storage/sqlite_table_entry.cpp | 20 ++++++++++++-------- test/sql/storage/attach_simple.test | 13 +++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/sqlite_extension.cpp b/src/sqlite_extension.cpp index 0fac9c1..a534259 100644 --- a/src/sqlite_extension.cpp +++ b/src/sqlite_extension.cpp @@ -37,6 +37,9 @@ static void LoadInternal(ExtensionLoader &loader) { config.AddExtensionOption("sqlite_debug_show_queries", "DEBUG SETTING: print all queries sent to SQLite to stdout", LogicalType::BOOLEAN, Value::BOOLEAN(false), SetSqliteDebugQueryPrint); + config.AddExtensionOption("sqlite_disable_multithreaded_scans", "Make all scans over the SQLite DB to be performed using a single worker thread", + LogicalType::BOOLEAN, Value::BOOLEAN(false)); + StorageExtension::Register(config, "sqlite_scanner", make_shared_ptr()); } diff --git a/src/storage/sqlite_table_entry.cpp b/src/storage/sqlite_table_entry.cpp index 512f78f..f7c0316 100644 --- a/src/storage/sqlite_table_entry.cpp +++ b/src/storage/sqlite_table_entry.cpp @@ -38,16 +38,20 @@ TableFunction SQLiteTableEntry::GetScanFunction(ClientContext &context, unique_p result->rows_per_group = optional_idx(); } - bool use_global_db = !transaction.IsReadOnly() || sqlite_catalog.InMemory(); - - Value threads_setting; - if (!use_global_db && context.TryGetCurrentSetting("threads", threads_setting) && !threads_setting.IsNull()) { - auto current_threads = NumericCast(BigIntValue::Get(threads_setting.DefaultCastAs(LogicalType::BIGINT))); - if (current_threads <= 1) { - use_global_db = true; - } + int64_t threads = 1; + Value threads_val; + if (context.TryGetCurrentSetting("threads", threads_val)) { + threads = BigIntValue::Get(threads_val); } + bool disable_multithreaded_scans = false; + Value disable_multithreaded_scans_val; + if (context.TryGetCurrentSetting("sqlite_disable_multithreaded_scans", disable_multithreaded_scans_val)) { + disable_multithreaded_scans = BooleanValue::Get(disable_multithreaded_scans_val); + } + + bool use_global_db = !transaction.IsReadOnly() || sqlite_catalog.InMemory() || threads <= 1 || disable_multithreaded_scans; + if (use_global_db) { // for in-memory databases or if we have transaction-local changes we can // only do a single-threaded scan set up the transaction's connection object diff --git a/test/sql/storage/attach_simple.test b/test/sql/storage/attach_simple.test index fa99693..d3afff6 100644 --- a/test/sql/storage/attach_simple.test +++ b/test/sql/storage/attach_simple.test @@ -39,3 +39,16 @@ query I SELECT * FROM simple.test2 ---- 84 + +# check option is supported + +statement ok +SET sqlite_disable_multithreaded_scans = TRUE; + +query I +SELECT * FROM simple.test2 +---- +84 + +statement ok +SET sqlite_disable_multithreaded_scans = FALSE;