{"record":{"id":"c1216f695aeb58c9","repo":"pentaho/pentaho-kettle","slug":"unable-to-close-prepared-statement-sel-stmt","errorCode":null,"errorMessage":"Unable to close prepared statement sel_stmt","messagePattern":"Unable to close prepared statement sel_stmt","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/database/Database.java","lineNumber":3627,"sourceCode":"      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 {\n    RowMeta meta = new RowMeta();\n\n    for ( int i = 0; i < md.getColumnCount(); i++ ) {\n      ValueMetaInterface valueMeta = getValueFromSQLType( md, i + 1, true, false );\n      meta.addValueMeta( valueMeta );\n    }\n\n    return meta;","sourceCodeStart":3609,"sourceCodeEnd":3645,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/database/Database.java#L3609-L3645","documentation":"Thrown by Database.getOneRow( String sql ) when closing the select statement held in the selStmt field fails after the row was fetched. The message identifies sel_stmt (the plain Statement used by openQuery for non-parameterized SQL) as the resource that could not be released. It wraps the driver's exception and signals a broken connection or driver-level close failure during statement cleanup.","triggerScenarios":"Calling db.getOneRow( sql ) where openQuery used the selStmt Statement, and selStmt.close() threw — e.g. connection already closed/aborted by the server, driver error on statement close, or the statement was invalidated by concurrent activity on the same Database object.","commonSituations":"Server-side timeouts or network interruptions that kill the session before cleanup; old/buggy JDBC drivers; sharing one Database instance across steps or threads so cleanup races occur; long-running jobs where the connection went stale between query and close.","solutions":["Read the wrapped cause to identify the underlying SQLException and fix the connection problem (timeouts, firewall idle disconnects, etc.)","Reconnect or recreate the Database object before further queries","Upgrade the database's JDBC driver","Give each thread/step its own Database instance to avoid racing on the shared selStmt field"],"exampleFix":"// before\nRowMetaAndData r = database.getOneRow( sql ); // throws \"Unable to close prepared statement sel_stmt\"\n// after\nRowMetaAndData r;\ntry {\n  r = database.getOneRow( sql );\n} catch ( KettleDatabaseException e ) {\n  log.logError( \"sel_stmt 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 the selStmt close path has a live session\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( \"sel_stmt\" ) ) {\n    log.logError( \"select statement cleanup failed\", e.getCause() );\n    database.disconnect();\n    database.connect();\n  } else {\n    throw e;\n  }\n}","preventionTips":["Reconnect after idle timeouts so the session survives through statement cleanup","Inspect e.getCause() for the driver-level reason the close failed","Do not share a Database object across steps/threads that could invalidate selStmt","Update JDBC drivers; stale drivers commonly throw during statement close"],"tags":["database","jdbc","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"}