{"record":{"id":"bbc24da4dcc6753e","repo":"OtterMind/Chat2DB","slug":"routine-operation-databaserequired","errorCode":"routine.operation.databaseRequired","errorMessage":"routine.operation.databaseRequired","messagePattern":"routine\\.operation\\.databaseRequired","errorType":"validation","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlRoutineManager.java","lineNumber":344,"sourceCode":"        String normalized = StringUtils.trimToEmpty(routineType).toUpperCase(Locale.ROOT);\n        if (!FUNCTION.equals(normalized) && !PROCEDURE.equals(normalized)) {\n            throw new BusinessException(\"routine.operation.typeUnsupported\");\n        }\n        return normalized;\n    }\n\n    private String requireRoutineName(RoutineOperation operation) {\n        String routineName = StringUtils.trimToEmpty(operation.getRoutineName());\n        if (StringUtils.isBlank(routineName)) {\n            throw new BusinessException(\"routine.operation.nameRequired\");\n        }\n        return routineName;\n    }\n\n    private String requireDatabaseName(RoutineOperation operation) {\n        String databaseName = StringUtils.trimToEmpty(operation.getDatabaseName());\n        if (StringUtils.isBlank(databaseName)) {\n            throw new BusinessException(\"routine.operation.databaseRequired\");\n        }\n        return databaseName;\n    }\n\n    private String ensureSqlEndsWithSemicolon(String sql) {\n        String trimmed = StringUtils.trimToEmpty(sql);\n        if (StringUtils.isBlank(trimmed)) {\n            throw new BusinessException(\"routine.operation.ddlRequired\");\n        }\n        return trimmed.endsWith(\";\") ? trimmed : trimmed + \";\";\n    }\n\n    private String mysqlQualifiedName(String databaseName, String routineName) {\n        return Arrays.asList(databaseName, routineName).stream()\n                .filter(StringUtils::isNotBlank)\n                .map(this::quoteMysqlIdentifier)\n                .reduce((left, right) -> left + \".\" + right)\n                .orElseThrow(() -> new BusinessException(\"routine.operation.nameRequired\"));","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlRoutineManager.java#L326-L362","documentation":"Thrown by requireDatabaseName when operation.getDatabaseName(), after trim, is blank. The database name is required so the routine can be qualified as `database`.`routine` in DROP/CREATE/CALL statements and so parameter metadata can be scoped. Without it the SQL would be ambiguous or fail.","triggerScenarios":"Calling a routine-manager method that triggers buildMigrationPlan or queryRoutineParameters with operation.getDatabaseName() returning null, empty, or whitespace-only.","commonSituations":"The frontend submits a routine operation without the active database context; the connection's current database was not propagated into the operation; a multi-step wizard lost the database selection between steps.","solutions":["Set operation.setDatabaseName(currentDatabase) from the connection's catalog before invoking.","Validate databaseName is non-blank at the request boundary.","If the operation originates from a tree node, ensure the node carries and forwards its database.","Fall back to connection.getCatalog() when the operation omits the database, after confirming it is non-null."],"exampleFix":"// before\nroutineManager.previewInvocation(connection, operation);\n\n// after\nif (StringUtils.isBlank(operation.getDatabaseName())) {\n    String catalog = connection.getCatalog();\n    if (StringUtils.isBlank(catalog)) {\n        throw new IllegalArgumentException(\"databaseName is required\");\n    }\n    operation.setDatabaseName(catalog);\n}\nroutineManager.previewInvocation(connection, operation);","handlingStrategy":"validation","validationCode":"if (StringUtils.isBlank(operation.getDatabaseName())) {\n    String catalog = connection.getCatalog();\n    if (StringUtils.isBlank(catalog)) {\n        throw new IllegalArgumentException(\"databaseName is required\");\n    }\n    operation.setDatabaseName(catalog);\n}","typeGuard":"static boolean hasDatabaseName(RoutineOperation op) {\n    return op != null && StringUtils.isNotBlank(op.getDatabaseName());\n}","tryCatchPattern":null,"preventionTips":["Forward the active database from the connection into the operation.","Validate databaseName at the request boundary.","Fall back to connection.getCatalog() when omitted, after a null check.","Ensure multi-step wizards retain the database selection."],"tags":["mysql","routine","validation"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}