{"record":{"id":"5c7e7b9e3ba871e4","repo":"MyCATApache/Mycat-Server","slug":"unhandled-sql-ast-node-type-encountered","errorCode":null,"errorMessage":"Unhandled SQL AST node type encountered: ","messagePattern":"Unhandled SQL AST node type encountered: ","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/parser/druid/impl/DruidUpdateParser.java","lineNumber":116,"sourceCode":"    \t\tTableStat ts = tableMap.get(_name);\n    \t\tupdateTableCount += ts.getUpdateCount();\n    \t}\n    \treturn updateTableCount;\n    }\n    \n    /*\n    * 判断字段是否在SQL AST的节点中，比如 col 在 col = 'A' 中，这里要注意，一些子句中可能会在字段前加上表的别名，\n    * 比如 t.col = 'A'，这两种情况， 操作符(=)左边被druid解析器解析成不同的对象SQLIdentifierExpr(无表别名)和\n    * SQLPropertyExpr(有表别名)\n     */\n    private static boolean columnInExpr(SQLExpr sqlExpr, String colName) throws SQLNonTransientException {\n        String column;\n        if (sqlExpr instanceof SQLIdentifierExpr) {\n            column = StringUtil.removeBackquote(((SQLIdentifierExpr) sqlExpr).getName()).toUpperCase();\n        } else if (sqlExpr instanceof SQLPropertyExpr) {\n            column = StringUtil.removeBackquote(((SQLPropertyExpr) sqlExpr).getName()).toUpperCase();\n        } else {\n            throw new SQLNonTransientException(\"Unhandled SQL AST node type encountered: \" + sqlExpr.getClass());\n        }\n\n        return column.equals(colName.toUpperCase());\n    }\n\n    /*\n    * 当前节点是不是一个子查询\n    * IN (select...), ANY, EXISTS, ALL等关键字, IN (1,2,3...) 这种对应的是SQLInListExpr\n     */\n    private static boolean isSubQueryClause(SQLExpr sqlExpr) throws SQLNonTransientException {\n        return (sqlExpr instanceof SQLInSubQueryExpr || sqlExpr instanceof SQLAnyExpr || sqlExpr instanceof SQLAllExpr\n                || sqlExpr instanceof SQLQueryExpr || sqlExpr instanceof SQLExistsExpr);\n    }\n\n    /*\n    * 遍历where子句的AST，寻找是否有与update子句中更新分片字段相同的条件，\n    * o 如果发现有or或者xor，然后分片字段的条件在or或者xor中的，这种情况update也无法执行，比如\n    *   update mytab set ptn_col = val, col1 = val1 where col1 = val11 or ptn_col = val；","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/parser/druid/impl/DruidUpdateParser.java#L98-L134","documentation":"During sharding-column update detection, Mycat's columnInExpr only understands simple column identifiers (SQLIdentifierExpr) and qualified names (SQLPropertyExpr). Any other AST node on the left side of a comparison (function calls, casts, arithmetic expressions) is rejected with this message, which includes the unexpected Java class.","triggerScenarios":"shardColCanBeUpdated/confirmShardColumnNotUpdated encounter a WHERE or SET comparison where the column side is an expression, e.g. WHERE UPPER(id)=..., WHERE id+0=..., or a function/cast applied to the sharding column, while checking whether the sharding column is being updated.","commonSituations":"Legacy SQL using functions on the sharding key in comparisons; generated SQL from ORMs that wrap column references; type-wrapping like CONCAT(id,'')='5' in WHERE clauses.","solutions":["Rewrite the SQL so the sharding column appears as a bare column (optionally qualified) on one side of the comparison, with the value/expression on the other side","Move the function/expression to the value side: WHERE id=UPPER('abc') instead of WHERE UPPER(id)='ABC'","Remove arithmetic or casts around the sharding key in WHERE clauses"],"exampleFix":"// before\nUPDATE t SET x=1 WHERE UPPER(shard_col)='ABC';\n// after\nUPDATE t SET x=1 WHERE shard_col=UPPER('abc');","handlingStrategy":"try-catch","validationCode":"// inspect your SQL: ensure the sharding column appears bare in comparisons\nif (sql.matches(\"(?i).*WHERE\\\\s+(UPPER|LOWER|CONCAT|CAST)\\\\s*\\\\(\\\\s*\" + shardCol + \".*\")) {\n    rewriteToMoveFunctionToValueSide();\n}","typeGuard":"boolean isSimpleColumnExpr(SQLExpr e) {\n    return e instanceof SQLIdentifierExpr || e instanceof SQLPropertyExpr;\n}","tryCatchPattern":"try { confirmShardColumnNotUpdated(schema, rrs, update, tableName, joinKey, hasParent) } catch (SQLNonTransientException e) { if (e.getMessage().contains(\"Unhandled SQL AST node type\")) { /* simplify WHERE expression on shard column */ } }","preventionTips":["Never wrap the sharding column in functions or arithmetic in WHERE/SET clauses","Write shard-key comparisons as col = literal","Lint SQL for functions applied to sharding keys"],"tags":["mysql","sharding","sql-ast"],"backgroundTag":"unsupported-operation","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}