{"record":{"id":"c4edf0b617a9f99d","repo":"pentaho/pentaho-kettle","slug":"unable-to-close-prepared-statement-pstmt","errorCode":null,"errorMessage":"Unable to close prepared statement pstmt","messagePattern":"Unable to close prepared statement pstmt","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/database/Database.java","lineNumber":3619,"sourceCode":"   * @param sql The SQL for the query\n   * @return one Row with data or null if nothing was found.\n   */\n  public RowMetaAndData getOneRow( String sql ) throws KettleDatabaseException {\n    ResultSet rs = openQuery( sql );\n    if ( rs != null ) {\n      Object[] row = getRow( rs ); // One row only\n\n      try {\n        rs.close();\n      } catch ( Exception e ) {\n        throw new KettleDatabaseException( \"Unable to close resultset\", e );\n      }\n\n      if ( pstmt != null ) {\n        try {\n          pstmt.close();\n        } catch ( Exception e ) {\n          throw new KettleDatabaseException( \"Unable to close prepared statement pstmt\", e );\n        }\n        pstmt = null;\n      }\n      if ( selStmt != null ) {\n        try {\n          selStmt.close();\n        } catch ( Exception e ) {\n          throw new KettleDatabaseException( \"Unable to close prepared statement sel_stmt\", e );\n        }\n        selStmt = null;\n      }\n      return new RowMetaAndData( rowMeta, row );\n    } else {\n      throw new KettleDatabaseException( \"error opening resultset for query: \" + sql );\n    }\n  }\n\n  public RowMeta getMetaFromRow( Object[] row, ResultSetMetaData md ) throws SQLException, KettleDatabaseException {","sourceCodeStart":3601,"sourceCodeEnd":3637,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/database/Database.java#L3601-L3637","documentation":"Thrown by Database.getOneRow( String sql ) after successfully fetching a row, when closing the shared prepared statement member pstmt fails. Kettle wraps the driver's exception in a KettleDatabaseException with this message. Like the resultset-close failure, it indicates the JDBC connection or driver is in a bad state, and it happens after the data was read — so it is a resource-release failure, not a query failure.","triggerScenarios":"Calling db.getOneRow( sql ) where the underlying query used a PreparedStatement stored in the pstmt field (openQuery with parameters), and pstmt.close() threw — typically because the connection was already closed, aborted, or the driver rejected the close call.","commonSituations":"Connection killed by the server between fetch and cleanup (idle timeouts, failover); shared Database instance whose pstmt was closed/nulled by another code path mid-flight; driver bugs with prepared-statement deallocation; running inside a transaction that was rolled back by another thread.","solutions":["Inspect the exception cause for the underlying SQLException and address the connection state issue","Reconnect the Database (disconnect/connect) before further use; consider closing and recreating the Database object entirely","Upgrade the JDBC driver if close() spuriously throws","Do not share the Database instance across threads or interleave other operations that would close pstmt while getOneRow runs"],"exampleFix":"// before\nRowMetaAndData r = database.getOneRow( sql ); // throws \"Unable to close prepared statement pstmt\"\n// after\nRowMetaAndData r;\ntry {\n  r = database.getOneRow( sql );\n} catch ( KettleDatabaseException e ) {\n  if ( e.getCause() != null ) log.logError( \"pstmt close failed\", e.getCause() );\n  database.disconnect();\n  database.connect();\n  r = database.getOneRow( sql );\n}","handlingStrategy":"try-catch","validationCode":"if ( database.getConnection() == null ) {\n  database.connect(); // ensure a live connection so pstmt close will succeed\n}","typeGuard":"boolean hasLiveConnection( Database db ) {\n  try {\n    return db != null && db.getConnection() != null && !db.getConnection().isClosed();\n  } catch ( SQLException e ) {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  RowMetaAndData row = database.getOneRow( sql );\n} catch ( KettleDatabaseException e ) {\n  if ( e.getMessage() != null && e.getMessage().contains( \"pstmt\" ) ) {\n    log.logError( \"prepared statement cleanup failed\", e.getCause() );\n    database.disconnect();\n    database.connect();\n  } else {\n    throw e;\n  }\n}","preventionTips":["Check connection health (connection.isClosed()) before running getOneRow","Never interleave getOneRow with code that closes or replaces the shared pstmt on the same Database object","Avoid thread-sharing Database instances; each thread gets its own","Keep the JDBC driver current to avoid spurious close() failures"],"tags":["database","jdbc","prepared-statement","resource-cleanup"],"backgroundTag":"database-query-failed","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}