Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Windows Authentication (Kerberos) to SQL Server now works on macOS. The bundled SQL Server driver was built without Kerberos support, so every Windows-auth connect failed as if the credentials were wrong. (#1918)
- The MongoDB, Oracle, Cassandra, and Elasticsearch plugins failed to install on 0.58 with "Bundle failed to load executable". (#1917)

## [0.58.0] - 2026-07-18

Expand Down
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ When adding a new method to the driver protocol: add to `PluginDatabaseDriver` (

**PluginKit ABI (resilient)**: TableProPluginKit is built with `BUILD_LIBRARY_FOR_DISTRIBUTION = YES` (Swift Library Evolution), so its public ABI is resilient. The Swift runtime instantiates witness tables for already-built plugins and fills any requirement the plugin did not implement from the protocol's default, so a plugin built against an older PluginKit keeps loading under a newer app.

**Additive changes are binary-compatible and need NO version bump**: adding a requirement to `DriverPlugin` / `PluginDatabaseDriver` that has a default implementation, reordering requirements, adding a field to a non-`@frozen` transfer struct, or removing a requirement that defaulted to `nil`.
**Additive changes are binary-compatible and need NO version bump**: adding a requirement to `DriverPlugin` / `PluginDatabaseDriver` that has a default implementation, reordering requirements, or adding a field to a non-`@frozen` transfer struct.

**Never remove a published protocol requirement, even one that defaulted to `nil`.** Library Evolution fills in requirements *added* after a plugin was built, but it cannot rescue a requirement *removed* out from under an already-built plugin. Removing one deletes both its method descriptor and its default-implementation symbol, and every shipped plugin that relied on the default hard-references both in its witness table, so it fails to load with "Bundle failed to load executable". If the app stops using a requirement, leave it in place with its default (it costs nothing). Removing it is a breaking change: bump `currentPluginKitVersion` and re-release every plugin. (#1917, and it broke MongoDB, Oracle, Cassandra, and Elasticsearch on 0.58.)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the published ABI guidance consistent

Update docs/development/plugin-development.mdx:81-82 as part of this correction. It still tells plugin authors that removing a defaulted requirement is additive and needs no version bump, which is the exact rule this change identifies as causing registry plugins to fail to load; following that documentation can recreate this production regression.

Useful? React with 👍 / 👎.


**Adding a field to a transfer struct is additive ONLY if every existing public initializer keeps its exact signature.** Adding a parameter to an existing public init or function, even with a default value, replaces its mangled symbol and breaks every already-built plugin (this shipped in 0.49.0: `PluginQueryResult` gained `columnMeta:` on its init and every registry plugin failed to load with "Bundle failed to load executable"). Add a NEW overload for the new field and keep the old signature; mark the old overload `@_disfavoredOverload` so new code resolves to the full init while old binaries keep their symbol. Before any PluginKit change run `scripts/check-pluginkit-abi.sh` (see below) and act on the result: either the diff is additive (verify no symbol disappeared) or it is breaking (bump and re-release).

Expand Down
4 changes: 4 additions & 0 deletions Plugins/TableProPluginKit/PluginDatabaseDriver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ public protocol PluginDatabaseDriver: AnyObject, Sendable {
// EXPLAIN query building (optional)
func buildExplainQuery(_ sql: String) -> String?

func injectRowLimit(_ sql: String, limit: Int) -> String?

func quoteIdentifier(_ name: String) -> String

func escapeStringLiteral(_ value: String) -> String
Expand Down Expand Up @@ -347,6 +349,8 @@ public extension PluginDatabaseDriver {

func buildExplainQuery(_ sql: String) -> String? { nil }

func injectRowLimit(_ sql: String, limit: Int) -> String? { nil }

func createViewTemplate() -> String? { nil }
func editViewFallbackTemplate(viewName: String) -> String? { nil }
func castColumnToText(_ column: String) -> String { column }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct PluginKitABIResilienceTests {
#expect(driver.foreignKeyEnableStatements() == nil)
#expect(driver.supportedMaintenanceOperations() == nil)
#expect(driver.buildExplainQuery("SELECT 1") == nil)
#expect(driver.injectRowLimit("SELECT 1", limit: 100) == nil)
#expect(driver.defaultExportQuery(table: "users") == nil)
#expect(driver.createViewTemplate() == nil)
#expect(driver.generateCreateTableSQL(definition: .init(tableName: "users", columns: [], primaryKeyColumns: [])) == nil)
Expand Down
Loading