{"record":{"id":"5ea04330301569ec","repo":"Tencent/APIJSON","slug":"having-value-value-expression","errorCode":null,"errorMessage":"@having:value 的 value 中字符串 ${expression} 不合法！不允许传超过 100 个字符的函数或表达式！请用 @raw 简化传参！","messagePattern":"@having:value 的 value 中字符串 (.+?) 不合法！不允许传超过 100 个字符的函数或表达式！请用 @raw 简化传参！","errorType":"validation","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java","lineNumber":1761,"sourceCode":"\t\t//fun0(arg0,arg1,...);fun1(arg0,arg1,...)\n\t\tString havingString = parseCombineExpression(getMethod(), getQuote(), getTable()\n\t\t\t\t, getAlias(), map, getHavingCombine(), true, containRaw, true);\n\n\t\treturn (hasPrefix ? \" HAVING \" : \"\") + StringUtil.concat(havingString, joinHaving, AND);\n\t}\n\n\tprotected String gainHavingItem(String quote, String table, String alias\n\t\t\t, String key, String expression, boolean containRaw) throws Exception {\n\t\t//fun(arg0,arg1,...)\n\t\tif (containRaw) {\n\t\t\tString rawSQL = gainRawSQL(KEY_HAVING, expression);\n\t\t\tif (rawSQL != null) {\n\t\t\t\treturn rawSQL;\n\t\t\t}\n\t\t}\n\n\t\tif (expression.length() > 100) {\n\t\t\tthrow new UnsupportedOperationException(\"@having:value 的 value 中字符串 \" + expression + \" 不合法！\"\n\t\t\t\t\t+ \"不允许传超过 100 个字符的函数或表达式！请用 @raw 简化传参！\");\n\t\t}\n\n\t\tint start = expression.indexOf(\"(\");\n\t\tif (start < 0) {\n\t\t\tif (isPrepared() && PATTERN_FUNCTION.matcher(expression).matches() == false) {\n\t\t\t\tthrow new UnsupportedOperationException(\"字符串 \" + expression + \" 不合法！\"\n\t\t\t\t\t\t+ \"预编译模式下 @having:\\\"column?value;function(arg0,arg1,...)?value...\\\"\"\n\t\t\t\t\t\t+ \" 中 column?value 必须符合正则表达式 \" + PATTERN_FUNCTION + \" 且不包含连续减号 -- ！不允许空格！\");\n\t\t\t}\n\t\t\t\n\t\t\treturn parseSQLExpression(KEY_HAVING, expression, containRaw, false, null);\n\t\t}\n\n\t\tint end = expression.lastIndexOf(\")\");\n\t\tif (start >= end) {\n\t\t\tthrow new IllegalArgumentException(\"字符 \" + expression + \" 不合法！\"\n\t\t\t\t\t+ \"@having:value 中 value 里的 SQL函数必须为 function(arg0,arg1,...) 这种格式！\");","sourceCodeStart":1743,"sourceCodeEnd":1779,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java#L1743-L1779","documentation":"gainHavingItem rejects any @having expression longer than 100 characters. Long expressions are treated as a smell (attempted injection or oversized payload); the library explicitly tells you to move such SQL into @raw so it is served from the server-side RAW_MAP whitelist instead of client input.","triggerScenarios":"A HAVING clause like \"@having\": \"sum(amount)>1000 and max(created_at)>'2024-01-01' and min(level)>=2 ...\" whose total string exceeds 100 chars.","commonSituations":"Dashboards building ever-growing condition strings; concatenated dynamic filters crossing the 100-char limit only for some users; migration from hand-written SQL HAVING into @having.","solutions":["Split logic: keep the numeric comparison in @having and move complex function text into a RAW_MAP entry referenced by @raw","Shorten by using aliases defined in @column (e.g. alias 'sum' then \"@having\": \"sum>10\")","Backend: add the full expression to RAW_MAP (key -> SQL) and pass the key via @raw"],"exampleFix":"// before\n{\"@column\": \"sum(amount):s\", \"@having\": \"sum(amount)>1000 and max(created_at)>'2024-01-01' and min(level)>=2 and count(*)>5\"}\n// after\n{\"@column\": \"sum(amount):s\", \"@raw\": \"@having\", \"@having\": \"amountFilter\"}  // amountFilter -> full SQL configured in backend RAW_MAP","handlingStrategy":"validation","validationCode":"const hv = obj['@having'];\nif (typeof hv === 'string' && hv.length > 100) {\n  throw new Error('@having expression >100 chars; move it to a backend RAW_MAP entry and use @raw');\n}","typeGuard":"const havingWithinLimit = s => typeof s === 'string' && s.length <= 100;","tryCatchPattern":"try { await api.get(req); } catch (e) { if (e.message.includes('不允许传超过 100 个字符')) moveHavingToRaw(req); else throw e; }","preventionTips":["Shorten @having via @column aliases (sum(x):s then s>10)","Pre-agree long expressions as RAW_MAP tokens with the backend"],"tags":["apijson","having","raw","input-limit"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}