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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- BigQuery: the sidebar now shows every dataset as an expandable node, with each dataset's tables loading when you open it, instead of showing one dataset at a time behind a picker.
- OpenCode Zen as an AI provider. Add it from the provider list and paste an OpenCode key, or leave the key blank to use the free models; the model list loads automatically, covering the Claude, GPT, Gemini, and open models Zen serves. (#1400)
- Oracle Database 11g (11.1 and 11.2) now connects. Previously only 12c and later worked, so 11g servers failed with a "Server Version Not Supported" error. (#1425)
- Cmd-click a foreign key arrow to open the referenced table in a new tab instead of the current one. The right-click menu has the same Open in New Tab option. (#1421)

### Changed
Expand All @@ -21,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Custom and OpenAI-compatible AI providers now work when the base URL already ends in `/v1`, instead of building a doubled `/v1/v1/` path that failed. (#1400)
- MongoDB: opening a collection no longer crashes when a document contains a NaN or infinite number. (#1418)
- Opening a saved connection that fails now shows the detailed troubleshooting dialog with suggested fixes, the same one Test Connection shows, instead of a generic error alert. (#1425, #483)
- Oracle connection errors no longer surface the driver's raw internal message; failures now explain the cause in plain language. (#483)

## [0.45.0] - 2026-05-26

Expand Down
22 changes: 21 additions & 1 deletion Plugins/OracleDriverPlugin/OracleConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ final class OracleConnectionWrapper: @unchecked Sendable {
if let sslError = Self.classifySSLError(detail) {
throw sslError
}
throw OracleError(message: detail, category: classifyConnectError(sqlError))
let category = classifyConnectError(sqlError)
throw OracleError(
message: Self.connectErrorMessage(for: category, serverDetail: detail),
category: category
)
} catch let nioSslError as NIOSSLError {
let detail = String(describing: nioSslError)
osLogger.error("Oracle TLS error: \(detail)")
Expand Down Expand Up @@ -237,6 +241,22 @@ final class OracleConnectionWrapper: @unchecked Sendable {
}
}

private static func connectErrorMessage(
for category: OracleError.Category,
serverDetail: String
) -> String {
switch category {
case .authVersionNotSupported:
return String(localized: "This Oracle server is older than release 11.1, which the database driver does not support.")
case .authConnectionDropped:
return String(localized: "The Oracle server closed the connection during the login handshake.")
case .authVerifierUnsupported:
return String(localized: "This account uses a password verifier the database driver does not support.")
case .generic, .notConnected, .connectionFailed, .queryFailed:
return serverDetail
}
}

func disconnect() {
let connection = state.withLock { current -> OracleNIO.OracleConnection? in
guard current.isConnected else { return nil }
Expand Down
12 changes: 6 additions & 6 deletions Plugins/OracleDriverPlugin/OraclePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ final class OraclePlugin: NSObject, TableProPlugin, DriverPlugin, PluginDiagnost
title: String(localized: "Connection Dropped During Handshake"),
message: oracleError.message,
suggestedActions: [
String(localized: "If the same connection works in DBeaver or sqlplus, this is likely an OOB compatibility issue with cloud-hosted Oracle."),
String(localized: "TablePro 1.2.0 already gates OOB on the server flag, so most cases are resolved. If you still hit this, file an issue."),
String(localized: "Try disabling SSH tunnel or load balancer firewall rules between client and server.")
String(localized: "The server may require Native Network Encryption, which the pure-Swift driver cannot negotiate."),
String(localized: "Configure the listener for TLS, or set SQLNET.ENCRYPTION_SERVER to ACCEPTED instead of REQUIRED."),
String(localized: "If the same connection works in DBeaver or SQL Developer, they use Oracle's OCI client, which supports Native Network Encryption."),
String(localized: "Check for a firewall or load balancer between the client and server that closes connections mid-handshake.")
],
supportURL: URL(string: "https://github.com/TableProApp/TablePro/issues/483")
)
Expand All @@ -134,9 +135,8 @@ final class OraclePlugin: NSObject, TableProPlugin, DriverPlugin, PluginDiagnost
title: String(localized: "Server Version Not Supported"),
message: oracleError.message,
suggestedActions: [
String(localized: "TablePro requires Oracle 12c or later via the OracleNIO Swift driver."),
String(localized: "Check the user account's password_versions; only 10G, 11G, and 12C are supported."),
String(localized: "Rotate the password under modern auth if password_versions contains an unrecognized verifier.")
String(localized: "TablePro supports Oracle Database 11.1 and later. This server reports an older release (10g or earlier)."),
String(localized: "Upgrade the database to 11.2 or later, or connect with a client that bundles Oracle's OCI client such as SQL Developer or DataGrip.")
],
supportURL: issuesURL
)
Expand Down
2 changes: 1 addition & 1 deletion TablePro.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -4191,7 +4191,7 @@
repositoryURL = "https://github.com/TableProApp/oracle-nio";
requirement = {
kind = revision;
revision = 7c01c8ff2e13794650719ebfa0294aa4281bbdd8;
revision = 254b72adfb6b527ac45895b42a38e60ba6c77a1f;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 4 additions & 9 deletions TablePro/Core/Services/Infrastructure/WelcomeRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import Combine
import Foundation
import Observation

internal struct PendingConnectionError: Equatable {
let connectionId: UUID
let connectionName: String
let message: String
internal struct PendingConnectionError {
let connection: DatabaseConnection
let error: Error
}

@MainActor
Expand Down Expand Up @@ -52,11 +51,7 @@ internal final class WelcomeRouter {
}

internal func routeError(_ error: Error, for connection: DatabaseConnection) {
pendingError = PendingConnectionError(
connectionId: connection.id,
connectionName: connection.name,
message: error.localizedDescription
)
pendingError = PendingConnectionError(connection: connection, error: error)
showWelcomeWindow()
}

Expand Down
18 changes: 14 additions & 4 deletions TablePro/ViewModels/WelcomeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ final class WelcomeViewModel {

var connectionError: String?
var showConnectionError = false
var pluginDiagnostic: PluginDiagnosticItem?

var showImportFilePanel = false
var importResultCount: Int?
Expand Down Expand Up @@ -219,8 +220,7 @@ final class WelcomeViewModel {
return
}
if let pendingError = WelcomeRouter.shared.consumePendingError() {
connectionError = pendingError.message
showConnectionError = true
presentConnectionFailure(pendingError.error, connection: pendingError.connection)
}
}

Expand Down Expand Up @@ -609,7 +609,17 @@ final class WelcomeViewModel {

Self.logger.error("Failed to connect: \(error.localizedDescription, privacy: .public)")
WindowManager.shared.closeWindow(for: connection.id)
connectionError = SSLHandshakeError.formatted(error)
showConnectionError = true
presentConnectionFailure(error, connection: connection)
}

private func presentConnectionFailure(_ error: Error, connection: DatabaseConnection) {
if let item = PluginDiagnosticItem.classify(
error: error, connection: connection, username: connection.username
) {
pluginDiagnostic = item
} else {
connectionError = SSLHandshakeError.formatted(error)
showConnectionError = true
}
}
}
5 changes: 5 additions & 0 deletions TablePro/Views/Connection/WelcomeWindowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ struct WelcomeWindowView: View {
.pluginInstallPrompt(connection: $vm.pluginInstallConnection) { connection in
vm.connectAfterInstall(connection)
}
.sheet(item: $vm.pluginDiagnostic) { item in
PluginDiagnosticSheet(item: item) {
vm.pluginDiagnostic = nil
}
}
.alert(String(localized: "Rename Group"), isPresented: $vm.showRenameGroupAlert) {
TextField(String(localized: "Group name"), text: $vm.renameGroupName)
Button(String(localized: "Rename")) { vm.confirmRenameGroup() }
Expand Down
10 changes: 5 additions & 5 deletions docs/databases/oracle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ description: Connect to Oracle Database with TablePro

# Oracle Database Connections

TablePro supports Oracle Database 12c and later via Oracle Call Interface (OCI). This covers Oracle Database instances running on-premises, in Docker, or Oracle Cloud.
TablePro supports Oracle Database 11.1 and later. It speaks the Oracle TNS wire protocol directly in Swift, so no Oracle Instant Client or other external library is required. This covers Oracle Database instances running on-premises, in Docker, or Oracle Cloud.

<Warning>
Oracle Instant Client must be installed before connecting to Oracle Database. Download it from [Oracle's website](https://www.oracle.com/database/technologies/instant-client.html) and ensure the libraries are accessible.
</Warning>
<Note>
Oracle 10g and earlier are not supported: they use the older O3LOGON handshake that the pure-Swift driver does not implement. Servers that require Native Network Encryption also need Oracle's OCI client (use TLS instead).
</Note>

## Install Plugin

Expand Down Expand Up @@ -116,7 +116,7 @@ ALTER USER <USER> IDENTIFIED BY <new-secure-password>;
SELECT username, password_versions FROM dba_users WHERE username = '<USER>';
```

If the connection fails with the dialog "Server Version Not Supported" or "Unsupported Password Verifier", check `password_versions` first.
If the connection fails with "Unsupported Password Verifier", check `password_versions` first. "Server Version Not Supported" means the database is older than 11.1 (10g or earlier), which the driver cannot connect to.

## Column Type Support

Expand Down
Loading