[Pitch] OracleNIO: Oracle DB Driver built on SwiftNIO

I'd like to pitch my OracleNIO library to the SSWG incubation process. It provides a database driver for interacting with Oracle databases starting with version 12.1.

Motivation

Oracle databases are widely used, especially in enterprise. People (myself included) have asked about the existence of an Oracle driver in the past (Vapor Discord, Swift Forums Thread, StackOverflow, Apple Developer Forums, ...).

Previously it was only possible to integrate with Oracle databases by wrapping a C library, which required a few system dependencies such as Oracle Call Interface (OCI) and others. The setup and usage was not ideal and error prone.

I believe that it is a great addition to the SSWG projects and would make Swift a viable choice for projects integrating with Oracle databases.

Proposed solution

During the last year, I've created a standalone Swift driver based on SwiftNIO. This is the first standalone driver in any language not developed directly by Oracle, most other drivers require OCI or ODPI-C. Due to that, OracleNIO does not require any system dependencies and works out of the box, like PostgresNIO and others.

The protocol implementation is based on python-oracledb (thin mode), node-oracledb (thin mode), and contact with Anthony Tuininga, Christopher Jones and Sudarshan Soma from Oracle.

It's API is very similar to PostgresNIO, this should make the adoption easier.

Most notable features:

  • Standalone connections
  • Connection pooling (backed by PostgresNIO's ConnectionPool module, thanks to @FabianFett)
  • Database Resident Connection Pooling (DRCP)
  • Multiple authentication options
  • TLS support
  • Oracle Cloud support
  • Connection pinging
  • SQL execution with binds (in and out)
  • PL/SQL execution with binds (in, in/out and out)
  • Commits and rollbacks
  • LOB support (up to 1 GB)

There are a few more things I'd like to add before v1.0:

  • Support for storing and reading JSON
  • Support for storing and reading LOBs bigger than 1 GB per LOB (I'm unsure about the necessity of this)
  • Removing the dependency on CryptoSwift (more about this below)
  • mutual TLS support (optional)
  • Improve documentation

Although I didn't publish a release yet, I'm already using the driver in production without issues (I'd encourage everyone else to wait for a release :slight_smile:).

Feedback is appreciated and breaking changes are still possible.

Usage example

import OracleNIO
import Logging

let logger = Logger(label: "my-logger")

let config = OracleConnection.Configuration(
    host: "127.0.0.1", 
    port: 1521,
    service: .serviceName("my_service"),
    username: "my_username",
    password: "my_password"
)

let connection = try await OracleConnection.connect(
  configuration: config,
  id: 1,
  logger: logger
)

let id = 1
let username = "fancyuser"
let birthday = Date()
try await connection.query("""
  INSERT INTO users (id, username, birthday) VALUES (\(id), \(username), \(birthday))
  """, 
  logger: logger
)

let rows = try await connection.query("SELECT id, username, birthday FROM users", logger: logger)

for try await (id, username, birthday) in rows.decode((Int, String, Date).self) {
  // do something with the rows.
}

try await connection.close()

Dependencies

I'd like to drop the dependency on CryptoSwift. It's currently used for CBC without padding and PBKDF2.
I've created a PR on swift-crypto which adds support for CBC without padding. It has been merged to main already. With the next release of swift-crypto, I'll be able to refactor the CBC related code to use it.
There is also a PR#98 on swift-crypto regarding PBKDF2, which is open since 2021. I'm wondering if I should add a C module for PBKDF2 until swift-crypto supports it, or stay on CryptoSwift. I'd like to hear some opinions on that.

I'm looking forward to your feedback :slight_smile:

15 Likes

cc @lukasa, @PeterAdams-A something for _CryptoExtras?

I think it's a good addition for _CryptoExtras, but I'd like us to add a better alternative alongside it. While I appreciate the need to have this for compatibility reasons, I want to make sure users can reach for a better solution than PBKDF2 for new use-cases. For example, we should also add scrypt for password storage.

3 Likes

I love it, fantastic work!!

2 Likes

+1

1 Like

At last!

1 Like

Is it already on the swift package index site?

If we're open adding additional algorithms, I'd also like to see Argon2 considered - it's a much more modern alternative with tunable resistance to GPU/ASIC and side-channel attacks.

1 Like

Not yet, I'd like to add it after releasing an initial version