# Architectural Design of DBX's Agent Runtime for JDBC Connections

> Explore the robust architectural design of DBX's agent runtime for JDBC connections. Learn how isolated agents ensure uniform, secure database interactions.

- Repository: [skyler/dbx](https://github.com/t8y2/dbx)
- Tags: architecture
- Published: 2026-07-05

---

**DBX implements each JDBC driver as an isolated agent process that communicates with the core platform via JSON-RPC 2.0 over stdin/stdout, providing a uniform interface for connection management, query execution, and metadata extraction across diverse database systems.**

The t8y2/dbx repository provides a lightweight, driver-agnostic solution for database connectivity by wrapping JDBC drivers in standalone agent processes. Understanding the architectural design of DBX's agent runtime for JDBC connections reveals how the system isolates driver-specific complexity while maintaining a consistent JSON-RPC interface for cross-database operations.

## Core Runtime Components

The agent runtime follows a standardized pattern implemented uniformly across all drivers, as demonstrated in the Oracle driver ([`agents/drivers/oracle-go/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/oracle-go/main.go)) and the Xugu driver ([`agents/drivers/xugu/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/xugu/main.go)).

### The Server Struct

Each agent maintains a **server struct** that serves as the central state container. This structure holds the live `*sql.DB` connection pool, connection parameters, and active pagination sessions.

In [`agents/drivers/oracle-go/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/oracle-go/main.go) (lines 58-65), the server is defined as:

```go
type server struct {
    db       *sql.DB
    host     string
    port     int
    username string
    password string
    // ... pagination sessions map
}

```

The Xugu driver implements an identical pattern in [`agents/drivers/xugu/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/xugu/main.go) (lines 61-66), ensuring runtime consistency across different database systems.

### JSON-RPC Entry Point

The **JSON-RPC 2.0 protocol** drives all communication between the DBX core and agent processes. The `main` function initializes the server, writes a readiness banner to stdout, and enters a read loop processing lines from stdin.

According to the source in [`agents/drivers/oracle-go/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/oracle-go/main.go) (lines 67-74):

```go
func main() {
    srv := &server{sessions: make(map[string]*querySession)}
    fmt.Println(`{"ready":true}`)
    // ... JSON-RPC read loop
}

```

This design ensures that DBX can spawn agent processes as needed and reliably detect when they are ready to accept connections.

### Method Dispatch Pattern

Incoming requests route through a centralized **dispatch** method that matches the `method` field to concrete handlers. The dispatcher in [`agents/drivers/oracle-go/main.go`](https://github.com/t8y2/dbx/blob/main/agents/drivers/oracle-go/main.go) (lines 12-34) handles methods including `connect`, `list_tables`, `execute_query`, and `shutdown`.

Each handler returns a standardized `response` struct containing `JSONRPC`, `ID`, and either `Result` or `Error`, enabling consistent error propagation back to the DBX core.

## Connection Management and JDBC URL Parsing

### DSN Construction

The **connect** method transforms incoming connection parameters into driver-specific Data Source Names (DSNs). The `buildDSN` function (Oracle lines 78-94, Xugu lines 92-110) supports multiple input formats:

- Plain host/port/database parameters
- Standard JDBC URLs (e.g., `jdbc:oracle:thin:@//host:1521/DB`)
- Custom connection strings

For Oracle specifically, `parseOracleJDBCURL` (lines 24-30) extracts the SID or service name and delegates to `go_ora.BuildUrl` to construct the final connection string.

### Driver Initialization

Once the DSN is constructed, the agent invokes `sql.Open` with the driver-specific dialect (e.g., `go_ora` for Oracle). The resulting `*sql.DB` is stored in the server struct, where it remains available for subsequent RPC calls until the **shutdown** method (Oracle lines 130-134) closes the connection and terminates the process.

## Query Execution and Pagination

### SELECT vs. DML/DDL Handling

The **executeQuery** function (Oracle lines 176-197, Xugu lines 176-197) determines statement type and routes accordingly:

- **SELECT statements**: Delegated to `executeSelect`, which uses `db.Query` and returns structured results
- **DML/DDL statements**: Executed via `db.Exec` with immediate acknowledgment

Results are marshaled into a `queryResult` struct containing column metadata and row data arrays.

### Session-Based Pagination

For large result sets, the agent implements **query sessions** that maintain iterator state between RPC calls. When `execute_query_page` receives a `pageSize` parameter, the agent creates a `querySession` storing the `*sql.Rows` iterator, remaining row count, and column metadata.

The session is identified by a generated string (e.g., `oracle-go-1` or `xugu-1`) returned to the client. Subsequent calls to `fetch_query_page` with this `sessionId` retrieve the next batch of rows without resending the original SQL.

Session storage occurs in `storeQuerySession` (Oracle lines 334-337, Xugu lines 215-218), which maps session IDs to live iterators in the server struct's sessions map.

## Metadata and Schema Operations

### Database Introspection

Metadata queries follow a consistent pattern across drivers. Functions like `list_databases`, `list_schemas`, `list_tables`, and `get_columns` construct driver-specific SQL (e.g., `oracleListTablesSQL`) and execute them via `queryRows`.

The `listTables` implementation (Oracle lines 221-244, Xugu lines 108-131) transforms raw SQL results into typed structs (`tableInfo`, `databaseInfo`) before returning them as JSON-RPC results.

### DDL Generation

When native metadata functions fail (such as Oracle's `DBMS_METADATA.GET_DDL`), the agent falls back to **DDL synthesis**. The `buildTableDDL` function (Oracle lines 216-250, Xugu lines 162-191) reconstructs `CREATE TABLE` statements by querying column metadata (names, types, defaults, constraints) and formatting them into valid SQL dialects specific to the target database.

## Error Handling and Lifecycle Management

All operations return structured error responses following JSON-RPC 2.0 specifications. The runtime guarantees graceful degradation through the `shutdown` RPC, which explicitly closes database connections and clears session state before process termination.

This architecture provides **process isolation** for driver-specific code—if a JDBC driver crashes or hangs, only that agent process is affected, leaving the DBX core and other connections unaffected.

## Summary

- **Process Isolation**: Each JDBC driver runs as a separate agent process communicating via JSON-RPC 2.0 over stdin/stdout  
- **Uniform Interface**: The `server` struct and `dispatch` pattern provide consistent handling across Oracle, Xugu, and future drivers  
- **Flexible Connection**: `buildDSN` and JDBC URL parsers support multiple connection string formats  
- **Streaming Results**: Session-based pagination with `querySession` objects enables efficient handling of large datasets  
- **Robust Metadata**: Driver-specific SQL queries handle introspection, with fallback DDL generation when native metadata APIs are unavailable  

## Frequently Asked Questions

### How does DBX handle different JDBC URL formats across databases?

Each agent implements driver-specific parsers such as `parseOracleJDBCURL` and `parseXuguJDBCURL` within their respective `buildDSN` functions. These extract host, port, and service components from standard JDBC URLs and convert them into the native DSN format required by the underlying Go driver (e.g., `go_ora` for Oracle).

### What is the purpose of the query session in DBX's pagination system?

The **query session** maintains a live `*sql.Rows` iterator on the agent side, allowing DBX to fetch large result sets in configurable chunks via `fetch_query_page` calls. This approach minimizes memory usage on both the agent and client by streaming data incrementally rather than loading entire result sets into memory.

### How does the agent runtime ensure isolation between database drivers?

By implementing each driver as a separate OS process spawned by the DBX core, the architecture prevents driver crashes or resource leaks from affecting other connections. The JSON-RPC boundary over stdin/stdout acts as a strict isolation layer, with the `server` struct encapsulating all driver-specific state within its own memory space.

### What happens when native metadata APIs like DBMS_METADATA are unavailable?

The agent automatically falls back to **DDL synthesis** via the `buildTableDDL` function. This method queries the information schema for column definitions, constraints, and indexes, then reconstructs valid `CREATE TABLE` statements programmatically, ensuring metadata retrieval works even when proprietary metadata packages are restricted or unavailable.