{"record":{"id":"5b00659f8b623ecd","repo":"pentaho/pentaho-kettle","slug":"couldn-t-prepare-statement","errorCode":null,"errorMessage":"Couldn't prepare statement:","messagePattern":"Couldn't prepare statement:","errorType":"exception","errorClass":"KettleDatabaseException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/database/Database.java","lineNumber":1269,"sourceCode":"   * Prepare a statement to be executed on the database.\n   *\n   * @param sql        The SQL to be prepared\n   * @param returnKeys set to true if you want to return generated keys from an insert statement\n   * @return The PreparedStatement object.\n   * @throws KettleDatabaseException\n   */\n  public PreparedStatement prepareSQL( String sql, boolean returnKeys ) throws KettleDatabaseException {\n    DatabaseInterface databaseInterface = databaseMeta.getDatabaseInterface();\n    boolean supportsAutoGeneratedKeys = databaseInterface.supportsAutoGeneratedKeys();\n\n    try {\n      if ( returnKeys && supportsAutoGeneratedKeys ) {\n        return connection.prepareStatement( databaseMeta.stripCR( sql ), Statement.RETURN_GENERATED_KEYS );\n      } else {\n        return connection.prepareStatement( databaseMeta.stripCR( sql ) );\n      }\n    } catch ( SQLException ex ) {\n      throw new KettleDatabaseException( \"Couldn't prepare statement:\" + Const.CR + sql, ex );\n    }\n  }\n\n  public void closeLookup() throws KettleDatabaseException {\n    if ( pstmt != null ) {\n      closePreparedStatement( pstmt );\n      pstmt = null;\n    }\n  }\n\n  public void closePreparedStatement( PreparedStatement ps ) throws KettleDatabaseException {\n    if ( ps != null ) {\n      try {\n        ps.close();\n      } catch ( SQLException e ) {\n        throw new KettleDatabaseException( \"Error closing prepared statement\", e );\n      }\n    }","sourceCodeStart":1251,"sourceCodeEnd":1287,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/database/Database.java#L1251-L1287","documentation":"KettleDatabaseException thrown when Connection.prepareStatement(sql) fails, wrapping the SQLException and including the offending SQL in the message. Means the driver rejected the SQL at prepare time — typically syntax errors, unknown tables/columns, or a closed connection.","triggerScenarios":"Calling prepareSQL/prepareInsert/lookup paths where connection.prepareStatement() throws SQLException — invalid SQL syntax, referenced table/column does not exist, connection closed, or parameter count unsupported.","commonSituations":"Typo in table/column names, SQL built dynamically with wrong placeholders, missing schema, DB dialect differences (SQL valid in one engine, not another), or stale closed connection.","solutions":["Read the SQL printed in the message and run it manually in the DB to see the precise syntax error","Verify the table/column names and schema exist and are correctly quoted/cased","Confirm the connection is still open; reconnect if it was closed","Adapt SQL to the target database dialect"],"exampleFix":"// before\nString sql = \"INSERT INTO usr (id,name) VALUES (?, ?)\"; // table is actually 'users'\ndatabase.prepareInsert(rowMeta, schema, \"usr\");\n// after\nString sql = \"INSERT INTO users (id,name) VALUES (?, ?)\";\ndatabase.prepareInsert(rowMeta, schema, \"users\");","handlingStrategy":"try-catch","validationCode":"if ( database.getConnection() == null || database.getConnection().isClosed() ) {\n  database.connect();\n}","typeGuard":"boolean canPrepare( Database db ) throws SQLException {\n  Connection c = db.getConnection();\n  return c != null && !c.isClosed();\n}","tryCatchPattern":"try {\n  database.prepareInsert( rowMeta, schema, table );\n} catch ( KettleDatabaseException e ) {\n  log.error( \"Prepare failed for SQL: \" + e.getMessage() );\n  throw e;\n}","preventionTips":["Test generated SQL directly in the target DB","Validate table/column names and quoting per dialect","Reconnect on stale connections before preparing statements","Keep dynamic SQL building covered by unit tests against the real dialect"],"tags":["jdbc","database","sql","prepared-statement"],"backgroundTag":"sql-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"}