Package com.tnsai.tools.database
Class SqlTools
java.lang.Object
com.tnsai.tools.database.SqlTools
Function-shape SQL query tool — the LangChain-style replacement for the
legacy
SQLQueryTool that took a single JSON-string input
(see issue #188 — RFC).
Single typed @Tool method backed by JDBC. Connection details
(URL / username / password) are constructor-injected rather
than passed per-call: the LLM should not need to know — or be able to
change — which database it's pointed at. sqlQuery only takes the
query text and optional parameters.
Security invariants
- Read-only: statements must start with
SELECTorWITH, and must not contain write tokens (DELETE / INSERT / INTO / …) outside string literals. The JDBC session is then opened} inside a read-only transaction so a modifying CTE cannot commit even if a dialect accepts it.invalid @link
{@link Connection#setReadOnly(true) - PreparedStatement only: parameters are bound
positionally via
PreparedStatement.setObject(int, java.lang.Object, int); the query string itself is never concatenated with parameter values, so SQL injection through parameter placement is impossible by construction. - Row cap:
maxRowsis enforced at the JDBC driver level viaStatement.setMaxRows(int). Default is 500; configurable per-tool-instance via the explicit-max constructor or per-call via themaxRowsOverrideparameter.
Threading
DriverManager.getConnection(java.lang.String, java.util.Properties) is called fresh per query — no
connection pool is owned by this POJO. Concurrent dispatches therefore
each open and close their own JDBC connection. Use a connection-pooled
data source (HikariCP, etc.) at the application level if your workload
needs it; this tool intentionally stays small and dependency-free.
- Since:
- 0.5.7 (Phase 2 batch 5 — built-in tool migration to function shape, see #188)
-
Constructor Summary
ConstructorsConstructorDescriptionSqlTools()Default constructor — picks JDBC connection details from environment variablesSQL_JDBC_URL,SQL_JDBC_USERNAME,SQL_JDBC_PASSWORD, plusSQL_JDBC_MAX_ROWS(defaults to 500).Explicit-credentials constructor.Full constructor — takes the same arguments as the explicit-credentials constructor plus a per-instance defaultmaxRows. -
Method Summary
-
Constructor Details
-
SqlTools
public SqlTools()Default constructor — picks JDBC connection details from environment variablesSQL_JDBC_URL,SQL_JDBC_USERNAME,SQL_JDBC_PASSWORD, plusSQL_JDBC_MAX_ROWS(defaults to 500). Suitable forRole.tools()when the JDBC URL is a deployment-level config. -
SqlTools
Explicit-credentials constructor. Passnullfor username / password if the JDBC URL embeds credentials (some SQLite / H2 setups use an empty user / password pair).jdbcUrlis required — call-time validation throwsIllegalStateExceptionwhen it is blank. -
SqlTools
Full constructor — takes the same arguments as the explicit-credentials constructor plus a per-instance defaultmaxRows. Useful when the same database is read by both interactive ("show me 10 rows") and batch ("export everything") agents and the row cap differs by role.
-
-
Method Details
-
sqlQuery
@Tool(name="sql_query", description="Run a read-only SQL SELECT query against the configured JDBC database and return the rows as a structured object ({\"rowCount\": N, \"rows\": [{column: value, \u2026}]}). Only SELECT (and WITH \u2026 SELECT) statements are accepted; any DML / DDL (INSERT / UPDATE / DELETE / DROP / \u2026) is rejected before execution. Use {parameters} for positional binding of values inside the query (placeholders \"?\") \u2014 string concatenation into the query is the wrong way and is not supported.", keywords={"sql","database","select","query","jdbc"}, idempotent=true) public Map<String,Object> sqlQuery(@ToolParam(description="SQL SELECT statement; placeholders are \"?\" (positional)") String query, @ToolParam(description="Positional parameter values for the query (in order of the placeholders); use an empty array for no parameters",required=false) List<Object> parameters, @ToolParam(description="Override the default row cap for this call (1..constructor-default); 0 / negative falls back to the default",required=false,defaultValue="0") int maxRowsOverride) throws SQLException - Throws:
SQLException
-