pentaho/pentaho-kettle · error · KettleDatabaseException
Unable to prepare statement for SQL statement [
Error message
Unable to prepare statement for SQL statement [
What it means
In Delete.prepareDelete, the generated DELETE SQL is handed to the JDBC connection via prepareStatement. If the driver throws a SQLException, it is wrapped in a KettleDatabaseException with the offending SQL text. The SQL string is logged, so the actual bad SQL is visible in the message.
Solutions
- Read the SQL shown in the error message and validate it directly against the target database (e.g. run it with a WHERE clause manually).
- Check the Delete step's target table and connection settings; use 'Browse' to confirm the table exists on the selected connection.
- Test the database connection (Test button) and confirm the JDBC driver is on the classpath.
- Check DB user privileges to DELETE on the target table, and review the wrapped SQLException cause for the driver-level reason.
Example fix
// before <connection>ProdDB_OLD</connection> <table>CUSTMR</table> // after <connection>ProdDB</connection> <table>CUSTOMERS</table> // names verified in DB
Defensive patterns
Strategy: try-catch
Validate before calling
// Before running: verify table and connection assert connectionMeta.testConnectionSuccess(); assert database.tableExists(targetSchema, targetTable);
Try / catch
try { prepareDelete(sql); } catch (KettleDatabaseException e) {
Throwable cause = e.getCause();
log.error("SQL failed: {} cause: {}", sql, cause == null ? "none" : cause.getMessage());
} Prevention
- Test the DB connection in the step dialog before running.
- Validate generated SQL against the target DB dialect.
- Grant DELETE privileges to the runtime DB user.
- Keep JDBC drivers up to date and on the classpath.
When it happens
Trigger: prepareDelete (called from processRow) executes data.db.getConnection().prepareStatement(stripCR(sql)) and the JDBC driver rejects the statement: bad table/field names, driver connectivity loss, or dialect-incompatible generated SQL.
Common situations: Wrong database connection selected in the step; table or schema name misspelled or missing; missing driver or wrong URL; database object renamed after the transformation was built; insufficient privileges on the table.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- An error occurred executing SQL:
- Couldn't execute SQL:
- Couldn't find any rows because of an error :
- Couldn't get a result because of an error :
- Couldn't prepare statement:
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/16b51e997e4ad835.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/delete/Delete.java:210
sql += " BETWEEN ? AND ? ";
data.deleteParameterRowMeta.addValueMeta( rowMeta.searchValueMeta( meta.getKeyFields()[i].getKeyStream() ) );
data.deleteParameterRowMeta.addValueMeta( rowMeta.searchValueMeta( meta.getKeyFields()[i].getKeyStream2() ) );
} else if ( "IS NULL".equalsIgnoreCase( meta.getKeyFields()[i].getKeyCondition() )
|| "IS NOT NULL".equalsIgnoreCase( meta.getKeyFields()[i].getKeyCondition() ) ) {
sql += " " + meta.getKeyFields()[i].getKeyCondition() + " ";
} else {
sql += " " + meta.getKeyFields()[i].getKeyCondition() + " ? ";
data.deleteParameterRowMeta.addValueMeta( rowMeta.searchValueMeta( meta.getKeyFields()[i].getKeyStream() ) );
}
}
try {
if ( log.isDetailed() ) {
logDetailed( "Setting delete preparedStatement to [" + sql + "]" );
}
data.prepStatementDelete = data.db.getConnection().prepareStatement( databaseMeta.stripCR( sql ) );
} catch ( SQLException ex ) {
throw new KettleDatabaseException( "Unable to prepare statement for SQL statement [" + sql + "]", ex );
}
}
public boolean init( StepMetaInterface smi, StepDataInterface sdi ) {
meta = (DeleteMeta) smi;
data = (DeleteData) sdi;
if ( super.init( smi, sdi ) ) {
data.db.setCommitSize( meta.getCommitSize( this ) );
return true;
}
return false;
}
@Override
protected Class<?> getPKG() {
return PKG;
}View on GitHub (pinned to f3058517a1)