{"record":{"id":"562577be4622e20c","repo":"OtterMind/Chat2DB","slug":"unsafe-h2-column-default-from-metadata-columndef","errorCode":null,"errorMessage":"Unsafe H2 column default from metadata: {columnDefault}","messagePattern":"Unsafe H2 column default from metadata: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"chat2db-community-server/chat2db-community-plugins/chat2db-community-h2/src/main/java/ai/chat2db/plugin/h2/H2SqlGuards.java","lineNumber":125,"sourceCode":"     * silently converted into a string literal with different semantics.\n     * Returns an empty string for {@code null}.\n     */\n    public static String escapeColumnDefault(String columnDefault) {\n        if (columnDefault == null) {\n            return \"\";\n        }\n        String trimmed = columnDefault.trim();\n        if (STRING_LITERAL.matcher(trimmed).matches()\n            || NUMERIC_LITERAL.matcher(trimmed).matches()\n            || SIMPLE_CONSTANT.matcher(trimmed).matches()\n            || CURRENT_TEMPORAL.matcher(trimmed).matches()\n            || SAFE_NO_ARG_FUNCTION.matcher(trimmed).matches()\n            || TYPED_LITERAL.matcher(trimmed).matches()\n            || BINARY_LITERAL.matcher(trimmed).matches()\n            || SEQUENCE_EXPRESSION.matcher(trimmed).matches()) {\n            return trimmed;\n        }\n        throw new IllegalArgumentException(\"Unsafe H2 column default from metadata: \" + columnDefault);\n    }\n}\n","sourceCodeStart":107,"sourceCodeEnd":128,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/chat2db-community-server/chat2db-community-plugins/chat2db-community-h2/src/main/java/ai/chat2db/plugin/h2/H2SqlGuards.java#L107-L128","documentation":"Thrown by H2SqlGuards.escapeColumnDefault when a non-null JDBC metadata column default does not match any accepted literal/expression pattern (string literal, numeric literal, NULL/TRUE/FALSE, CURRENT_TEMPORAL, no-arg function, typed literal, binary literal, or NEXT VALUE FOR sequence). Null defaults return \"\"; everything else unrecognized is rejected rather than silently re-quoted into a semantically different string literal.","triggerScenarios":"Calling escapeColumnDefault(columnDefault) where columnDefault is a complex expression, function call with arguments, arithmetic, CASE/CAST, or any text outside the eight allow-listed forms.","commonSituations":"H2 metadata reporting a DEFAULT that references a user function or expression; a schema using DEFAULT CURRENT_TIMESTAMP... that doesn't match the strict pattern; metadata from a newer H2 that emits a default format the guard doesn't recognize.","solutions":["Verify the default expression is one of the allow-listed forms; if it is a function with arguments, extend the guard pattern or handle that column manually.","Leave the default null/blank to emit no DEFAULT clause.","If a legitimate H2 default is rejected, report it so the allow-list pattern can be widened rather than bypassing the guard."],"exampleFix":"// before\n// metadata default = \"NOW(0)\" works, but \"MYFUNC(1)\" fails\nH2SqlGuards.escapeColumnDefault(\"MYFUNC(1)\");\n\n// after\n// drop the unsupported default for this column, or whitelist MYFUNC\nString d = column.getDefaultValue();\nString safe = (d == null || isKnownSafeDefault(d)) ? H2SqlGuards.escapeColumnDefault(d) : null;","handlingStrategy":"validation","validationCode":"// Reuse the same allow-list checks H2SqlGuards applies internally is not exposed,\n// so validate structurally before calling escapeColumnDefault:\nstatic boolean looksLikeSafeH2Default(String d) {\n    if (d == null) return true;\n    String t = d.trim();\n    return t.isEmpty()\n        || t.matches(\"'(?:''|[^'])*'\")\n        || t.matches(\"^[+-]?(?:\\\\d+(?:\\\\.\\\\d*)?|\\\\.\\\\d+)(?:[eE][+-]?\\\\d+)?$\")\n        || t.matches(\"(?i)^(?:NULL|TRUE|FALSE)$\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ddl.append(H2SqlGuards.escapeColumnDefault(def));\n} catch (IllegalArgumentException e) {\n    // Drop the DEFAULT clause for this column and surface a warning;\n    // do NOT stringify the value into quotes (it changes semantics).\n    log.warn(\"Skipping unsafe H2 default for column: {}\", def);\n}","preventionTips":["Prefer allow-listed H2 default forms (literal, CURRENT_TIMESTAMP, NEXT VALUE FOR).","Never coerce an unknown default into a quoted string to silence the guard.","Report legitimately-rejected H2 defaults so the pattern can be widened."],"tags":["h2","sql-guard","ddl","metadata","default","validation"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}