BoxLang 🚀 A New JVM Dynamic Language Learn More...
|:------------------------------------------------------: |
| ⚡︎ B o x L a n g ⚡︎
| Dynamic : Modular : Productive
|:------------------------------------------------------: |
Copyright Since 2023 by Ortus Solutions, Corp
www.boxlang.io | www.ortussolutions.com
This module provides a BoxLang JDBC driver for Oracle databases, enabling seamless integration between BoxLang applications and Oracle Database for enterprise-grade data operations with support for both Service Name and SID-based connections.
thin (default), oci, and kprb protocolsqueryExecute() and datasource managementbox install bx-oracle
# Into the BoxLang HOME
install-bx-module bx-oracle
# Or a local folder
install-bx-module bx-oracle --local
Once installed, you can immediately start using Oracle databases in your BoxLang applications:
// Define a datasource using Service Name
this.datasources[ "oracleDB" ] = {
"driver": "oracle",
"serviceName": "XEPDB1",
"host": "localhost",
"port": 1521,
"username": "system",
"password": "mypassword"
};
// Use it in your code
result = queryExecute("SELECT * FROM employees WHERE department_id = ?", [10], {"datasource": "oracleDB"});
See BoxLang's Defining Datasources documentation for full examples on where and how to construct a datasource connection pool.
This is the modern and recommended approach for Oracle connections:
this.datasources["oracleDB"] = {
"driver": "oracle",
"serviceName": "XEPDB1", // Oracle Service Name
"host": "localhost", // Default: localhost
"port": 1521, // Default: 1521
"username": "system",
"password": "mypassword"
};
Generated JDBC URL: jdbc:oracle: thin:@//localhost:1521/XEPDB1
For older Oracle installations or legacy systems:
this.datasources["legacyDB"] = {
"driver": "oracle",
"SID": "ORCL", // Oracle System ID
"host": "oracle-server.company.com",
"port": 1521,
"username": "appuser",
"password": "securepass"
};
Generated JDBC URL: jdbc:oracle:
thin:@oracle-server.company.com:1521: ORCL
For Oracle Autonomous Database or Oracle Cloud Infrastructure:
this.datasources["cloudDB"] = {
"driver": "oracle",
"serviceName": "mydb_high",
"host": "adb.us-ashburn-1.oraclecloud.com",
"port": 1522,
"protocol": "thin", // Options: thin, oci, kprb
"username": "ADMIN",
"password": "CloudPassword123"
};
You can specify additional JDBC properties and connection pool settings:
this.datasources["advancedDB"] = {
"driver": "oracle",
"serviceName": "PRODDB",
"host": "prod-oracle.example.com",
"port": 1521,
"username": "produser",
"password": "prodpassword",
// HikariCP Connection Pool Settings
"properties": {
"maximumPoolSize": 20,
"minimumIdle": 5,
"connectionTimeout": 30000,
"idleTimeout": 600000,
"maxLifetime": 1800000
},
// Oracle-specific JDBC parameters
"custom": {
"oracle.net.CONNECT_TIMEOUT": "10000",
"oracle.jdbc.ReadTimeout": "30000",
"v$session.program": "BoxLangApp"
}
};
| Property | Description | Example |
|---|---|---|
driver
| Must be "oracle"
| "oracle"
|
username
| Database username | "system"
|
password
| Database password | "mypassword"
|
| Either: | ||
serviceName
| Oracle Service Name (recommended) | "XEPDB1"
|
| Or: | ||
SID
| Oracle System Identifier (legacy) | "ORCL"
|
| Property | Default | Description |
|---|---|---|
host
| localhost
| Database server hostname or IP |
port
| 1521
| Oracle listener port |
protocol
| thin
| Connection protocol: thin, oci,
or kprb
|
Note: You must provide either
serviceName
or
SID, but not both.
thin
(Default): Pure Java JDBC driver, no Oracle Client requiredoci
: Oracle Call Interface, requires Oracle Client installationkprb
: Server-side internal driver for stored procedures// Create a table
queryExecute("
CREATE TABLE employees (
employee_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
first_name VARCHAR2(50) NOT NULL,
last_name VARCHAR2(50) NOT NULL,
email VARCHAR2(100) UNIQUE,
hire_date DATE DEFAULT SYSDATE,
salary NUMBER(10,2)
)
", [], {"datasource": "oracleDB"});
// Insert data
queryExecute("
INSERT INTO employees (first_name, last_name, email, salary)
VALUES (?, ?, ?, ?)
", ["John", "Doe", "[email protected]", 75000.00], {"datasource": "oracleDB"});
// Query data with bind parameters
employees = queryExecute("
SELECT employee_id, first_name, last_name, email, hire_date, salary
FROM employees
WHERE salary > ?
ORDER BY last_name
", [50000], {"datasource": "oracleDB"});
// Update data
queryExecute("
UPDATE employees
SET salary = salary * 1.10
WHERE employee_id = ?
", [1], {"datasource": "oracleDB"});
try {
// Begin transaction
transaction action="begin" {
// Multiple operations
queryExecute("
INSERT INTO employees (first_name, last_name, email, salary)
VALUES (?, ?, ?, ?)
", ["Jane", "Smith", "[email protected]", 80000], {"datasource": "oracleDB"});
queryExecute("
INSERT INTO audit_log (action, performed_by, performed_at)
VALUES (?, ?, SYSDATE)
", ["NEW_EMPLOYEE", "admin"], {"datasource": "oracleDB"});
// Commit transaction
transaction action="commit";
}
} catch (any e) {
// Rollback on error
transaction action="rollback";
rethrow;
}
// Sequences
newId = queryExecute("
SELECT employee_seq.NEXTVAL as next_id FROM dual
", [], {"datasource": "oracleDB"});
// PL/SQL Blocks
queryExecute("
BEGIN
update_employee_salary(?, ?);
END;
", [employeeId, newSalary], {"datasource": "oracleDB"});
// Oracle Date Functions
recentEmployees = queryExecute("
SELECT first_name, last_name, hire_date
FROM employees
WHERE hire_date >= ADD_MONTHS(SYSDATE, -6)
ORDER BY hire_date DESC
", [], {"datasource": "oracleDB"});
// Using ROWNUM for pagination
pagedResults = queryExecute("
SELECT * FROM (
SELECT e.*, ROWNUM rnum FROM (
SELECT * FROM employees ORDER BY hire_date DESC
) e WHERE ROWNUM <= ?
) WHERE rnum > ?
", [20, 10], {"datasource": "oracleDB"}); // Get rows 11-20
Perfect for development and testing with Oracle Express Edition:
// Application.bx for testing
component {
this.name = "MyTestApp";
this.datasources["testDB"] = {
"driver": "oracle",
"serviceName": "XEPDB1",
"host": "localhost",
"port": 1521,
"username": "system",
"password": "testpassword"
};
function onApplicationStart() {
// Create test schema
queryExecute("
CREATE TABLE IF NOT EXISTS test_data (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
test_name VARCHAR2(100),
test_value NUMBER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
", [], {"datasource": "testDB"});
return true;
}
}
# Clone the repository
git clone https://github.com/ortus-boxlang/bx-oracle.git
cd bx-oracle
# Build the module
./gradlew build
# Run tests (requires Oracle XE running)
./gradlew test
# Create module structure for local testing
./gradlew createModuleStructure
For local development and testing, use the included Docker Compose configuration:
# Start Oracle XE container
docker-compose up -d
# Check logs
docker-compose logs -f
# Stop the container
docker-compose down
Default Connection Details:
localhost
1521
XEPDB1
system
boxlangrocks
bx-oracle/
├── src/
│ ├── main/
│ │ ├── bx/
│ │ │ └── ModuleConfig.bx # Module configuration
│ │ ├── java/
│ │ │ └── ortus/boxlang/modules/
│ │ │ └── oracle/
│ │ │ ├── OracleDriver.java # JDBC driver implementation
│ │ │ └── util/
│ │ │ └── KeyDictionary.java
│ │ └── resources/
│ └── test/
│ ├── java/ # Unit and integration tests
│ └── resources/
│ ├── boxlang.json # Test runtime config
│ └── libs/ # BoxLang runtime JAR
├── build.gradle # Build configuration
├── box.json # ForgeBox module manifest
├── docker-compose.yaml # Oracle XE for testing
└── readme.md # This file
The module includes comprehensive tests:
# Run all tests
./gradlew test
# Run with verbose output
./gradlew test --info
# Run specific test class
./gradlew test --tests "OracleDriverTest"
# Format code
./gradlew spotlessApply
git checkout -b feature/amazing-feature)./gradlew test)./gradlew spotlessApply)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)| Module Version | BoxLang Version | Oracle JDBC Version |
|---|---|---|
| 1.6.x | 1.3.0+ | 23.5.0.24.07 |
| 1.5.x | 1.2.0+ | 21.x |
Solution: Ensure Oracle listener is running and accessible:
# Check listener status
lsnrctl status
# Check if port is open
telnet oracle-host 1521
# Verify firewall rules allow connections to port 1521
Error: Either the serviceName or SID property
is required for the Oracle JDBC Driver.
Solution: Provide exactly one connection identifier:
// CORRECT - Service Name
"serviceName": "XEPDB1"
// CORRECT - SID
"SID": "ORCL"
// INCORRECT - Missing both
// (no serviceName or SID property)
// INCORRECT - Both specified (SID takes precedence)
"serviceName": "XEPDB1",
"SID": "ORCL"
Error: The protocol 'xyz' is not valid for the
Oracle Driver.
Solution: Use only supported protocols:
"protocol": "thin" // Default, pure Java
"protocol": "oci" // Requires Oracle Client
"protocol": "kprb" // Server-side only
Error: UnsatisfiedLinkError: no ocijdbc in java.library.path
Solution: The oci protocol requires
Oracle Instant Client:
LD_LIBRARY_PATH (Linux) or PATH
(Windows) to include the client locationthin protocol which doesn't require client librariesError: Module fails to load or driver not registered
Solution: Ensure module is properly installed:
# Rebuild module
./gradlew clean build
# Check module structure
ls -la build/module/libs/
# Verify BoxLang can find the module
install-bx-module bx-oracle --force
Enable debug logging in your BoxLang application:
// In your Application.bx
this.datasources["debugDB"] = {
"driver": "oracle",
"serviceName": "XEPDB1",
"host": "localhost",
"port": 1521,
"username": "system",
"password": "password",
"logSql": true,
"logLevel": "DEBUG"
};
See changelog.md for a complete list of changes and version history.
Licensed under the Apache License, Version 2.0. See LICENSE for details.
BoxLang is a professional open-source project and it is completely funded by the community and Ortus Solutions, Corp. Ortus Patreons get many benefits like a cfcasts account, a FORGEBOX Pro account and so much more. If you are interested in becoming a sponsor, please visit our patronage page: https://patreon.com/ortussolutions
"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
serviceName datasource property
$
box install bx-oracle