apache/seatunnel · warning

Failed to close PreparedStatement during schema change

Error message

Failed to close PreparedStatement during schema change

What it means

Logged in DatabendSinkWriter.applySchemaChange() when closing the old PreparedStatement fails with a SQLException after a schema change is detected. The writer closes the old statement before rebuilding the INSERT SQL for the new schema. The close failure is only a warning — the statement reference is nulled regardless, so the schema change still proceeds (the leaked statement is reclaimed on GC).

Solutions

  1. Restore/verify the JDBC connection health; if the connection is dead the subsequent re-created statement will also fail
  2. Check the attached stack trace — usually a symptom of an already-broken connection rather than a code bug
  3. Ensure only one thread touches the writer's preparedStatement
  4. If warnings recur, upgrade the Databend JDBC driver to a version with more forgiving close semantics

Example fix

// before
try {
    preparedStatement.close();
} catch (SQLException e) {
    log.warn("Failed to close PreparedStatement during schema change", e);
}
// after
try {
    if (isStatementValid(preparedStatement)) {
        preparedStatement.close();
    }
} catch (SQLException e) {
    log.warn("Failed to close PreparedStatement during schema change", e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (preparedStatement != null && !preparedStatement.isClosed()) {
    preparedStatement.close();
}

Type guard

boolean safelyClosable(PreparedStatement ps) {
    try { return ps != null && !ps.isClosed(); } catch (SQLException e) { return false; }
}

Try / catch

try {
    writer.applySchemaChange(newCatalogTable);
} catch (SQLException e) {
    log.error("Schema change failed; old statement may not have been closed", e);
    // writer nulls the statement anyway; verify new statements work
}

Prevention

When it happens

Trigger: applySchemaChange() detects the target table schema changed, calls preparedStatement.close(), and the underlying connection is broken/closed so the driver throws SQLException.

Common situations: Connection dropped mid-run (network issue, Databend restart); driver-level invalidation of the statement; concurrent close from another thread.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/ab6f7c4ca306a882. 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:293

    @Override
    public void applySchemaChange(SchemaChangeEvent event) {
        try {
            // save the current batch
            executeBatch();

            // update the table schema
            this.tableSchema = tableSchemaChanger.reset(tableSchema).apply(event);

            // update the catalog table
            schemaChangeManager.applySchemaChange(sinkTablePath, event);

            // close the old prepared statement
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    log.warn("Failed to close PreparedStatement during schema change", e);
                } finally {
                    preparedStatement = null;
                }
            }

            // update the insert SQL statement
            this.insertSql = generateInsertSql(catalogTable, tableSchema);

            this.batchCount = 0;

            log.info(
                    "Schema change applied successfully for table {}", sinkTablePath.getFullName());
        } catch (Exception e) {
            throw new DatabendConnectorException(
                    DatabendConnectorErrorCode.SQL_OPERATION_FAILED,
                    "Failed to apply schema change: " + e.getMessage(),
                    e);
        }

View on GitHub (pinned to cf67b549a7)