feat(ios): DuckDB support for files and in-memory databases#1537
Conversation
Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a91679c3e3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 83e0520102
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4ad21b2102
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
TablePro/TableProMobile/TableProMobile.xcodeproj/project.pbxproj
Lines 2093 to 2096 in 2429a26
For iphoneos builds this conditional OTHER_LDFLAGS value overrides the unqualified OTHER_LDFLAGS above, so the actual device link only gets $(inherited) -force_load libduckdb-device.a and drops the newly required -lc++ plus the existing -lz/-liconv flags. Because the force-loaded DuckDB archive contains C++ and compression/iconv references, device builds fail at link time; include the base libraries in each SDK-specific value (the simulator override needs the same treatment).
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c6db8341a1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| func connect() async throws { | ||
| let resolvedPath = try resolvePath() | ||
| try await actor.open(path: resolvedPath) |
There was a problem hiding this comment.
Release security scope when opening fails
When this is opening a bookmarked external DuckDB file and duckdb_open_ext fails (for example, the file is corrupt or locked), resolvePath() has already called startAccessingSecurityScopedResource() and stored the URL, but the thrown error exits connect() before any caller has a connected session to later call disconnect(). Repeated failed tests/opens can leak security-scoped file handles until iOS denies access to more picked files; stop the secured URL in the actor.open failure path.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1b6099b1a9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| continuation.onTermination = { reason in | ||
| task.cancel() | ||
| if case .cancelled = reason { | ||
| Task { await actor.interrupt() } |
There was a problem hiding this comment.
Wire cancellation to an existing actor API
In the stream termination path this calls actor.interrupt(), but DuckDBActor in this commit does not define an interrupt method (the only DuckDB cancellation entry point added here is DuckDBDriver.cancelCurrentQuery()). As soon as this file is type-checked, the TableProMobile target fails to build, so DuckDB support cannot compile until this cancellation path is connected to a real API.
Useful? React with 👍 / 👎.
| case DUCKDB_TYPE_BLOB: | ||
| return decodeBlob(data, row: row) |
There was a problem hiding this comment.
Preserve BLOB cells as binary while streaming
For streamed DuckDB queries that return BLOB columns, this path always base64-encodes the entire value into a .text cell, unlike the existing SQLite streaming path which emits .binary(byteCount:ref:). Large DuckDB blobs are therefore fully materialized and rendered as text even when StreamOptions.inlineBinary is false, defeating the streaming memory protections and binary-cell UI for queries such as SELECT blob_col FROM files.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c6799fde89
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| case DUCKDB_TYPE_TIMESTAMP, DUCKDB_TYPE_TIMESTAMP_S, DUCKDB_TYPE_TIMESTAMP_MS, DUCKDB_TYPE_TIMESTAMP_NS: | ||
| return .text(formatTimestamp(normalizedTimestamp(data, row: row, type: column.type))) | ||
| default: | ||
| return decodeVarchar(data, row: row, options: options) |
There was a problem hiding this comment.
Decode TIME_NS without treating it as text
When a DuckDB query returns a TIME_NS column, requiresTextCast leaves castToText false and this switch has no DUCKDB_TYPE_TIME_NS case, so it falls through to decodeVarchar. DuckDB stores TIME_NS vectors as an Int64 nanosecond count, not a duckdb_string_t, so streaming a result like a nanosecond-precision time can interpret arbitrary integer bytes as a string length/pointer and produce corrupt output or crash; add a TIME_NS decoder or force this type through the text-cast path.
Useful? React with 👍 / 👎.
…ecated value-API crash (#1526)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 84b56216b2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| default: | ||
| return decodeVarchar(data, row: row, options: options) |
There was a problem hiding this comment.
Cast BIGNUM before decoding as varchar
When a DuckDB query returns a BIGNUM column, neither the materialized nor streaming planners mark it for text casting, and this fallback treats the vector as duckdb_string_t. DuckDB exposes DUCKDB_TYPE_BIGNUM as duckdb_bignum (data pointer, size, sign), so queries such as SELECT 10::BIGNUM ^ 1000 can read the wrong layout and produce corrupt output or crash; add a BIGNUM case or force it through the VARCHAR cast path.
Useful? React with 👍 / 👎.
…ly-decoded type (#1526)
Closes #1526.
Adds DuckDB to the iOS app: open
.duckdb/.ddbfiles or run an in-memory database, matching the Mac app.Why this is structured differently from macOS
iOS can't load the macOS
.tablepluginbundle at runtime (App Store Guideline 2.5.2 + the sandbox), so iOS compiles each driver into the app and links a staticxcframework. This follows the exact patternSQLiteDriverestablished. DuckDB was missing two things: an iOS DuckDB binary and an iOS driver. Both are added here.What's in the PR
DuckDBDriver(+DuckDBDriver+Schema): aDatabaseDriverimplementation over the DuckDB C API, ported from the macOS plugin. Handles:memory:, security-scoped file access, schema/table/column/index/FK introspection, transactions, and TZ/GEOMETRY rendering.CBridges/CDuckDB: the C module map forduckdb.h.FileBookmarkStore: device-local (UserDefaults) security-scoped bookmarks, keyed by connection id. Kept out of the synced model and iCloud keychain, since a bookmark is meaningless on another device..duckdb/.ddb. Opened files keep working across launches; edits write back to the original file.scripts/build-duckdb-ios.sh: builds the iOS xcframework from DuckDB v1.5.2 (matches the bundled macOS lib) for device + simulator, linkingjson,parquet, andicu. Remote extension autoloading is off (httpfsand friends are not available on iOS).IOSDriverFactory,DatabaseType+Mobile,ConnectionCoordinatorschema support, bookmark cleanup on delete,project.pbxproj(xcframework link,CDuckDBinclude path,-lc++).Native library
DuckDB.xcframeworkis not in git (same as the other iOS xcframeworks); it lives in thelibs-v1release. I rebuilttablepro-libs-ios-v1.tar.gzwith the new framework and uploaded it, and bumped theios-tests.ymlcache key so CI fetches the refreshed set. To rebuild locally:scripts/build-duckdb-ios.sh.Tests
DuckDBDriverTests: in-memory integration (create/insert/select, null, blob base64, tables/columns/PK, views, schemas). No server or file needed, so it runs in CI.FileBookmarkStoreTests: save/resolve/delete round-trip.ConnectionFormViewModelDuckDBTests: in-memory toggle, file-based save, type reset.Notes