OtterMind/Chat2DB · error · BusinessException
routine.operation.ddlRequired
routine.operation.ddlRequired
Error message
routine.operation.ddlRequired
What it means
Thrown by ensureSqlEndsWithSemicolon when operation.getDdl(), after trim, is blank. During migration the new routine body (CREATE statement) is mandatory: the manager executes DROP then the provided CREATE, so an empty CREATE would leave no routine behind. The guard rejects this before building the migration plan.
Source
Thrown at chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlRoutineManager.java:352
String routineName = StringUtils.trimToEmpty(operation.getRoutineName());
if (StringUtils.isBlank(routineName)) {
throw new BusinessException("routine.operation.nameRequired");
}
return routineName;
}
private String requireDatabaseName(RoutineOperation operation) {
String databaseName = StringUtils.trimToEmpty(operation.getDatabaseName());
if (StringUtils.isBlank(databaseName)) {
throw new BusinessException("routine.operation.databaseRequired");
}
return databaseName;
}
private String ensureSqlEndsWithSemicolon(String sql) {
String trimmed = StringUtils.trimToEmpty(sql);
if (StringUtils.isBlank(trimmed)) {
throw new BusinessException("routine.operation.ddlRequired");
}
return trimmed.endsWith(";") ? trimmed : trimmed + ";";
}
private String mysqlQualifiedName(String databaseName, String routineName) {
return Arrays.asList(databaseName, routineName).stream()
.filter(StringUtils::isNotBlank)
.map(this::quoteMysqlIdentifier)
.reduce((left, right) -> left + "." + right)
.orElseThrow(() -> new BusinessException("routine.operation.nameRequired"));
}
private String quoteMysqlIdentifier(String name) {
return MysqlIdentifierProcessor.INSTANCE.quoteIdentifierAlways(name);
}
private String routineInvocationName(String name) {
String trimmed = StringUtils.trimToEmpty(name);View on GitHub (pinned to 5ee1e990e7)
Solutions
- Ensure operation.setDdl(createStatement) carries a non-empty CREATE FUNCTION/PROCEDURE body.
- Validate the DDL is non-blank and starts with CREATE at the request boundary.
- If migrating from an existing routine, capture the DDL via SHOW CREATE before submitting.
- Reject empty DDL in the editor with an inline validation message before submit.
Example fix
// before
operation.setDdl("");
routineManager.executeMigration(connection, operation);
// after
if (StringUtils.isBlank(operation.getDdl())) {
throw new IllegalArgumentException("DDL body is required for migration");
}
operation.setDdl(operation.getDdl());
routineManager.executeMigration(connection, operation); Defensive patterns
Strategy: validation
Validate before calling
if (StringUtils.isBlank(operation.getDdl())) {
throw new IllegalArgumentException("DDL body is required for migration");
} Type guard
static boolean hasDdl(RoutineOperation op) {
return op != null && StringUtils.isNotBlank(op.getDdl());
} Prevention
- Require a non-empty CREATE body in the migration editor before submit.
- Capture the DDL via SHOW CREATE when migrating an existing routine.
- Validate the DDL starts with CREATE at the boundary.
- Reject empty DDL with an inline message rather than reaching the manager.
When it happens
Trigger: Calling previewMigration/executeMigration (via buildMigrationPlan → ensureSqlEndsWithSemicolon) with operation.getDdl() returning null, empty, or whitespace-only.
Common situations: A migration submitted from a UI where the DDL editor was left empty; a programmatic caller that builds the operation but forgets to attach the CREATE body; a paste/parse step that dropped the DDL content.
Related errors
- Existing routine definition is empty
- Existing routine definition does not contain routine name
- routine.operation.typeUnsupported
- routine.operation.nameRequired
- routine.operation.databaseRequired
AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14).
Data as JSON: /api/errors/de21bfc41a3b4d27.
Report an issue: GitHub.