You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SQLite Driver Improvements — Feature Parity Audit & Plan
Executive Summary
A comprehensive audit of the SQLite driver (src-tauri/src/drivers/sqlite/) reveals
that the driver is structurally sound and correctly handles most SQLite-specific
behaviors. However, it has 2 bugs, 1 missing CRUD capability, and several polish
items that impact the user experience. Most "gaps" identified in a raw feature
matrix comparison against PostgreSQL/MySQL are actually SQLite limitations rather
than driver deficiencies.
This document separates genuine issues from inherent SQLite constraints, proposes
fixes prioritized by impact, and provides implementation guidance.
let _is_auto = pk > 0 && dtype.to_uppercase().contains("INT");TableColumn{// ...is_auto_increment:false,// Always false — _is_auto is unused// ...}
The detection logic is computed but the result is assigned to an unused variable
(prefixed with _).
Impact:
The UI never shows "Auto" placeholder for auto-increment columns
Users may be forced to manually enter values for ROWID/INTEGER PRIMARY KEY columns
The "Set Generated" quick-action button doesn't appear in the row editor
Correct Behavior:
In SQLite, any INTEGER PRIMARY KEY column is automatically an alias for ROWID
and auto-increments. The AUTOINCREMENT keyword only adds a stricter guarantee
that values are never reused. Both should report is_auto_increment: true.
Location:src-tauri/src/drivers/sqlite/mod.rs line 893
The Problem:
SQLite cannot ALTER a primary key on an existing table via ALTER TABLE. The
capability alter_primary_key is declared true, which allows the UI to present
PK modification options — but executing the generated SQL fails silently or with
a confusing error.
Impact:
Users see an enabled PK checkbox, make changes, and get unexpected errors
No path to actually modify PKs on existing SQLite tables
Solution: Table Recreation with Explicit User Consent
Keep alter_primary_key: true — the capability genuinely exists, it just requires
a multi-step approach. When the user attempts to modify a PK on a SQLite table:
Show a confirmation dialog explaining the operation
If user consents, execute the table-recreation algorithm
If user cancels, revert the UI change
Confirmation Dialog Content:
Recreate Table Required
SQLite cannot modify primary keys directly. This operation will:
Create a new table with the updated primary key
Copy all existing data to the new table
Verify the data was copied completely
Replace the original table with the new one
Rebuild all indexes, triggers, and constraints
This runs inside a single transaction — if any step fails, all changes
are rolled back and your original table remains untouched.
[Cancel][Proceed]
The Algorithm:
BEGIN IMMEDIATE;
-- Step 1: Create new table with modified schemaCREATETABLE "_tabularis_tmp_users" (
id INTEGERPRIMARY KEY AUTOINCREMENT,
name TEXTNOT NULL,
email TEXT
);
-- Step 2: Copy all data (column-mapped)INSERT INTO"_tabularis_tmp_users" (id, name, email)
SELECT id, name, email FROM"users";
-- Step 3: Verify row count-- (programmatic check: COUNT(*) of both must match)-- Step 4: Drop the originalDROPTABLE"users";
-- Step 5: Rename to original nameALTERTABLE"_tabularis_tmp_users" RENAME TO "users";
-- Step 6: Recreate dependent objectsCREATEINDEXidx_users_emailON"users" (email);
CREATETRIGGERtrg_users_audit AFTER UPDATEON"users" ...;
COMMIT;
Why This Is Safe — Zero Risk of Data Loss:
Guarantee
Mechanism
Atomicity
All steps run inside BEGIN IMMEDIATE ... COMMIT. If ANY step fails, ROLLBACK undoes everything — including the DDL. SQLite uniquely supports transactional DDL (CREATE, DROP, ALTER all roll back).
Write lock
BEGIN IMMEDIATE takes an exclusive write lock at the start. No other writer can interfere or see intermediate state.
Original untouched until step 4
The original table exists with all data intact through steps 1-3. If the INSERT or verification fails, ROLLBACK restores the database to its pre-transaction state.
Row count verification
Before dropping the original, programmatically verify COUNT(*) matches between old and new tables. Mismatch → ROLLBACK.
Crash safety
If the application crashes mid-transaction, SQLite's journal/WAL automatically rolls back the uncommitted transaction on next database open. The original table survives intact.
Temp table naming
Uses _tabularis_tmp_ prefix — won't collide with user tables.
Disk-full handling
If disk runs out during COMMIT, the transaction fails and rolls back. The only true unrecoverable case is disk-full combined with journal corruption, which is a system-level failure beyond any application's control.
Implementation Requirements:
Detect when a PK change is requested on a SQLite connection
Gather all dependent objects (indexes, triggers, views referencing the table)
Generate the full recreation script
Show the confirmation dialog with the script preview
Execute within a single transaction on an acquired connection
Verify row count before DROP
Report success/failure clearly to the user
What Gets Rebuilt:
Object Type
Detection
Rebuild Method
Indexes
PRAGMA index_list
CREATE INDEX from stored metadata
Triggers
SELECT * FROM sqlite_master WHERE type='trigger' AND tbl_name=?
Re-execute the original CREATE TRIGGER SQL
Views
SELECT * FROM sqlite_master WHERE type='view' AND sql LIKE '%tablename%'
Views reference by name — they automatically resolve after rename
Foreign keys from other tables
PRAGMA foreign_key_list on all tables
Cannot be rebuilt (SQLite limitation) — warn user if detected
Complexity: High (new Tauri command + dialog + dependent object detection + testing)
Note: This same table-recreation infrastructure can later be reused for other
SQLite operations that require table rebuilds: changing column types, reordering
columns, changing nullability, and removing columns on older SQLite versions.
Findings: Genuine Improvements
Improvement 1: JSON Object/Array Support in CRUD
Location:insert_record and update_record functions
Current Behavior:
_ => returnErr("Unsupported value type".into()),
When a user edits a cell containing a JSON object or array, the sidebar/inline
editor sends a serde_json::Value::Object or Value::Array. The SQLite driver
rejects these with a generic error.
How MySQL Handles It: Wraps with CAST(... AS JSON)
Correct SQLite Approach:
SQLite stores JSON as plain TEXT. The fix is to serialize the value to a JSON
string:
SQLite exposes zero settings. Users must know to use the startup_script field
to configure PRAGMAs.
Proposed Settings:
Setting
PRAGMA
Default
Description
journalMode
journal_mode
delete
WAL mode enables concurrent readers with one writer. Options: delete, truncate, persist, memory, wal, off
foreignKeys
foreign_keys
OFF → ON
Whether FK constraints are enforced. SQLite defaults to OFF for backwards compatibility.
synchronous
synchronous
FULL
Durability vs performance trade-off. Options: OFF, NORMAL, FULL, EXTRA
cacheSize
cache_size
-2000
Page cache size. Negative = KiB, positive = pages
busyTimeout
busy_timeout
5000
Milliseconds to wait for a locked database before returning BUSY
Implementation:
Add DriverSetting entries to the SQLite manifest
In build_sqlite_connectoptions, apply settings via .pragma() calls:
fnbuild_sqlite_connectoptions(params:&ConnectionParams) -> SqliteConnectOptions{letmut opts = SqliteConnectOptions::new().filename(params.database.to_string()).journal_mode(SqliteJournalMode::Wal)// from settings.foreign_keys(true)// from settings.busy_timeout(Duration::from_millis(5000));// from settings
opts
}
Note on foreign_keys=ON default: This is a behavior change. Existing users
may have data violating FK constraints. The setting should default to ON for new
connections but respect existing saved configurations. A migration path is needed.
Complexity: Medium (settings infrastructure + pool creation changes)
Impact: The UI type picker when creating/altering tables shows only 8 options.
Users familiar with SQL may expect to see common type names that SQLite accepts
via its type affinity system.
Important context: In SQLite, type names are advisory — the engine uses type affinity rules to determine storage
class. All of these types "work" regardless of whether the driver lists them. This
improvement is purely for UI discoverability.
Complexity: Low (add entries to the types array)
Improvement 4: Parse character_maximum_length from Type Strings
Current State: Always returns None, even for VARCHAR(255).
Why it matters: The frontend uses character_maximum_length to show a character
counter in the row editor and to validate input length.
Fix:
fnparse_max_length(data_type:&str) -> Option<u64>{// Match patterns like VARCHAR(255), CHAR(10), NVARCHAR(100)let re = regex::Regex::new(r"\((\d+)\)").ok()?;
re.captures(data_type)?
.get(1)?
.as_str().parse::<u64>().ok()}
Complexity: Low (add a helper function, call it in get_columns)
Improvement 5: Full ALTER COLUMN Support via Table Recreation
Depends on: Tier 3 (Table Recreation Engine from Bug 2)
Current State:
The SQLite driver correctly returns errors for ALTER COLUMN operations beyond
rename. The alter_column capability is declared false. However, once the
table-recreation engine is built for PK changes, the same infrastructure enables:
Operation
Current Behavior
With Recreation Engine
Change column type
Error: "not supported"
✅ Recreate table with new type
Change nullability
Error: "not supported"
✅ Recreate table with NOT NULL / NULL
Change default value
Error: "not supported"
✅ Recreate table with new DEFAULT
Reorder columns
Not possible
✅ Recreate table with new column order
Drop column (SQLite < 3.35.0)
Error on old versions
✅ Recreate table without the column
Implementation:
Once the recreation engine exists, the get_alter_column_sql method would:
Detect that the requested change requires recreation (type, nullability, or default change)
Return a special marker or invoke the recreation flow with the modified column definition
Show the same safety confirmation dialog as PK changes
Execute the recreation within a single atomic transaction
Impact: This changes alter_column capability from false to true —
enabling the full Modify Column modal for SQLite users, matching the PostgreSQL
and MySQL experience.
Complexity: Medium (reuses the Tier 3 recreation engine; primarily wiring + UI integration)
Findings: Not Applicable (SQLite Limitations)
These items appeared as "gaps" in a raw comparison but are inherent SQLite
limitations that cannot be fixed at the driver level:
Item
Why It's Not Fixable
No EXPLAIN ANALYZE
SQLite does not support runtime execution statistics. EXPLAIN QUERY PLAN is the only available introspection. The plain EXPLAIN shows internal bytecode opcodes that are meaningless to end users.
No cost/timing data in query plans
SQLite's query planner does not expose cost estimates or actual execution times. This is a fundamental architectural difference from PG/MySQL.
No schemas
SQLite is a file-based embedded database with a single namespace. ATTACH DATABASE provides a workaround but it's a different concept.
No stored procedures/routines
SQLite has no procedural language. This is by design — it's an embedded engine.
No enum types
SQLite uses CHECK constraints instead (CHECK(status IN ('active','inactive'))).
No array types
SQLite has no composite types. JSON arrays stored as TEXT are the workaround.
No geometry types
No spatial extension in vanilla SQLite (SpatiaLite exists but is a separate extension).
Synthetic FK names
PRAGMA foreign_key_list does not return constraint names — only an integer id. The driver correctly generates synthetic names fk_{id}_{ref_table}. No alternative exists.
No multi-result sets
SQLite does not support returning multiple result sets from a single execution.
This is the most significant piece of work — implementing the safe table-recreation
approach for PK alterations (and eventually other unsupported ALTER operations).
Item
Risk
New Tauri command: recreate_sqlite_table
Medium — must handle all edge cases
Dependent object detection (indexes, triggers, FK references)
Low
Confirmation dialog (frontend)
None
Row count verification step
None
Integration with existing ModifyColumnModal flow
Low
Comprehensive tests (see Testing Strategy)
None
Future reuse: Once the table-recreation engine exists, it unlocks other
operations that SQLite can't do via ALTER TABLE:
Change column types
Change column nullability
Change column defaults
Reorder columns
Remove columns (on SQLite < 3.35.0)
Testing Strategy
Unit Tests
tests/drivers/sqlite/
├── autoincrement_detection.test.rs
│ ├── INTEGER PRIMARY KEY reports is_auto_increment: true
│ ├── INTEGER PRIMARY KEY AUTOINCREMENT reports is_auto_increment: true
│ ├── TEXT PRIMARY KEY reports is_auto_increment: false
│ ├── Non-PK INTEGER column reports is_auto_increment: false
│ └── Composite PK does not report auto-increment
├── json_crud.test.rs
│ ├── Insert JSON object stores as TEXT
│ ├── Insert JSON array stores as TEXT
│ ├── Insert nested JSON preserves structure
│ ├── Update cell with JSON object succeeds
│ ├── Round-trip: insert JSON → select → compare
│ └── json_extract() works on inserted values
├── character_max_length.test.rs
│ ├── VARCHAR(255) → 255
│ ├── CHAR(10) → 10
│ ├── NVARCHAR(100) → 100
│ ├── TEXT → None
│ ├── INTEGER → None
│ └── VARCHAR (no parens) → None
├── pragma_settings.test.rs
│ ├── journal_mode=WAL applied on connect
│ ├── foreign_keys=ON applied on connect
│ ├── Settings from saved connection respected
│ └── Invalid PRAGMA value handled gracefully
└── table_recreation.test.rs
├── Basic recreation (change PK column)
│ ├── Data fully preserved after recreation
│ ├── Row count matches before and after
│ └── New PK constraint is enforced
├── Dependent object rebuild
│ ├── Indexes recreated correctly
│ ├── Triggers recreated and functional
│ └── Views still resolve after rename
├── Rollback safety
│ ├── Invalid new schema → rolls back, original intact
│ ├── Data copy failure → rolls back, original intact
│ ├── Row count mismatch → rolls back, original intact
│ └── Simulated disk error → original survives
├── Edge cases
│ ├── Table with no indexes or triggers
│ ├── Table with composite PK
│ ├── Table with self-referencing FK
│ ├── Table with columns containing special characters
│ ├── Empty table (zero rows)
│ ├── Large table (10K+ rows) — verify performance
│ └── Table with BLOB data preserved
└── Concurrent access
├── Read during recreation blocked by IMMEDIATE lock
└── Write during recreation blocked by IMMEDIATE lock
Integration Tests
Create table with INTEGER PRIMARY KEY → insert row without specifying PK → verify auto-generated
Create table with FK → insert violating row with foreign_keys=ON → verify error
Create table with FK → insert violating row with foreign_keys=OFF → verify success
foreign_keys=ON default — Should this be ON by default for all SQLite
connections, or only new ones? Existing users may have data that violates
constraints. Proposed: ON for new connections, preserve existing config for
saved connections.
WAL mode default — Should new SQLite connections default to WAL mode?
WAL provides better concurrency but creates additional files (-wal, -shm)
alongside the database. Desktop app context may favor WAL; CLI/embedded may not.
Type list scope — How exhaustive should the type picker be? SQLite accepts
literally any string as a type name. Should we list only common types, or
include obscure but valid ones?
AUTOINCREMENT vs ROWID semantics — Should the UI distinguish between INTEGER PRIMARY KEY (auto-assigns but can reuse deleted IDs) and INTEGER PRIMARY KEY AUTOINCREMENT (strictly monotonic, never reuses)?
Both are "auto increment" but with different guarantees.
Recreation engine scope — Should the table-recreation engine be
implemented as a generic utility (reusable for PK changes, column type
changes, nullability, reorder, etc.) from the start? Or build it narrowly
for PK changes first and generalize later? A generic approach is more
effort upfront but avoids rework.
Recreation for column drops — SQLite 3.35.0+ supports ALTER TABLE DROP COLUMN natively. Should the recreation engine only be used for older SQLite versions, or always (for consistency)?
Activity
aesslinger commentedon Jul 27, 2026
SQLite Driver Improvements — Feature Parity Audit & Plan
Executive Summary
A comprehensive audit of the SQLite driver (
src-tauri/src/drivers/sqlite/) revealsthat the driver is structurally sound and correctly handles most SQLite-specific
behaviors. However, it has 2 bugs, 1 missing CRUD capability, and several polish
items that impact the user experience. Most "gaps" identified in a raw feature
matrix comparison against PostgreSQL/MySQL are actually SQLite limitations rather
than driver deficiencies.
This document separates genuine issues from inherent SQLite constraints, proposes
fixes prioritized by impact, and provides implementation guidance.
Table of Contents
Audit Methodology
The audit compared three drivers across all methods of the
DatabaseDrivertrait(50+ methods):
src-tauri/src/drivers/postgres/mod.rs(2420 lines, 6 extraction submodules)src-tauri/src/drivers/mysql/mod.rs(2279 lines, 5 extraction submodules)src-tauri/src/drivers/sqlite/mod.rs(1405 lines, 2 extraction submodules)Additionally reviewed:
src-tauri/src/drivers/driver_trait.rs— trait definition andDriverCapabilitiessrc-tauri/src/pool_manager.rs— connection pool creationsrc-tauri/src/models.rs— shared data structures (TableColumn,ForeignKey,Index)Current State
What Works Correctly
The SQLite driver correctly implements:
get_tables,get_columns,get_views,get_indexes,get_foreign_keys)ALTER COLUMNcorrectly limited to rename-only (returns error for type/null changes)create_foreign_keys: falsecorrectly declared (SQLite only supports FKs at CREATE TABLE time)Declared Capabilities
Findings: Bugs
Bug 1: AUTOINCREMENT Detection Always Returns False
Location:
src-tauri/src/drivers/sqlite/mod.rslines 82-89The Problem:
The detection logic is computed but the result is assigned to an unused variable
(prefixed with
_).Impact:
Correct Behavior:
In SQLite, any
INTEGER PRIMARY KEYcolumn is automatically an alias for ROWIDand auto-increments. The
AUTOINCREMENTkeyword only adds a stricter guaranteethat values are never reused. Both should report
is_auto_increment: true.Fix:
Complexity: Trivial (one-line change)
Bug 2: Primary Key Alteration — Table Recreation with Safety Dialog
Location:
src-tauri/src/drivers/sqlite/mod.rsline 893The Problem:
SQLite cannot ALTER a primary key on an existing table via
ALTER TABLE. Thecapability
alter_primary_keyis declaredtrue, which allows the UI to presentPK modification options — but executing the generated SQL fails silently or with
a confusing error.
Impact:
Solution: Table Recreation with Explicit User Consent
Keep
alter_primary_key: true— the capability genuinely exists, it just requiresa multi-step approach. When the user attempts to modify a PK on a SQLite table:
Confirmation Dialog Content:
The Algorithm:
Why This Is Safe — Zero Risk of Data Loss:
BEGIN IMMEDIATE ... COMMIT. If ANY step fails,ROLLBACKundoes everything — including the DDL. SQLite uniquely supports transactional DDL (CREATE, DROP, ALTER all roll back).BEGIN IMMEDIATEtakes an exclusive write lock at the start. No other writer can interfere or see intermediate state.COUNT(*)matches between old and new tables. Mismatch → ROLLBACK._tabularis_tmp_prefix — won't collide with user tables.Implementation Requirements:
What Gets Rebuilt:
PRAGMA index_listCREATE INDEXfrom stored metadataSELECT * FROM sqlite_master WHERE type='trigger' AND tbl_name=?CREATE TRIGGERSQLSELECT * FROM sqlite_master WHERE type='view' AND sql LIKE '%tablename%'PRAGMA foreign_key_liston all tablesComplexity: High (new Tauri command + dialog + dependent object detection + testing)
Note: This same table-recreation infrastructure can later be reused for other
SQLite operations that require table rebuilds: changing column types, reordering
columns, changing nullability, and removing columns on older SQLite versions.
Findings: Genuine Improvements
Improvement 1: JSON Object/Array Support in CRUD
Location:
insert_recordandupdate_recordfunctionsCurrent Behavior:
When a user edits a cell containing a JSON object or array, the sidebar/inline
editor sends a
serde_json::Value::ObjectorValue::Array. The SQLite driverrejects these with a generic error.
How MySQL Handles It: Wraps with
CAST(... AS JSON)Correct SQLite Approach:
SQLite stores JSON as plain TEXT. The fix is to serialize the value to a JSON
string:
No special function or cast is needed — SQLite's JSON functions (
json(),json_extract(), etc.) operate on TEXT values containing valid JSON.Complexity: Low (add a match arm in two functions)
Improvement 2: PRAGMA Settings as Connection Configuration
Current State:
MySQL exposes 4 configurable settings via the driver manifest:
SQLite exposes zero settings. Users must know to use the
startup_scriptfieldto configure PRAGMAs.
Proposed Settings:
journalModejournal_modedeleteforeignKeysforeign_keysOFF→ONsynchronoussynchronousFULLcacheSizecache_size-2000busyTimeoutbusy_timeout5000Implementation:
DriverSettingentries to the SQLite manifestbuild_sqlite_connectoptions, apply settings via.pragma()calls:Note on
foreign_keys=ONdefault: This is a behavior change. Existing usersmay have data violating FK constraints. The setting should default to ON for new
connections but respect existing saved configurations. A migration path is needed.
Complexity: Medium (settings infrastructure + pool creation changes)
Improvement 3: Expanded Data Type List
Current State: 8 types declared (INTEGER, REAL, TEXT, BLOB, VARCHAR, BOOLEAN, DATE, DATETIME)
Impact: The UI type picker when creating/altering tables shows only 8 options.
Users familiar with SQL may expect to see common type names that SQLite accepts
via its type affinity system.
Proposed Additions:
Important context: In SQLite, type names are advisory — the engine uses
type affinity rules to determine storage
class. All of these types "work" regardless of whether the driver lists them. This
improvement is purely for UI discoverability.
Complexity: Low (add entries to the types array)
Improvement 4: Parse
character_maximum_lengthfrom Type StringsCurrent State: Always returns
None, even forVARCHAR(255).Why it matters: The frontend uses
character_maximum_lengthto show a charactercounter in the row editor and to validate input length.
Fix:
Complexity: Low (add a helper function, call it in
get_columns)Improvement 5: Full ALTER COLUMN Support via Table Recreation
Depends on: Tier 3 (Table Recreation Engine from Bug 2)
Current State:
The SQLite driver correctly returns errors for ALTER COLUMN operations beyond
rename. The
alter_columncapability is declaredfalse. However, once thetable-recreation engine is built for PK changes, the same infrastructure enables:
Implementation:
Once the recreation engine exists, the
get_alter_column_sqlmethod would:Impact: This changes
alter_columncapability fromfalsetotrue—enabling the full Modify Column modal for SQLite users, matching the PostgreSQL
and MySQL experience.
Complexity: Medium (reuses the Tier 3 recreation engine; primarily wiring + UI integration)
Findings: Not Applicable (SQLite Limitations)
These items appeared as "gaps" in a raw comparison but are inherent SQLite
limitations that cannot be fixed at the driver level:
EXPLAIN QUERY PLANis the only available introspection. The plainEXPLAINshows internal bytecode opcodes that are meaningless to end users.ATTACH DATABASEprovides a workaround but it's a different concept.CHECK(status IN ('active','inactive'))).PRAGMA foreign_key_listdoes not return constraint names — only an integerid. The driver correctly generates synthetic namesfk_{id}_{ref_table}. No alternative exists.Feature Comparison Matrix
Implementation Plan
Tier 1: Quick Fixes
character_maximum_lengthTier 2: PRAGMA Settings
foreign_keysforeign_keys=ONfor new connectionsbusy_timeout=5000Tier 3: Table Recreation Engine
This is the most significant piece of work — implementing the safe table-recreation
approach for PK alterations (and eventually other unsupported ALTER operations).
recreate_sqlite_tableFuture reuse: Once the table-recreation engine exists, it unlocks other
operations that SQLite can't do via ALTER TABLE:
Testing Strategy
Unit Tests
Integration Tests
foreign_keys=ON→ verify errorforeign_keys=OFF→ verify successOpen Questions
foreign_keys=ONdefault — Should this be ON by default for all SQLiteconnections, or only new ones? Existing users may have data that violates
constraints. Proposed: ON for new connections, preserve existing config for
saved connections.
WAL mode default — Should new SQLite connections default to WAL mode?
WAL provides better concurrency but creates additional files (
-wal,-shm)alongside the database. Desktop app context may favor WAL; CLI/embedded may not.
Type list scope — How exhaustive should the type picker be? SQLite accepts
literally any string as a type name. Should we list only common types, or
include obscure but valid ones?
AUTOINCREMENT vs ROWID semantics — Should the UI distinguish between
INTEGER PRIMARY KEY(auto-assigns but can reuse deleted IDs) andINTEGER PRIMARY KEY AUTOINCREMENT(strictly monotonic, never reuses)?Both are "auto increment" but with different guarantees.
Recreation engine scope — Should the table-recreation engine be
implemented as a generic utility (reusable for PK changes, column type
changes, nullability, reorder, etc.) from the start? Or build it narrowly
for PK changes first and generalize later? A generic approach is more
effort upfront but avoids rework.
Recreation for column drops — SQLite 3.35.0+ supports
ALTER TABLE DROP COLUMNnatively. Should the recreation engine only be used for older SQLite versions, or always (for consistency)?aesslinger commentedon Jul 27, 2026
@debba just some thoughts here that I starting thinking through