apache/seatunnel · error · DatabendConnectorException
SQL_OPERATION_FAILED
SQL_OPERATION_FAILED
Error message
Failed to prepare custom statement: ${e.getMessage()} What it means
Thrown in the DatabendSinkWriter constructor when preparing the user's custom SQL insert statement fails with a SQLException. This happens in the 'custom SQL' branch where the user supplied their own insertSql instead of the auto-generated one.
Solutions
- Run the custom SQL directly in a Databend client to reproduce and fix the syntax error.
- Verify every table/column referenced in the custom SQL exists in the target database.
- Use Databend-compatible syntax; the statement is prepared with parameters (? placeholders), so parameter count must match the SeaTunnelRowType field count.
- Check executeTimeoutSec is a positive integer accepted by the JDBC driver.
Example fix
// before "insert into db.tbl values (?, ?, ?)" // 3 placeholders but schema has 4 fields // after "INSERT INTO db.tbl (id, name, ts, amount) VALUES (?, ?, ?, ?)" // matches row type
Defensive patterns
Strategy: validation
Validate before calling
// validate custom SQL before configuring the job: // run the SQL (with dummy params) in a Databend client: PREPARE stmt FROM 'INSERT ... VALUES (?, ?, ?)'; // confirm placeholder count == SeaTunnelRowType field count
Prevention
- Test custom SQL in a Databend client before putting it into config.
- Count '?' placeholders and match them to the source schema's column count.
- Use Databend-compatible SQL syntax, not MySQL/Postgres dialect.
- Keep executeTimeoutSec a positive integer.
When it happens
Trigger: connection.prepareStatement(customInsertSql) or setQueryTimeout throws: the custom SQL has a syntax error, references non-existent tables/columns, or the query timeout value is invalid (e.g. 0/negative unsupported by the driver).
Common situations: User typo in the custom SQL template; custom SQL written for another dialect (MySQL syntax in Databend); schema renamed so the custom SQL references a dropped column.
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
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/4814f212fc79177e.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-connectors-v2/connector-databend/src/main/java/org/apache/seatunnel/connectors/seatunnel/databend/sink/DatabendSinkWriter.java:143
log.info("DatabendSinkWriter constructor - catalogTable: {}", catalogTable);
log.info("DatabendSinkWriter constructor - tableSchema: {}", tableSchema);
log.info(
"DatabendSinkWriter constructor - rowType: {}", catalogTable.getSeaTunnelRowType());
log.info("DatabendSinkWriter constructor - target table path: {}", sinkTablePath);
log.info("DatabendSinkWriter constructor - CDC mode: {}", isCdcMode);
// if custom SQL is provided, use it directly
if (customSql != null && !customSql.isEmpty()) {
this.insertSql = customSql;
log.info("Using custom SQL: {}", insertSql);
try {
this.schemaChangeManager = new SchemaChangeManager(databendSinkConfig);
this.preparedStatement = connection.prepareStatement(insertSql);
this.preparedStatement.setQueryTimeout(executeTimeoutSec);
log.info("PreparedStatement created successfully with custom SQL");
} catch (SQLException e) {
throw new DatabendConnectorException(
DatabendConnectorErrorCode.SQL_OPERATION_FAILED,
"Failed to prepare custom statement: " + e.getMessage(),
e);
}
} else {
try {
if (isCdcMode) {
// In CDC mode, we don't create tables here, it's done in AggregatedCommitter
// We'll get the raw table and stream names from the committer via prepareCommit
log.info(
"CDC mode enabled, table creation will be handled by AggregatedCommitter");
} else {
// Traditional mode
initTraditionalMode(database, table);
}
} catch (SQLException e) {
throw new DatabendConnectorException(
DatabendConnectorErrorCode.SQL_OPERATION_FAILED,View on GitHub (pinned to cf67b549a7)