{"record":{"id":"bad0930ff0049bf2","repo":"Tencent/APIJSON","slug":"ck-column-column0-column1-al","errorCode":null,"errorMessage":"字符 {ck} 不合法！预编译模式下 @column:\"`column0`,`column1`:alias;function0(arg0,arg1,...);function1(...):alias...\" 中所有字符串 column 都必须必须为1个单词 ！","messagePattern":"字符 (.+?) 不合法！预编译模式下 @column:\"`column0`,`column1`:alias;function0\\(arg0,arg1,\\.\\.\\.\\);function1\\(\\.\\.\\.\\):alias\\.\\.\\.\" 中所有字符串 column 都必须必须为1个单词 ！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java","lineNumber":2693,"sourceCode":"\t\t// 以\",\" 分割参数\n\t\tString quote = getQuote();\n\t\tboolean isKeyPrefix = isKeyPrefix();\n\t\tString tableAlias = quote + gainSQLAlias() + quote;\n\t\tString[] ckeys = StringUtil.split(param); // 以\",\"分割参数\n\t\tif (ckeys != null && ckeys.length > 0) {\n\n\t\t\tfor (int i = 0; i < ckeys.length; i++) {\n\t\t\t\tString ck = ckeys[i];\n\n\t\t\t\tString origin;\n\t\t\t\tString alias;\n\n\t\t\t\t// 如果参数包含 \"'\" ,解析字符串\n\t\t\t\tif (ck.startsWith(\"`\") && ck.endsWith(\"`\")) {\n\t\t\t\t\torigin = ck.substring(1, ck.length() - 1);\n\t\t\t\t\t//sql 注入判断 判断\n\t\t\t\t\tif (origin.startsWith(\"_\") || StringUtil.isName(origin) == false) {\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+ \" 中所有字符串 column 都必须必须为1个单词 ！\");\n\t\t\t\t\t}\n\n\t\t\t\t\torigin = gainKey(origin);\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\torigin = gainValue(origin).toString();\n\t\t\t\t}\n\t\t\t\telse {","sourceCodeStart":2675,"sourceCodeEnd":2711,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java#L2675-L2711","documentation":"In parseArgsSplitWithComma, an argument wrapped in backticks is unquoted and must be a single identifier that additionally must not start with '_' (underscore-prefixed columns are reserved for APIJSON's own keys like _password). Failing StringUtil.isName or starting with '_' throws this IllegalArgumentException.","triggerScenarios":"\"@column\":\"concat(`user name`,'x')\" (space inside backticks), \"@column\":\"max(`_password`)\" (leading underscore), \"@column\":\"`user.id`\" (dot). All are rejected in prepared mode.","commonSituations":"Tables with columns whose names contain spaces or hyphens; accessing APIJSON reserved underscore columns; assuming backticks allow arbitrary SQL identifiers.","solutions":["Only pass plain single-word columns in backticks, or skip backticks entirely for simple names.","For columns with special names, register an alias/mapping in the backend schema config or RAW_MAP.","Do not access underscore-prefixed reserved columns; rename the physical column if you control the schema.","Rewrite the expression to reference a view or @raw entry."],"exampleFix":"// before\n{\"User\":{\"@column\":\"max(`_password`)\"}}\n// after (assuming column renamed or mapped server-side)\n{\"User\":{\"@column\":\"max(password)\"}}","handlingStrategy":"validation","validationCode":"const NAME=/^[A-Za-z][A-Za-z0-9_]*$/;\nfor(const arg of args){ if(arg.startsWith('`')&&arg.endsWith('`')){const inner=arg.slice(1,-1); if(inner.startsWith('_')||!NAME.test(inner))throw new Error('backtick arg must be one word, not _-prefixed'); } }","typeGuard":"function isBacktickArg(a) { if (!a.startsWith('`') || !a.endsWith('`')) return true; const i = a.slice(1, -1); return !i.startsWith('_') && /^[A-Za-z][A-Za-z0-9_]*$/.test(i); }","tryCatchPattern":"catch IllegalArgumentException; map offending backtick arg to a backend raw alias and retry","preventionTips":["Only single-word columns in backticks","Never reference underscore-prefixed reserved columns","Rename odd physical columns or expose them via views"],"tags":["apijson","sql","input-validation","identifier","backtick"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}