fix(android): match iOS SQLITE_THREADSAFE=2 and SQLITE_STRICT_SUBTYPE=1#403
Conversation
|
you have some conflicts, please fix them and I will merge this PR |
1ed26aa to
a33e615
Compare
What this PR changesOne line, in - "-DSQLITE_USE_ALLOCA=1", "-DSQLITE_THREADSAFE=1"
+ "-DSQLITE_USE_ALLOCA=1", "-DSQLITE_STRICT_SUBTYPE=1", "-DSQLITE_THREADSAFE=2"Two effects: adds Where iOS already has theseoptimizedCflags = ' -DSQLITE_DQS=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_DEPRECATED=1 \
-DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_OMIT_SHARED_CACHE=1 -DSQLITE_USE_ALLOCA=1 \
-DSQLITE_STRICT_SUBTYPE=1 -DSQLITE_THREADSAFE=2'That string is appended to What the flags mean
|
| Value | Mode | Internal locking | Caller responsibility |
|---|---|---|---|
0 |
Single-thread | None | Only one thread may touch the whole library |
1 |
Serialized | Full mutex on every API call | SQLite handles it; multiple threads may share a connection |
2 |
Multi-thread | Mutex only on shared globals | Each connection used by one thread at a time |
The compile-time setting only chooses the default — a connection's actual mode can be overridden when it is opened by passing SQLITE_OPEN_NOMUTEX (multi-thread) or SQLITE_OPEN_FULLMUTEX (serialized) to sqlite3_open_v2().
op-sqlite always opens connections with SQLITE_OPEN_FULLMUTEX (cpp/bridge.cpp#L95-L96):
int flags =
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;So at runtime every connection is serialized regardless of whether the compile-time default is =1 or =2. This PR brings Android's compile-time flags into parity with iOS — it does not materially change SQLite's per-connection mutex behaviour unless SQLITE_OPEN_FULLMUTEX is removed in a separate change. Any real perf win from =2 only lands after that follow-up (which would also need to be reconciled with the executeSync vs async execute paths on the same DB, since SQLite would no longer serialize them for us).
SQLITE_STRICT_SUBTYPE=1 — catch incorrectly registered SQL functions
SQLite values carry an optional "subtype", a small integer tag that SQL functions can attach to their results via sqlite3_result_subtype(). JSON1 / jsonb use this so functions like json() tag their output as already-parsed JSON, letting downstream JSON functions skip re-parsing.
With SQLITE_STRICT_SUBTYPE=1 (sqlite.org/compile.html#strict_subtype), SQLite raises an error if an application-defined SQL function calls sqlite3_result_subtype() without having been registered with the SQLITE_RESULT_SUBTYPE function flag. It catches extension authors who forgot the registration flag — what would otherwise be silent miscommunication between functions becomes a hard error at the boundary.
This is a correctness / debuggability flag. No perf impact, no behaviour change for code that registers its functions correctly. iOS already enables it under performanceMode; this brings Android in line.
Why both flags belong inside performanceMode
performanceMode is the consumer's signal that they accept the perf-leaning trade-offs (deprecated APIs removed, shared cache off, DQS=0, etc.). THREADSAFE=2 slots into that bucket as the compile-time default Android would use if a future change relaxed SQLITE_OPEN_FULLMUTEX. STRICT_SUBTYPE=1 is technically orthogonal (correctness, not perf) but iOS already includes it in optimizedCflags, so keeping the two platforms aligned is the simpler story.
If a consumer wants to opt out, the sqliteFlags override from #402 lets them — e.g. "sqliteFlags": "-DSQLITE_THREADSAFE=1" restores =1 as the compile-time default on Android.
Summary
Aligns Android's
performanceModecompile flags with iOS so the two platforms produce SQLite builds with the same threading and subtype-strictness profile.iOS (op-sqlite.podspec line 174) sets:
Android (this PR) now sets the same. Previously Android set
-DSQLITE_THREADSAFE=1(serialized) and didn't set-DSQLITE_STRICT_SUBTYPEat all.Why each flag
SQLITE_THREADSAFE=2(multithread): eachDBHostObjectowns a single-worker thread pool, so a given connection is only ever touched by one thread at a time — serialized mode's internal mutex is wasted overhead. iOS has shipped at=2for a while; aligning Android picks up the same small perf win and removes a platform discrepancy. Note: this inherits iOS's existing assumption that consumers do not callexecuteSync()from the JS thread while an asyncexecute()is in flight on the same DB. The library doesn't lock around that today on either platform.SQLITE_STRICT_SUBTYPE=1: enforces subtype safety for SQL function return values. Pure correctness flag with no perf cost. Matches iOS.Verification
Built the example app on
arm64-v8aand grepped the generatedcompile_commands.jsonfor thesqlite3.ccompile line — both flags now present:Then ran
./scripts/test-android.shagainst a local Pixel 7 Pro emulator (API 34). Full release APK build, install, in-app@op-engineering/op-testsuite run —OPSQLITE_TEST_RESULT:PASS.Notes
performanceModeflag list inandroid/build.gradle.sqliteFlagsoverride fix). If both merge, this PR's flags become defaults that users can still override.