{"record":{"id":"24da10f9b28db0dc","repo":"OtterMind/Chat2DB","slug":"invalid-sql-server-collation-name-collation","errorCode":null,"errorMessage":"Invalid SQL Server collation name: {collation}","messagePattern":"Invalid SQL Server collation name: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"chat2db-community-server/chat2db-community-plugins/chat2db-community-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerSqlGuards.java","lineNumber":49,"sourceCode":"            \"NATIONAL CHAR\",\n            \"NATIONAL CHAR VARYING\",\n            \"NATIONAL CHARACTER\",\n            \"NATIONAL CHARACTER VARYING\");\n    private static final Set<String> COLUMN_CLAUSE_KEYWORDS = Set.of(\n            \"CHECK\", \"CONSTRAINT\", \"DEFAULT\", \"ENCRYPTED\", \"IDENTITY\", \"MASKED\",\n            \"PERSISTED\", \"REFERENCES\", \"ROWGUIDCOL\", \"SPARSE\", \"UNIQUE\");\n\n    private SqlServerSqlGuards() {\n    }\n\n    /**\n     * Validates a collation name before it is embedded into generated DDL.\n     * Returns the collation unchanged when it matches the allow-list; throws\n     * otherwise (fail closed).\n     */\n    public static String validateCollation(String collation) {\n        if (collation == null || !COLLATION_NAME_PATTERN.matcher(collation).matches()) {\n            throw new IllegalArgumentException(\"Invalid SQL Server collation name: \" + collation);\n        }\n        return collation;\n    }\n\n    /**\n     * Accepts a SQL Server built-in or schema-qualified user-defined type,\n     * with an optional balanced argument list such as {@code decimal(18, 2)},\n     * {@code nvarchar(max)}, or {@code xml(CONTENT [dbo].[Collection])}.\n     */\n    public static String requireColumnTypeExpression(String columnType) {\n        if (StringUtils.isBlank(columnType)) {\n            throw invalid(\"column type\", columnType);\n        }\n        String expression = columnType.trim();\n        int argumentsStart = findArgumentsStart(expression);\n        String typeName = argumentsStart < 0 ? expression : expression.substring(0, argumentsStart).trim();\n        if (!isTypeName(typeName)) {\n            throw invalid(\"column type\", columnType);","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/chat2db-community-server/chat2db-community-plugins/chat2db-community-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerSqlGuards.java#L31-L67","documentation":"Thrown by SqlServerSqlGuards.validateCollation when the collation is null or does not fully match the allow-list [A-Za-z0-9_]+. Collation names are embedded as bare (unquoted) tokens in generated DDL, so anything outside ASCII alphanumerics/underscore is rejected to block DDL injection (fail closed).","triggerScenarios":"Passing a collation containing a space, dot, hyphen, parentheses, quote, or any non-[A-Za-z0-9_] character - e.g. 'Latin1_General_CI_AS' is valid, but 'Latin1 General' or a Windows collation with a locale suffix delimiter is not. A null collation also triggers it.","commonSituations":"User-supplied or JDBC-reported collation with unexpected punctuation; copy-paste introducing whitespace; an attempt to pass a collation ID rather than its name.","solutions":["Supply only ASCII letters, digits, and underscore (e.g. SQL_Latin1_General_CP1_CI_AS).","Pre-validate the collation against [A-Za-z0-9_]+ before setting it on the column model.","If null/empty collation is intended, omit the COLLATE clause instead of passing null."],"exampleFix":"// before\ncolumn.setCollationName(\"Latin1_General CI AS\"); // spaces\n// -> Invalid SQL Server collation name\n\n// after\ncolumn.setCollationName(\"Latin1_General_CI_AS\");","handlingStrategy":"validation","validationCode":"private static final java.util.regex.Pattern COLL = java.util.regex.Pattern.compile(\"[A-Za-z0-9_]+\");\nif (collation != null && !COLL.matcher(collation).matches()) {\n    throw new IllegalArgumentException(\"Reject collation: \" + collation);\n}","typeGuard":"static boolean isSafeSqlServerCollation(String c) {\n    return c != null && c.matches(\"[A-Za-z0-9_]+\");\n}","tryCatchPattern":null,"preventionTips":["Restrict collations to ASCII alphanumerics/underscore.","Omit the COLLATE clause for null/empty rather than forwarding null.","Validate at the boundary with the same regex."],"tags":["sqlserver","ddl","validation","security","collation"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}