# Chat2DB Database SPI Plugins Implementation Contract: A Complete Developer Guide

> Learn the Chat2DB database SPI plugins implementation contract. Discover how to implement the IPlugin interface, expose database specifics with IDbMetaData, IDbManager, and ISqlBuilder, and register for Spring runtime discovery.

- Repository: [OtterMind/Chat2DB](https://github.com/OtterMind/Chat2DB)
- Tags: api-reference
- Published: 2026-07-26

---

**Chat2DB database SPI plugins must implement the `IPlugin` interface as a single entry point, expose database-specific implementations via `IDbMetaData`, `IDbManager`, and `ISqlBuilder`, and register via `META-INF/services/ai.chat2db.spi.IPlugin` to be discovered by the Spring-based runtime.**

The Chat2DB project uses a Service Provider Interface (SPI) architecture to support multiple database dialects without hard-coding database logic into the core server. Understanding this implementation contract is essential for developers extending Chat2DB with custom database support or maintaining existing plugins.

## Core SPI Architecture

The `chat2db-community-spi` module defines the contracts that every database plugin must obey. The architecture separates concerns into distinct interfaces: configuration, metadata discovery, connection management, and SQL generation.

### The Primary Entry Point: `IPlugin`

Every plugin must provide exactly one class implementing `ai.chat2db.spi.IPlugin`, located at [`chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/IPlugin.java`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/IPlugin.java). This class serves as the primary entry point discovered by the runtime.

The contract mandates:
- **Naming convention**: The entry class must be named `<Database>Plugin` (e.g., `MysqlPlugin`, `PostgresqlPlugin`)
- **Registration**: Must be listed in `META-INF/services/ai.chat2db.spi.IPlugin`

The `IPlugin` interface requires implementation of these core methods:
- `getDBConfig()` – Returns default connection configuration (driver class, URL template, etc.)
- `getDbMetaData()` – Provides the metadata provider (defaults to `DefaultMetaService` if not overridden)
- `getDbManager()` – Returns the DDL and connection manager (implementation class must be named `<Database>DBManager`)
- `getSqlBuilder()` – Returns the dialect-specific SQL builder
- `getValueProcessor()` – Handles value type conversions
- `getSQLIdentifierProcessor()` – Manages identifier quoting and escaping
- `getCommandExecutor()` – Executes commands specific to the database
- `getKeyOperations()` – Provides key operation handlers

### Metadata Provider Interface

The `IDbMetaData` interface, defined in [`chat2db-community-spi/src/main/java/ai/chat2db/spi/IDbMetaData.java`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-spi/src/main/java/ai/chat2db/spi/IDbMetaData.java), supplies catalog information. Implementations must provide methods for enumerating database objects:

- `databases()` – List available databases
- `schemas()` – List schemas within a database
- `tables()` – List tables with filtering support
- `columns()` – Describe table columns
- `indexes()` – List table indexes
- `functions()` and `triggers()` – List routines and triggers

The interface also includes helpers for identifier handling and result-set type mapping.

### Database Manager and SQL Builder

The `IDbManager` implementation (naming convention: `<Database>DBManager`) handles JDBC connections and executes DDL/DML. Critically, contract section 4 mandates that this class **must not** contain SQL construction logic; it delegates to an `ISqlBuilder`.

The `ISqlBuilder` interface provides the unified entry point for constructing SQL strings. Methods must follow the naming pattern `build<Verb><Object>` (e.g., `buildCreateTable`, `buildDropIndex`). The builder supports semantic groups including:
- `identifier()` and `literal()` – Escaping and formatting
- `dql()`, `dml()`, `ddl()`, `dcl()`, `tcl()` – SQL command categories
- `metadata()` – Information schema queries
- `routine()` – Stored procedure/function DDL
- `export()` – Export-specific SQL generation
- `unsafe()` – Raw SQL passthrough

## Discovery and Registration

The runtime discovers plugins using Spring's `ServiceLoader` mechanism. Each plugin must include a registration file:

```

META-INF/services/ai.chat2db.spi.IPlugin

```

This file contains the fully-qualified name of the plugin's entry class (e.g., `ai.chat2db.plugin.mysql.MysqlPlugin`). Only one entry class is permitted per plugin JAR.

## Implementation Requirements and Constraints

### Security and Resource Management

The contract enforces strict security patterns for database interaction:
- **PreparedStatement usage**: All SQL execution involving user input must use `PreparedStatement`. Direct use of `Statement#createStatement().execute(...)` is prohibited (contract sections 8-71 to 8-74)
- **Resource handling**: JDBC objects must be managed via try-with-resources. Implementations must never close connections owned by the caller (contract sections 10-87 to 10-90)

### Error Handling Semantics

Plugin methods must throw exceptions for failures and return empty collections where appropriate. Using `null` to signal unsupported operations, failures, or empty results violates the contract (sections 9-79 to 9-84).

### Constants and Resources

All raw SQL fragments, error codes, and command names must reside in the `.../constant` package within each plugin module. Hard-coding literals in implementation classes violates contract sections 5-35 to 5-42. Resource files live under `src/main/resources` (contract section 7).

### SPI Boundary Rules

The `chat2db-community-spi` and `chat2db-community-tools` modules must remain database-agnostic. No concrete database-type branching (e.g., `if (type == MYSQL)`) is permitted inside the SPI layer; such logic belongs exclusively in concrete plugin implementations (contract sections 11-94 to 11-98).

## Optional Extensions

Plugins may optionally implement:
- `ISqlSyntaxPlugin` – Exposed via `IPlugin#getSqlSyntaxPlugin()` for SQL parsing and completion support (must be obtained through the primary plugin, not via separate ServiceLoader)
- `IAccountManager` – For database-specific user account management
- `IRoutineManager` – For stored procedure and function management

## Code Example: Minimal MySQL Plugin

Below is a complete skeleton implementing the Chat2DB SPI contract for MySQL:

```java
// src/main/java/ai/chat2db/plugin/mysql/MysqlPlugin.java
package ai.chat2db.plugin.mysql;

import ai.chat2db.community.domain.api.config.DBConfig;
import ai.chat2db.spi.*;

public class MysqlPlugin implements IPlugin, ISqlSyntaxPlugin {
    
    @Override
    public DBConfig getDBConfig() {
        return new DBConfig()
                .setDbType("MYSQL")
                .setDriverClassName("com.mysql.cj.jdbc.Driver")
                .setUrlTemplate("jdbc:mysql://{host}:{port}/{database}");
    }

    @Override
    public IDbManager getDbManager() {
        return new MysqlDBManager();
    }

    @Override
    public ISqlBuilder getSqlBuilder() {
        return new MysqlSqlBuilder();
    }

    @Override
    public ISqlSyntaxPlugin getSqlSyntaxPlugin() {
        return this;
    }
}

```

```java
// src/main/java/ai/chat2db/plugin/mysql/MysqlDBManager.java
package ai.chat2db.plugin.mysql;

import ai.chat2db.spi.IDbManager;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class MysqlDBManager implements IDbManager {
    
    @Override
    public void execute(Connection conn, String sql, Object... args) throws Exception {
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            ps.execute();
        }
    }
}

```

Contract reference documentation is maintained in [`java-plugin-contracts.md`](https://github.com/OtterMind/Chat2DB/blob/main/java-plugin-contracts.md) at the repository root, with full interface definitions available in the `chat2db-community-spi` module source tree.

## Summary

- **Single entry point**: Implement `IPlugin` in a class named `<Database>Plugin` and register it in `META-INF/services/ai.chat2db.spi.IPlugin`
- **Core interfaces**: Provide implementations for `IDbMetaData` (catalog discovery), `IDbManager` (connection/execution), and `ISqlBuilder` (SQL generation)
- **Security first**: Use `PreparedStatement` for all parameterized queries and try-with-resources for resource management
- **Naming conventions**: Follow the `<Database>DBManager` pattern for managers and `build<Verb><Object>` for SQL builder methods
- **No null returns**: Throw exceptions for errors, return empty collections for missing data
- **SPI purity**: Keep database-agnostic logic in SPI modules; database-specific branching belongs only in plugin implementations

## Frequently Asked Questions

### What files must I create to add a new database plugin to Chat2DB?

You must create a class implementing `ai.chat2db.spi.IPlugin` named `<YourDatabase>Plugin`, plus implementations of `IDbMetaData`, `IDbManager` (named `<YourDatabase>DBManager`), and `ISqlBuilder`. Additionally, create the file `META-INF/services/ai.chat2db.spi.IPlugin` in your resources directory containing the fully-qualified name of your plugin class.

### Can I use `Statement` instead of `PreparedStatement` in my plugin implementation?

No. The Chat2DB SPI contract explicitly prohibits using `Statement#createStatement().execute()` for SQL containing user input. You must use `PreparedStatement` with parameterized queries to prevent SQL injection vulnerabilities (contract sections 8-71 to 8-74).

### Where should I put raw SQL strings in my Chat2DB plugin?

All raw SQL fragments, error codes, and command names must be defined as constants in the `.../constant` package within your plugin module, not hard-coded in implementation classes. Resources such as property files should reside under `src/main/resources` (contract sections 5-35 to 5-42 and section 7).

### How does Chat2DB discover and load my database plugin?

Chat2DB uses Spring's `ServiceLoader` mechanism to discover plugins at runtime. The loader reads the `META-INF/services/ai.chat2db.spi.IPlugin` file from your plugin JAR, instantiates the class listed there, and registers it with the application context. Only one `IPlugin` implementation is permitted per plugin archive.