{"record":{"id":"fb71198eed972681","repo":"tursodatabase/turso","slug":"statement-is-closed-fb7119","errorCode":null,"errorMessage":"Statement is closed","messagePattern":"Statement is closed","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Statement.java","lineNumber":500,"sourceCode":"  /**\n   * Functional interface for SQL callable operations.\n   *\n   * @param <T> the return type\n   */\n  @FunctionalInterface\n  protected interface SQLCallable<T> {\n    /**\n     * Executes the SQL operation.\n     *\n     * @return the result of the operation\n     * @throws SQLException if a database access error occurs\n     */\n    T call() throws SQLException;\n  }\n\n  private void ensureOpen() throws SQLException {\n    if (closed) {\n      throw new SQLException(\"Statement is closed\");\n    }\n  }\n}\n","sourceCodeStart":482,"sourceCodeEnd":504,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Statement.java#L482-L504","documentation":"ensureOpen() is the shared guard at the top of JDBC4Statement's executeQuery, execute, getResultSet, addBatch, clearBatch and executeBatch (executeUpdate reaches it through execute). Once the `closed` flag is set it throws SQLException(\"Statement is closed\"). Statements are closed both by an explicit close() and when their connection is closed, so the original close is often not visible at the failure site.","triggerScenarios":"Reusing a statement after close(); execute/addBatch/executeBatch on a statement whose connection was closed (connection close cascades to its statements); statements stored in fields or app-level caches that outlive their lifespan; double-processing a request where the second pass hits an already-closed statement.","commonSituations":"App-level statement caching in servlets or service singletons; background jobs holding statements while a connection pool reclaims connections (idle timeout, eviction on validation failure); helper classes that hide statement creation but expose execute methods; tests that close resources early.","solutions":["Check stmt.isClosed() before use, or recreate the statement per unit of work","Create statements with try-with-resources scoped to one task; let the pool manage connections only","Keep the connection open for the statement's whole lifetime and verify conn.isValid() when a pool is involved","Catch the SQLException and treat 'Statement is closed' as a signal to rebuild the statement and retry once"],"exampleFix":"// before\nprivate final Statement stmt; // cached field\npublic List<User> users() throws SQLException {\n  return query(stmt.executeQuery(\"SELECT ...\")); // fails after first close\n}\n\n// after\npublic List<User> users() throws SQLException {\n  try (Statement stmt = conn.createStatement();\n       ResultSet rs = stmt.executeQuery(\"SELECT ...\")) {\n    return query(rs);\n  }\n}","handlingStrategy":"validation","validationCode":"if (stmt.isClosed()) {\n  stmt = conn.createStatement(); // recreate and reconfigure as needed\n}\nResultSet rs = stmt.executeQuery(sql);","typeGuard":null,"tryCatchPattern":"try {\n  return stmt.executeQuery(sql);\n} catch (SQLException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"Statement is closed\")) {\n    try (Statement fresh = conn.createStatement()) {\n      return fresh.executeQuery(sql); // rebuild and retry once\n    }\n  }\n  throw e;\n}","preventionTips":["Scope statements to one unit of work with try-with-resources; never cache them in fields","Remember connection.close() cascades to its statements — check conn.isValid() when pooling","Verify statement and connection state in long-lived background jobs before each use"],"tags":["java","jdbc","turso","statement","lifecycle","closed-resource","connection-pool"],"backgroundTag":"resource-closed","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}