{"record":{"id":"7e6728835085d118","repo":"Tencent/APIJSON","slug":"origin-column-column0-column1-al","errorCode":null,"errorMessage":"字符 {origin} 不合法！预编译模式下 @column:\"column0,column1:alias;function0(arg0,arg1,...);function1(...):alias...\" 中所有 arg 都必须是1个不以 _ 开头的单词 或者符合正则表达式 {PATTERN_FUNCTION} 且不包含连续减号 -- ！DISTINCT 必须全大写，且后面必须有且只有 1 个空格！其它情况不允许空格！","messagePattern":"字符 (.+?) 不合法！预编译模式下 @column:\"column0,column1:alias;function0\\(arg0,arg1,\\.\\.\\.\\);function1\\(\\.\\.\\.\\):alias\\.\\.\\.\" 中所有 arg 都必须是1个不以 _ 开头的单词 或者符合正则表达式 (.+?) 且不包含连续减号 -- ！DISTINCT 必须全大写，且后面必须有且只有 1 个空格！其它情况不允许空格！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java","lineNumber":2856,"sourceCode":"\n\t\t\t\t\tmkes[j] = gainKey(origin);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (ck.startsWith(\"'\") && ck.endsWith(\"'\")) {\n\t\t\t\t\torigin = ck.substring(1, ck.length() - 1);\n\t\t\t\t\tif (origin.contains(\"'\")) {\n\t\t\t\t\t\tthrow new IllegalArgumentException(\"字符串 \" + ck + \" 不合法！\"\n\t\t\t\t\t\t\t\t+ \"预编译模式下 @column:\\\"column0,column1:alias;function0(arg0,arg1,...);function1(...):alias...\\\"\"\n\t\t\t\t\t\t\t\t+ \" 中字符串参数不合法，必须以 ' 开头, ' 结尾,字符串中不能包含 ' \");\n\t\t\t\t\t}\n\n\t\t\t\t\t// 1.字符串不是字段也没有别名,所以不解析别名 2. 是字符串，进行预编译，使用getValue() ,对字符串进行截取\n\t\t\t\t\tmkes[j] = gainValue(origin).toString();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (ck.contains(\"`\") || ck.contains(\"'\") || origin.startsWith(\"_\") || origin.contains(\"--\")) {\n\t\t\t\t\t// || PATTERN_FUNCTION.matcher(origin).matches() == false) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"字符 \" + origin + \" 不合法！\"\n\t\t\t\t\t\t\t+ \"预编译模式下 @column:\\\"column0,column1:alias;function0(arg0,arg1,...);function1(...):alias...\\\"\"\n\t\t\t\t\t\t\t+ \" 中所有 arg 都必须是1个不以 _ 开头的单词 或者符合正则表达式 \" + PATTERN_FUNCTION\n\t\t\t\t\t\t\t+ \" 且不包含连续减号 -- ！DISTINCT 必须全大写，且后面必须有且只有 1 个空格！其它情况不允许空格！\");\n\t\t\t\t}\n\n\t\t\t\tif (StringUtil.isNumber(origin)) {\n\t\t\t\t\t//do nothing\n\t\t\t\t} else {\n\t\t\t\t\tString[] keys = origin.split(\"[.]\");\n\t\t\t\t\tStringBuilder sb = new StringBuilder();\n\n\t\t\t\t\tint len = keys == null ? 0 : keys.length;\n\t\t\t\t\tif (len > 0) {\n\t\t\t\t\t\tboolean first = true;\n\t\t\t\t\t\tfor (String k : keys) {\n\t\t\t\t\t\t\tif (StringUtil.isName(k) == false) {\n\t\t\t\t\t\t\t\tsb = null;\n\t\t\t\t\t\t\t\tbreak;","sourceCodeStart":2838,"sourceCodeEnd":2874,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java#L2838-L2874","documentation":"Second-pass catch-all validation of @column tokens: if a token (after any splitting) contains a backtick or single quote anywhere, or its origin starts with '_', or contains '--', it is rejected in prepared mode. This complements errors 141/142 by catching mixed cases — e.g. a quote in the middle of a token rather than at both ends — using the same anti-injection rules (identifier word or PATTERN_FUNCTION shape, no SQL comment).","triggerScenarios":"@column items like \"a`b\", \"tag='x'\", \"_id\", \"price--discount\" or function args mixing quotes with identifiers, e.g. \"concat(name,'x\")\" where quotes are unbalanced so the 141/142 branches don't fire and control falls to this else-if at AbstractSQLConfig.java:2856.","commonSituations":"Unbalanced quoting when dynamically concatenating @column strings; copying SQL expressions that embed quotes; legacy '_'-prefixed columns; subtraction typos with double minus. Note the check mixes ck (raw token) and origin (alias-stripped), so an alias starting with '_' can also trip it.","solutions":["Fix quoting so each quoted token is fully wrapped (then 141/142 rules apply cleanly) or remove quotes entirely.","Remove '--' sequences and '_' prefixes as in error 140.","Strip a bad alias: the offending part may be the ':alias' half — make alias a plain word not starting with '_'.","Add a client-side pre-check that rejects tokens containing ` or ' mid-token (see validation code)."],"exampleFix":"// before\n{\"@column\":\"concat(name,'x) AS c, _id\"}\n// after\n{\"@column\":\"concat(name,'x'):c, id\"}","handlingStrategy":"validation","validationCode":"boolean ok = Arrays.stream(atColumn.split(\",\")).allMatch(t -> {\n    String origin = t.contains(\":\") ? t.substring(0, t.indexOf(':')) : t;\n    return !t.contains(\"`\") && !t.contains(\"'\")\n        && !origin.startsWith(\"_\") && !origin.contains(\"--\");\n});","typeGuard":"function safeToken(t: string): boolean {\n  const origin = t.includes(':') ? t.slice(0, t.indexOf(':')) : t;\n  return !t.includes('`') && !t.includes(\"'\") && !origin.startsWith('_') && !origin.includes('--');\n}","tryCatchPattern":"catch (IllegalArgumentException e) { log.warn(\"@column rejected: {}\", atColumn); /* fall back to safe column list */ }","preventionTips":["Fully wrap or fully remove quotes — never mix.","Remember the alias half also gets checked; keep aliases plain words.","Run the same token lint client-side before each request."],"tags":["apijson","sql-injection","column","escaping","validation"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}