Interface DatabaseProvider
- All Superinterfaces:
Serializable
Applications implement this interface with their own database connection. The provider exposes the schema so the LLM can generate valid SQL, and executes the resulting queries.
Note: For security, the implementation should use a database account with read-only access limited to the relevant tables or views. This prevents the LLM from inadvertently modifying or deleting data.
public class MyDatabaseProvider implements DatabaseProvider {
private final DataSource readOnlyDataSource;
public MyDatabaseProvider(DataSource readOnlyDataSource) {
this.readOnlyDataSource = readOnlyDataSource;
}
@Override
public String getSchema() {
return "Tables: employees(id INT, name VARCHAR, dept VARCHAR), "
+ "departments(id INT, name VARCHAR). Dialect: PostgreSQL.";
}
@Override
public List<Map<String, Object>> executeQuery(String sql) {
try (var connection = readOnlyDataSource.getConnection();
var statement = connection.prepareStatement(sql);
var resultSet = statement.executeQuery()) {
// Convert to List<Map<String, Object>>
}
}
}
Dynamic schema retrieval: Hand-writing the schema string works for
small fixed schemas, but for larger schemas DatabaseMetaData
builds the description at runtime from a truly read-only connection and works
consistently across H2, MySQL, and PostgreSQL. Including primary and foreign
keys helps the LLM pick correct joins rather than guessing them from column
names:
@Override
public String getSchema() {
try (var connection = readOnlyDataSource.getConnection()) {
var meta = connection.getMetaData();
var catalog = connection.getCatalog();
var schemaName = connection.getSchema();
var schema = new StringBuilder();
try (var tables = meta.getTables(catalog, schemaName, "%",
new String[] { "TABLE" })) {
while (tables.next()) {
var table = tables.getString("TABLE_NAME");
// Append columns via meta.getColumns(catalog, schemaName,
// table, "%")
// Append primary keys via meta.getPrimaryKeys(catalog,
// schemaName, table)
// Append foreign keys via meta.getImportedKeys(catalog,
// schemaName, table)
}
}
return schema.toString();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
- Author:
- Vaadin Ltd
-
Method Summary
-
Method Details
-
getSchema
String getSchema()Returns a text description of the database schema available to the LLM. The description should include table names, column names with their types, and optionally the SQL dialect (e.g., PostgreSQL, MySQL). The LLM uses this information to generate valid SQL queries.See the class-level "Dynamic schema retrieval" section for a
DatabaseMetaData-based example that builds this description at runtime.- Returns:
- a text description of the database schema, never
null
-
executeQuery
Executes the given SQL query and returns the results. Each row is represented as a map from column name to column value.Implementations should ensure that only read-only queries are executed.
- Parameters:
sql- the SQL query to execute, notnull- Returns:
- the query results as a list of column-name-to-value maps, never
nullbut may be empty - Throws:
NullPointerException- if the query isnullIllegalArgumentException- if the query is invalid
-