{"record":{"id":"78515bf7af820710","repo":"Tencent/APIJSON","slug":"sample-value-item-value","errorCode":null,"errorMessage":"预编译模式下 @sample:value 中 ${item} 不合法! value 里面用 , 分割的每一项必须是 column 且其中 column 必须是 数字或英语字母组合！并且不要有多余的空格！","messagePattern":"预编译模式下 @sample:value 中 (.+?) 不合法! value 里面用 , 分割的每一项必须是 column 且其中 column 必须是 数字或英语字母组合！并且不要有多余的空格！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java","lineNumber":1860,"sourceCode":"\n\t\tString[] keys = StringUtil.split(sample);\n\t\tif (keys == null || keys.length <= 0) {\n\t\t\treturn StringUtil.isEmpty(joinSample, true) ? \"\" : (hasPrefix ? \" SAMPLE BY \" : \"\") + joinSample;\n\t\t}\n\n\t\tfor (int i = 0; i < keys.length; i++) {\n\t\t\tString item = keys[i];\n\n\t\t\tString origin = item;\n\n\t\t\tif (isPrepared()) { //不能通过 ? 来代替，SELECT 'id','name' 返回的就是 id:\"id\", name:\"name\"，而不是数据库里的值！\n\t\t\t\t//这里既不对origin trim，也不对 ASC/DESC ignoreCase，希望前端严格传没有任何空格的字符串过来，减少传输数据量，节约服务器性能\n\t\t\t\tif (StringUtil.isName(origin)) {}\n\t\t\t\telse if (StringUtil.isCombineOfNumOrAlpha(origin)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new IllegalArgumentException(\"预编译模式下 @sample:value 中 \" + item + \" 不合法! value 里面用 , 分割的\"\n\t\t\t\t\t\t\t+ \"每一项必须是 column 且其中 column 必须是 数字或英语字母组合！并且不要有多余的空格！\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tkeys[i] = gainKey(origin);\n\t\t}\n\n\t\treturn (hasPrefix ? \" SAMPLE BY \" : \"\") + StringUtil.concat(StringUtil.get(keys), joinSample, \", \");\n\t}\n\n\t@Override\n\tpublic String getLatest() {\n\t\treturn latest;\n\t}\n\tpublic AbstractSQLConfig<T, M, L> setLatest(String... conditions) {\n\t\treturn setLatest(StringUtil.get(conditions));\n\t}\n\t@Override","sourceCodeStart":1842,"sourceCodeEnd":1878,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java#L1842-L1878","documentation":"In prepared mode every comma-separated item of @sample:value must pass StringUtil.isName or StringUtil.isCombineOfNumOrAlpha — a column name or a digits+letters combination, with no spaces or symbols. Like other identifier-list clauses it cannot be parameter-bound, so malformed items are rejected outright.","triggerScenarios":"\"@sample\": \"user id\" (space), \"@sample\": \"id,name-1\" (hyphen), \"@sample\": \"count(*)\" — any SAMPLE BY item that is neither a name nor an alphanumeric combination.","commonSituations":"Copy-pasting SQL SAMPLE BY clauses; columns with special characters; the SAMPLE BY feature is ClickHouse-oriented so devs unfamiliar with its strict item syntax hit it first.","solutions":["Send bare identifiers: \"@sample\": \"0.1\" style numeric or plain column names only","Remove spaces and symbols from each item","For expressions, pre-configure in RAW_MAP and use @raw"],"exampleFix":"// before\n{\"@sample\": \"user id, 0.1\"}\n// after\n{\"@sample\": \"userId,0.1\"}","handlingStrategy":"validation","validationCode":"const ok = s => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s) || /^[A-Za-z0-9]+$/.test(s);\nfor (const item of String(obj['@sample'] ?? '').split(',')) {\n  if (item && !ok(item)) throw new Error(`@sample item '${item}' must be a name or digit/letter combo`);\n}","typeGuard":"const isSampleItemValid = s => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s) || /^[A-Za-z0-9.]+$/.test(s);","tryCatchPattern":"try { await api.get(req); } catch (e) { if (e.message.includes('@sample')) sanitizeListField(req, '@sample'); else throw e; }","preventionTips":["Generate @sample from column pickers and numeric inputs only","No spaces after commas in any clause list value"],"tags":["apijson","sample","prepared-statement","clickhouse"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}