Repository navigation
6.0.0 release prep - #31
Merged
Merged
Conversation
Replaces the branch: "main" pin with the released version, so a version-pinned consumer can resolve this package. Package.resolved is gitignored; swift package resolve picks Perfect-CRUD 3.0.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pins the install and Perfect-CRUD snippets to from: "6.0.0" / "3.0.0", notes the SQLite 3.29 floor, and lists the changes since 5.0.0: toolchain and platforms, Linux on the system libsqlite3, double-quoted strings off, reconcile reaching sub-tables (non-atomic, .shallow opt-out), reconcile keeping FOREIGN KEYs, quoted identifiers, and the Dynamic API's affectedRows (0) and insertedID (nil). Dynamic select works on this connector (nextDynamicRow is implemented); checked from a scratch consumer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sqlite3_prepare_v2 stops after the first statement, so execute(DynamicSQL(..., allowsMultipleStatements: true)) and Database.sql ran the first statement and silently ignored the others. An SQLExeDelegate runs exactly one statement with one set of bindings and one row cursor, and CRUD documents DynamicSQL as a single statement whose multi-statement guard is best-effort, so the connector now throws an SQLiteCRUDError when another statement follows (even one that can't be prepared yet) rather than running them in turn. Trailing whitespace, ';' and comments are still accepted. The raw SQLite.prepare/execute API is unchanged. Adds DynamicAPITests: Dynamic select and execute return rows, and two INSERTs in one execute throw with neither run. The refusal test fails with 5 issues without the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Binding .uinteger or .uinteger64 (Dynamic .uint, or a typed comparison with a UInt) did Int(i), which traps above Int64.max. They now go through Int64(exactly:) and throw an SQLiteCRUDError when the value doesn't fit SQLite's signed 64-bit INTEGER. Typed UInt/UInt64 properties on insert/update never reach this path: CRUD 3.0.0's encoder converts them with Int(value) itself and still traps there above Int.max. That needs a Perfect-CRUD fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With two result columns of the same name (SELECT a.id, b.id, or 1 AS x, 2 AS x) the column map kept the last one, so Dynamic rows and the typed reader returned the second column's value. The first now wins, as in SQLite's own name lookup. Dynamic rows also fold names case-insensitively (first wins), matching DynamicRow's lowercased keys: SELECT 1 AS a, 2 AS A used to crash in CRUD 3.0.0's DynamicRow.init with duplicate keys. Tests cover execute with a join, exact and case-only duplicates, a Dynamic select with duplicate fields, and the typed reader. Without the fix they record 2 issues and then trap on the case-only duplicate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…docs/ - DQS: a "..." string in a CHECK clause or partial-index WHERE makes every reconcile that removes columns fail (ALTER TABLE ... RENAME re-parses the schema); reconcile such databases with doubleQuotedStrings: true. Reproduced for both on macOS; DEFAULT values were unaffected. - Reconcile: the FK check also counts violations that already existed; the in-transaction refusal applies with foreign_keys on and includes self-referencing tables; a rebuild drops triggers as well as indexes. - Dynamic API: new through Perfect-CRUD 3 (5.0.0 had none), so drop the before/after comparison. lastInsertRowID()/Insert.lastInsertId() return the rowid, which isn't the key on CRUD's INT PRIMARY KEY tables. - Migrating: one statement per call, unsigned overflow throws, first duplicate column wins, columnText repairs invalid UTF-8 (5.0.0 gave ""). - Linux: libsqlite3-dev and pkg-config, as CI installs. - Delete docs/ (pre-5.0.0 jazzy output for the Swift 3 API, not served by GitHub Pages) and its .jazzy.yaml (Swift 3 toolchain); nothing else referenced them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Perfect-CRUD 3.0.0 requires C: Sendable for DatabaseConnectionPool, transactionAsync, sqlAsync, insertAsync, firstAsync and fetchAll(), so none of them compiled with SQLite. The configuration stores a String and the SQLite connection, a class around a raw sqlite3* with no locking (already @unchecked Sendable), so the conformance is @unchecked, with a comment on when it's safe: one task at a time per connection. The async methods and the pool move a connection between threads without sharing it, which SQLite allows in multi-thread mode (the Apple SDKs: sqlite3_threadsafe() == 2, checked on macOS 27 with SQLite 3.54) and serialized mode (Ubuntu noble's 3.45.1: 1). Connections aren't opened with SQLITE_OPEN_FULLMUTEX, so concurrent use of one connection is a data race on Apple platforms; the README says to give each task its own connection. AsyncPoolTests: an insertAsync / transactionAsync (commit and rollback) / fetchAll / firstAsync / sqlAsync round trip, and a 3-connection pool serving 12 concurrent inserts plus manual acquire/release. Without the conformance the test target fails to compile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Empty, whitespace-only, ";"-only and comment-only SQL prepares without
error but gives no statement, and SQLiteExeDelegate then crashed on the
nil statement ("Unexpectedly found nil") through db.sql(_:) and
Dynamic execute. This is pre-existing (5.0.0 behaves the same), found by
the final verification. prepareSingle now throws SQLiteCRUDError for
it. Its old "Empty SQL statement" guard could never fire, because
utf8CString always has a NUL.
SQL with an embedded NUL ran up to the NUL and silently ignored the
rest; it now throws.
The empty-SQL test crashes without the fix, and the NUL test records an
issue. 58/58 on Xcode 27 (debug and release), Xcode 26.3 (release) and
Linux 6.2 and 6.4 (release), all with -warnings-as-errors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.0.1 fixes four crashes in 3.0.0 reachable from public API, including a Codable UInt/UInt64 above Int.max trapping in CRUD's encoder (now bound as unsigned). Tests pass against 3.0.1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Release prep for Perfect-SQLite 6.0.0, the first release since 5.0.0 (2020). It requires Perfect-CRUD
from: "3.0.1". CI was already onmain.SQLiteCRUDError. Before, everything after the first statement was silently dropped (Database.sqland Dynamicexecute).;, a comment) or with an embedded NUL now throws. It used to crash or silently truncate.Int64.maxthrow instead of trapping.SQLiteDatabaseConfigurationisSendable, so CRUD's connection pool and async methods work with it. Tests cover the pool and async round trips.legacypointer, and "Migrating from 5.x", which covers DQS off, reconcile reaching sub-tables, Linux using the systemlibsqlite3-dev, and the Dynamic API.lastInsertIdadvice (rowid), and the threading modes.docs/.Testing
58/58 with warnings as errors:
Three adversarial reviews. The final one checked that every SQL string CRUD generates is a single statement (create, reconcile rebuilds, indexes, FKs), and the pool test's determinism (40/40).
🤖 Generated with Claude Code