{"record":{"id":"9b3cbe4b0bdacdea","repo":"apache/shardingsphere","slug":"unsupported-expression-s-in-page-expression","errorCode":null,"errorMessage":"Unsupported expression: %s in page expression","messagePattern":"Unsupported expression: (.+?) in page expression","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/pagination/rownum/ExpressionRowNumberValueSegment.java","lineNumber":58,"sourceCode":"     *\n     * @param params parameters\n     * @return value\n     */\n    public Long getValue(final List<Object> params) {\n        return getValueFromExpression(expressionSegment, params);\n    }\n    \n    private Long getValueFromExpression(final ExpressionSegment expressionSegment, final List<Object> params) {\n        if (expressionSegment instanceof ParameterMarkerExpressionSegment) {\n            return null == params || params.isEmpty() ? 0L : Long.parseLong(params.get(((ParameterMarkerExpressionSegment) expressionSegment).getParameterMarkerIndex()).toString());\n        }\n        if (expressionSegment instanceof BinaryOperationExpression) {\n            return getValueFromBinaryOperationExpression((BinaryOperationExpression) expressionSegment, params);\n        }\n        if (expressionSegment instanceof LiteralExpressionSegment) {\n            return Long.parseLong(expressionSegment.getText());\n        }\n        throw new UnsupportedOperationException(String.format(\"Unsupported expression: %s in page expression\", expressionSegment.getClass().getName()));\n    }\n    \n    private Long getValueFromBinaryOperationExpression(final BinaryOperationExpression binaryOperationExpression, final List<Object> params) {\n        String operator = binaryOperationExpression.getOperator();\n        Long leftValue = getValueFromExpression(binaryOperationExpression.getLeft(), params);\n        Long rightValue = getValueFromExpression(binaryOperationExpression.getRight(), params);\n        switch (operator) {\n            case \"+\":\n                return leftValue + rightValue;\n            case \"-\":\n                return leftValue - rightValue;\n            case \"*\":\n                return leftValue * rightValue;\n            case \"/\":\n                return leftValue / rightValue;\n            default:\n                throw new UnsupportedOperationException(String.format(\"Unsupported operator: %s in page expression\", operator));\n        }","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/pagination/rownum/ExpressionRowNumberValueSegment.java#L40-L76","documentation":"Thrown by ExpressionRowNumberValueSegment.getValueFromExpression when evaluating a row-number pagination expression at rewrite time: only ParameterMarkerExpressionSegment, BinaryOperationExpression, and LiteralExpressionSegment are evaluatable. Any other ExpressionSegment subclass triggers UnsupportedOperationException naming the segment class. This is runtime pagination-math evaluation (Oracle/rownum-style LIMIT/OFFSET folding), not initial parsing.","triggerScenarios":"A rownum-based pagination predicate whose value expression is, e.g., a function call (LEVEL, sequence, SYSDATE), a case expression, or any segment type beyond the three handled — getValueFromExpression is called during SQL rewrite to fold the numeric value and cannot resolve it.","commonSituations":"ROWNUM <= ? + 10 works (binary op), but ROWNUM <= some_func(1) or nested function expressions fail; upgrades that change how an expression is visited (reclassified segments); dialect migrations bringing non-numeric-friendly pagination expressions.","solutions":["Rewrite the pagination expression using literals, parameter markers, or +/-/*// over them","Compute the bound in application code and pass it as a single parameter marker","Avoid functions or exotic expressions inside ROWNUM/row-number pagination predicates","If the segment type is genuinely evaluatable, extend getValueFromExpression in a fork/PR"],"exampleFix":"// before\nSELECT * FROM t WHERE ROWNUM <= CEIL(10/2)\n\n// after\nSELECT * FROM t WHERE ROWNUM <= 5","handlingStrategy":"validation","validationCode":"// Fold pagination bounds in app code; only literals/markers/+,-,*,/ survive rewrite\nlong bound = pageSize + offset;\nString sql = \"SELECT * FROM (SELECT t.*, ROWNUM rn FROM t) WHERE rn <= \" + bound;","typeGuard":null,"tryCatchPattern":"try { rewriteEngine.rewrite(query); } catch (UnsupportedOperationException e) { /* reissue with folded literal bound */ }","preventionTips":["Compute pagination values app-side and bind them as parameters or literals","Never put functions or exotic expressions inside ROWNUM bounds"],"tags":["pagination","rownum","rewrite","expression","unsupported"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}