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

## [Unreleased]

### Added

- Oracle connections negotiate Native Network Encryption when the server asks for it, so servers with `SQLNET.ENCRYPTION_SERVER` or `SQLNET.CRYPTO_CHECKSUM_SERVER` set to REQUIRED now connect (AES with a SHA crypto-checksum), matching what SQL Developer and DBeaver do. (#483)
- Oracle connections follow listener redirects, so RAC SCAN listeners, shared server, and load-balanced setups now connect instead of failing during the handshake. (#483)

### Fixed

- Oracle connection failures show the listener's actual reason (such as an unknown service name) instead of a generic "server closed the connection" message. (#483)

## [0.46.0] - 2026-05-28

### Added
Expand Down
15 changes: 14 additions & 1 deletion Plugins/OracleDriverPlugin/OracleConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ final class OracleConnectionWrapper: @unchecked Sendable {
let target = useSID ? "\(self.host):\(self.port):\(identifier)" : "\(self.host):\(self.port)/\(identifier)"
osLogger.debug("Connected to Oracle \(target)")
} catch let sqlError as OracleSQLError {
let detail = sqlError.serverInfo?.message ?? sqlError.description
let detail = Self.connectFailureDetail(sqlError)
osLogger.error("Oracle connection failed: \(detail)")
if let sslError = Self.classifySSLError(detail) {
throw sslError
Expand Down Expand Up @@ -246,6 +246,19 @@ final class OracleConnectionWrapper: @unchecked Sendable {
}
}

private static func connectFailureDetail(_ error: OracleSQLError) -> String {
if let refused = error.underlying as? OracleListenerRefusedError {
if let code = refused.code {
return String(
format: String(localized: "The Oracle listener refused the connection (ORA-%d)."),
code
)
Comment on lines +251 to +255
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 Preserve the listener refusal text

For listener-refused failures such as ORA-12514, ORA-12516, or ACL/policy refusals, the listener's text distinguishes very different fixes (unknown service vs no handler vs filtered by ACL). This new branch formats only the numeric code and discards the refused error's own message/description, so the connection dialog still won't show the “actual reason” this change is meant to surface; include the listener text alongside the ORA code instead of replacing it with this generic sentence.

Useful? React with 👍 / 👎.

}
return String(localized: "The Oracle listener refused the connection.")
}
return error.serverInfo?.message ?? error.description
}

private static func connectErrorMessage(
for category: OracleError.Category,
serverDetail: String
Expand Down
7 changes: 3 additions & 4 deletions Plugins/OracleDriverPlugin/OraclePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,9 @@ final class OraclePlugin: NSObject, TableProPlugin, DriverPlugin, PluginDiagnost
title: String(localized: "Connection Dropped During Handshake"),
message: oracleError.message,
suggestedActions: [
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.")
String(localized: "Check for a firewall, VPN, or load balancer between you and the server that closes connections mid-handshake."),
String(localized: "If the listener endpoint is TLS-only (TCPS), set the SSL mode in the connection's SSL settings."),
String(localized: "Confirm the host and port reach the database listener directly, not a proxy that resets unknown traffic.")
],
supportURL: URL(string: "https://github.com/TableProApp/TablePro/issues/483")
)
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 = 254b72adfb6b527ac45895b42a38e60ba6c77a1f;
revision = 04a4e5967bf4d96cadf66081ea5a22133fe403ea;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down

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

4 changes: 3 additions & 1 deletion docs/databases/oracle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ description: Connect to Oracle Database with TablePro
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.

<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).
Oracle 10g and earlier are not supported: they use the older O3LOGON handshake that the pure-Swift driver does not implement.
</Note>

Servers behind a RAC SCAN listener, shared server, or a load balancer are supported: TablePro follows the listener's redirect to the instance that serves the session. Servers that require Native Network Encryption (`SQLNET.ENCRYPTION_SERVER` or `SQLNET.CRYPTO_CHECKSUM_SERVER` set to REQUIRED) are also supported; TablePro negotiates AES encryption with a SHA crypto-checksum, the same as SQL Developer and DBeaver.

## Install Plugin

The Oracle driver is available as a downloadable plugin. When you select Oracle in the connection form, TablePro will prompt you to install it automatically. You can also install it manually:
Expand Down
Loading