Class SqlTools

java.lang.Object
com.tnsai.tools.database.SqlTools

public class SqlTools extends Object
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 SELECT or WITH, and must not contain write tokens (DELETE / INSERT / INTO / …) outside string literals. The JDBC session is then opened
    invalid @link
    {@link Connection#setReadOnly(true)
    } inside a read-only transaction so a modifying CTE cannot commit even if a dialect accepts it.
  • 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: maxRows is enforced at the JDBC driver level via Statement.setMaxRows(int). Default is 500; configurable per-tool-instance via the explicit-max constructor or per-call via the maxRowsOverride parameter.

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

    Constructors
    Constructor
    Description
    Default constructor — picks JDBC connection details from environment variables SQL_JDBC_URL, SQL_JDBC_USERNAME, SQL_JDBC_PASSWORD, plus SQL_JDBC_MAX_ROWS (defaults to 500).
    SqlTools(String jdbcUrl, String username, String password)
    Explicit-credentials constructor.
    SqlTools(String jdbcUrl, String username, String password, int defaultMaxRows)
    Full constructor — takes the same arguments as the explicit-credentials constructor plus a per-instance default maxRows.
  • Method Summary

    Modifier and Type
    Method
    Description
    sqlQuery(String query, List<Object> parameters, int maxRowsOverride)
     

    Methods inherited from class java.lang.Object

    equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • SqlTools

      public SqlTools()
      Default constructor — picks JDBC connection details from environment variables SQL_JDBC_URL, SQL_JDBC_USERNAME, SQL_JDBC_PASSWORD, plus SQL_JDBC_MAX_ROWS (defaults to 500). Suitable for Role.tools() when the JDBC URL is a deployment-level config.
    • SqlTools

      public SqlTools(String jdbcUrl, String username, String password)
      Explicit-credentials constructor. Pass null for username / password if the JDBC URL embeds credentials (some SQLite / H2 setups use an empty user / password pair). jdbcUrl is required — call-time validation throws IllegalStateException when it is blank.
    • SqlTools

      public SqlTools(String jdbcUrl, String username, String password, int defaultMaxRows)
      Full constructor — takes the same arguments as the explicit-credentials constructor plus a per-instance default maxRows. 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