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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Redis: "Required (skip verify)" SSL mode now actually skips certificate verification, matching `redis-cli --tls --insecure`. Previously every mode performed verification because of a phantom dictionary key the app never wrote. Connections to Upstash Redis and similar endpoints with untrusted CAs work (#1247).
- MSSQL: SSL mode finally affects the connection. `Disabled` / `Preferred` / `Required` / `Verify CA` / `Verify Identity` map to FreeTDS `off` / `request` / `require` / `require` / `require` via `DBSETENCRYPT`. Previously the setting was read and silently ignored.
- MongoDB: "Required" and "Verify CA" pass the right libmongoc flags (`tlsAllowInvalidCertificates`, `tlsAllowInvalidHostnames`) so connections to self-signed or untrusted-CA servers stop failing on those paths.
- MongoDB: connecting no longer crashes with `dispatch_sync called on queue already owned by current thread` when the server version cache is cold (#1249).
- MongoDB: TLS handshake to Atlas no longer fails with `internal error (-9838)` on macOS 26. libmongoc is rebuilt with OpenSSL 3.4.3 instead of Apple Secure Transport; the previous backend hit a peer-side `internal_error` alert during TLS 1.3 negotiation with Atlas clusters.
- MongoDB: importing a connection URL without a database path no longer fails with Unauthorized when the user lacks `listDatabases` privilege on `admin`. `listDatabases` now passes `authorizedDatabases: true` so Atlas users restricted to one database see that database; if the call still fails, the connection stays open with no default database selected.
- MySQL: CA certificate is no longer loaded when the user picked a mode that skips verification, matching PostgreSQL.

## [0.40.3] - 2026-05-13
Expand Down
16 changes: 8 additions & 8 deletions Libs/checksums.sha256
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
36e3a521b8da03bafd0f943c4f3b21c8c573bf9d640c6c9e764c0c3632672849 Libs/libbson_arm64.a
b7716e3f295a54feee85c8771332505be2f9a4a430a088d476d60e358d737c9e Libs/libbson_universal.a
1e502e7fb4edc79639140e18d433a1ed1be2931162daecee71a74d09e9f4c550 Libs/libbson_x86_64.a
b7716e3f295a54feee85c8771332505be2f9a4a430a088d476d60e358d737c9e Libs/libbson.a
6c16abade13041111a9551245043b195aa27ce79ce0ab32113962e762f63485f Libs/libbson_arm64.a
9b7d7abb13b36a4856fd8b4a6cc2a2b312c1bb1815ae9891cc30fe605badeb3c Libs/libbson_universal.a
adb2ade8531660c846df3dab6cafc0a6ba15bf4a9d0ae0a1bc8edaca98bf1ffa Libs/libbson_x86_64.a
9b7d7abb13b36a4856fd8b4a6cc2a2b312c1bb1815ae9891cc30fe605badeb3c Libs/libbson.a
8d7e31145470a339f4f57930831936db30412393a339598deece6f650214865a Libs/libcassandra_arm64.a
9bfd7d7cb4a7ee9823b4c5141e942a8534de63395983388722dc7c98e5d7731e Libs/libcassandra_universal.a
7f1d058c77b66273db2b3867103c19f62ed0518fb38611b178ce04029213d5d8 Libs/libcassandra_x86_64.a
Expand All @@ -26,10 +26,10 @@ b777f7a42766fb08c8e67b2310c67d2d463d77d3554c6092221c3352778622b2 Libs/libmariad
5326ed729b287ae5dbbcf073aaa70dce29a73c7431e446d5958271af19dac8d8 Libs/libmariadb_universal.a
4f7bbb3d73be178d4211c3bd5b2726b4a12db8b808eaa5212bf8e9eb3c570814 Libs/libmariadb_x86_64.a
5326ed729b287ae5dbbcf073aaa70dce29a73c7431e446d5958271af19dac8d8 Libs/libmariadb.a
9f4c87916ef65eae43b19d7568dc4fd4dffd884dc0cae15913b90965293339a7 Libs/libmongoc_arm64.a
0d7ddc82dc7327a4b5187ffbc68a1419b5e5ff7b2be7b927e16793eef4d34303 Libs/libmongoc_universal.a
635705c7dc8d689efdee5ec1bd8a8cbd0d09ae20db0869480271a293d492de50 Libs/libmongoc_x86_64.a
0d7ddc82dc7327a4b5187ffbc68a1419b5e5ff7b2be7b927e16793eef4d34303 Libs/libmongoc.a
06268890fb365085d7f093b6941c507fb8f7fa2754fb22c62331ba8e8ae2068a Libs/libmongoc_arm64.a
b063818886170377f6cd1de714157032e3948e8a9616d3488a503423d8045053 Libs/libmongoc_universal.a
51b08ff457246e3032f1a13306f0e540658e91b1c560a7251ce5087a2ff17be0 Libs/libmongoc_x86_64.a
b063818886170377f6cd1de714157032e3948e8a9616d3488a503423d8045053 Libs/libmongoc.a
5dbf2cb5ef37d8adbf607db82461b36a3fd7037c11d891383e6e918378a33d78 Libs/libpgcommon_arm64.a
3ca491a723b9d9dfc13b815659b44a82253b540dd6b115f03ac68c5154ec26db Libs/libpgcommon_universal.a
4bfad7376aefa866d1ed0b7e54966ec6c9d70dcfed928e1311c20321bf08881c Libs/libpgcommon_x86_64.a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
* MONGOC_ENABLE_SSL_SECURE_TRANSPORT is set from configure to determine if we are
* compiled with Native SSL support on Darwin
*/
#define MONGOC_ENABLE_SSL_SECURE_TRANSPORT 1
#define MONGOC_ENABLE_SSL_SECURE_TRANSPORT 0

#if MONGOC_ENABLE_SSL_SECURE_TRANSPORT != 1
# undef MONGOC_ENABLE_SSL_SECURE_TRANSPORT
Expand All @@ -89,7 +89,7 @@
* MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO is set from configure to determine if we are
* compiled with Native Crypto support on Darwin
*/
#define MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO 1
#define MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO 0

#if MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO != 1
# undef MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO
Expand All @@ -111,7 +111,7 @@
* MONGOC_ENABLE_SSL_OPENSSL is set from configure to determine if we are
* compiled with OpenSSL support.
*/
#define MONGOC_ENABLE_SSL_OPENSSL 0
#define MONGOC_ENABLE_SSL_OPENSSL 1

#if MONGOC_ENABLE_SSL_OPENSSL != 1
# undef MONGOC_ENABLE_SSL_OPENSSL
Expand All @@ -122,7 +122,7 @@
* MONGOC_ENABLE_CRYPTO_LIBCRYPTO is set from configure to determine if we are
* compiled with OpenSSL support.
*/
#define MONGOC_ENABLE_CRYPTO_LIBCRYPTO 0
#define MONGOC_ENABLE_CRYPTO_LIBCRYPTO 1

#if MONGOC_ENABLE_CRYPTO_LIBCRYPTO != 1
# undef MONGOC_ENABLE_CRYPTO_LIBCRYPTO
Expand Down Expand Up @@ -164,7 +164,7 @@
/*
* Use ASN1_STRING_get0_data () rather than the deprecated ASN1_STRING_data
*/
#define MONGOC_HAVE_ASN1_STRING_GET0_DATA 0
#define MONGOC_HAVE_ASN1_STRING_GET0_DATA 1

#if MONGOC_HAVE_ASN1_STRING_GET0_DATA != 1
# undef MONGOC_HAVE_ASN1_STRING_GET0_DATA
Expand Down
4 changes: 4 additions & 0 deletions Plugins/MongoDBDriverPlugin/MongoDBCapabilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ struct MongoDBCapabilities: Sendable, Equatable {
major > 3 || (major == 3 && minor >= 4)
}

var supportsAuthorizedDatabases: Bool {
major >= 4
}

static func parse(_ version: String?) -> MongoDBCapabilities {
guard let version else { return .unknown }
let parts = version.split(separator: ".")
Expand Down
23 changes: 18 additions & 5 deletions Plugins/MongoDBDriverPlugin/MongoDBConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ extension MongoDBError: PluginDriverError {

/// Thread-safe MongoDB connection using libmongoc.
/// All blocking C calls are dispatched to a dedicated serial queue.
/// Uses `queue.async` + continuations (never `queue.sync`) to prevent deadlocks.
/// Async entry points use `queue.async` + continuations. Synchronous entry points
/// detect on-queue re-entry via `queueKey` and call sync helpers directly to
/// avoid `dispatch_sync` deadlocks when an on-queue block re-enters a public API.
final class MongoDBConnection: @unchecked Sendable {
// MARK: - Properties

Expand All @@ -50,6 +52,7 @@ final class MongoDBConnection: @unchecked Sendable {
private var client: OpaquePointer?
#endif

private static let queueKey = DispatchSpecificKey<ObjectIdentifier>()
private let queue = DispatchQueue(label: "com.TablePro.mongodb", qos: .userInitiated)
private let host: String
private let port: Int
Expand Down Expand Up @@ -133,6 +136,11 @@ final class MongoDBConnection: @unchecked Sendable {
self.authMechanism = authMechanism
self.replicaSet = replicaSet
self.extraUriParams = extraUriParams
queue.setSpecific(key: Self.queueKey, value: ObjectIdentifier(self))
}

private var isOnQueue: Bool {
DispatchQueue.getSpecific(key: Self.queueKey) == ObjectIdentifier(self)
}

deinit {
Expand Down Expand Up @@ -416,7 +424,7 @@ final class MongoDBConnection: @unchecked Sendable {
stateLock.unlock()

#if canImport(CLibMongoc)
let version = queue.sync { fetchServerVersionSync() }
let version = isOnQueue ? fetchServerVersionSync() : queue.sync { fetchServerVersionSync() }
stateLock.lock()
_cachedServerVersion = version
stateLock.unlock()
Expand Down Expand Up @@ -1044,9 +1052,14 @@ private extension MongoDBConnection {
try checkCancelled()

let caps = MongoDBCapabilities.parse(serverVersion())
let commandJSON = caps.supportsListDatabasesNameOnly
? "{\"listDatabases\": 1, \"nameOnly\": true}"
: "{\"listDatabases\": 1}"
var fields = ["\"listDatabases\": 1"]
if caps.supportsListDatabasesNameOnly {
fields.append("\"nameOnly\": true")
}
if caps.supportsAuthorizedDatabases {
fields.append("\"authorizedDatabases\": true")
}
let commandJSON = "{\(fields.joined(separator: ", "))}"
guard let command = jsonToBson(commandJSON) else {
throw MongoDBError(code: 0, message: "Failed to create listDatabases command")
}
Expand Down
3 changes: 1 addition & 2 deletions Plugins/MongoDBDriverPlugin/MongoDBPluginDriver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ final class MongoDBPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
let dbs = try await conn.listDatabases()
currentDb = dbs.first { !Self.systemDatabases.contains($0) } ?? dbs.first ?? ""
} catch {
conn.disconnect()
throw error
Self.logger.warning("listDatabases failed during connect, continuing without default database: \(error.localizedDescription, privacy: .public)")
}
}

Expand Down
32 changes: 20 additions & 12 deletions TablePro.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2871,19 +2871,23 @@
);
INFOPLIST_FILE = Plugins/MongoDBDriverPlugin/Info.plist;
INFOPLIST_KEY_NSPrincipalClass = "$(PRODUCT_MODULE_NAME).MongoDBPlugin";
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Libs";
LD_RUNPATH_SEARCH_PATHS = (
"@executable_path/../Frameworks",
"$(PROJECT_DIR)/Libs/dylibs",
);
LIBRARY_SEARCH_PATHS = (
"$(PROJECT_DIR)/Libs",
"$(PROJECT_DIR)/Libs/dylibs",
);
MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0;
OTHER_LDFLAGS = (
"-force_load",
"$(PROJECT_DIR)/Libs/libmongoc.a",
"-force_load",
"$(PROJECT_DIR)/Libs/libbson.a",
"-framework",
Security,
"-framework",
CoreFoundation,
"-lssl.3",
"-lcrypto.3",
"-lresolv",
"-lz",
);
Expand Down Expand Up @@ -2913,19 +2917,23 @@
);
INFOPLIST_FILE = Plugins/MongoDBDriverPlugin/Info.plist;
INFOPLIST_KEY_NSPrincipalClass = "$(PRODUCT_MODULE_NAME).MongoDBPlugin";
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Libs";
LD_RUNPATH_SEARCH_PATHS = (
"@executable_path/../Frameworks",
"$(PROJECT_DIR)/Libs/dylibs",
);
LIBRARY_SEARCH_PATHS = (
"$(PROJECT_DIR)/Libs",
"$(PROJECT_DIR)/Libs/dylibs",
);
MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0;
OTHER_LDFLAGS = (
"-force_load",
"$(PROJECT_DIR)/Libs/libmongoc.a",
"-force_load",
"$(PROJECT_DIR)/Libs/libbson.a",
"-framework",
Security,
"-framework",
CoreFoundation,
"-lssl.3",
"-lcrypto.3",
"-lresolv",
"-lz",
);
Expand Down
Loading
Loading