MyCATApache/Mycat-Server · error · SQLNonTransientException

SQL AST nodes type mismatch!

Error message

SQL AST nodes type mismatch!

What it means

When a comparison clause in the UPDATE statement matches col = value where col is the sharding column, Mycat checks whether the right side equals the value being SET. It first requires both sides to be the same AST node class; if e.g. the WHERE literal is an integer and the SET value is a string (or vice versa), it throws 'SQL AST nodes type mismatch!' instead of silently allowing or denying the update.

Solutions

  1. Make the literal types consistent: use the same form of the value in the WHERE clause and the SET clause (both quoted or both unquoted)
  2. Quote consistently for string sharding keys, e.g. SET id='5' ... WHERE id='5'
  3. Avoid updating the sharding column at all; update other columns only

Example fix

// before
UPDATE t SET id=5 WHERE id='5';
// after
UPDATE t SET id='5' WHERE id='5';
Defensive patterns

Strategy: validation

Validate before calling

// keep literal types consistent between WHERE and SET for the shard key
String setVal = "'5'", whereVal = "'5'"; // both quoted for string keys
if (isNumericShardKey) { setVal = setVal.replace("'",""); whereVal = whereVal.replace("'",""); }

Type guard

boolean sameLiteralKind(SQLExpr a, SQLExpr b) {
    return a.getClass().equals(b.getClass());
}

Try / catch

try { router.route(...) } catch (SQLNonTransientException e) { if ("SQL AST nodes type mismatch!".equals(e.getMessage())) { normalizeLiteralsAndRetry(); } }

Prevention

When it happens

Trigger: confirmShardColumnNotUpdated -> shardColCanBeUpdated finds leftExpr column equals the partition column, and rightExpr.getClass() != value.getClass() — e.g. WHERE id='5' but SET id=5 (string literal vs SQLIntegerExpr), or any literal/parameter-type difference between the two sides.

Common situations: Quoting numeric sharding keys in one clause but not the other; ORM-generated SQL mixing typed and untyped literals; implicit MySQL type coercion assumptions that the Druid AST does not share.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11). Data as JSON: /api/errors/3a2069523a5a9436. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/mycat/route/parser/druid/impl/DruidUpdateParser.java:180

            * 条件中有or或者xor的,如果分片字段出现在or/xor的一个子句中,则此update
            * 语句无法执行
             */
            if ((nodeOpExpr.getOperator() == SQLBinaryOperator.BooleanOr) ||
                    (nodeOpExpr.getOperator() == SQLBinaryOperator.BooleanXor)) {
                parentHasOR = true;
            }
            // 发现类似 col = value 的子句
            if (nodeOpExpr.getOperator() == SQLBinaryOperator.Equality) {
                boolean foundCol;
                SQLExpr leftExpr = nodeOpExpr.getLeft();
                SQLExpr rightExpr = nodeOpExpr.getRight();

                foundCol = columnInExpr(leftExpr, column);

                // 发现col = value子句,col刚好是分片字段,比较value与update要更新的值是否一样,并且是否在or/xor子句中
                if (foundCol) {
                    if (rightExpr.getClass() != value.getClass()) {
                        throw new SQLNonTransientException("SQL AST nodes type mismatch!");
                    }

                    canUpdate = rightExpr.toString().equals(value.toString()) && (!hasOR) && (!parentHasOR);
                }
            } else if (nodeOpExpr.getOperator().isLogical()) {
                if (nodeOpExpr.getLeft() != null) {
                    if (nodeOpExpr.getLeft() instanceof SQLBinaryOpExpr) {
                        canUpdate = shardColCanBeUpdated(nodeOpExpr.getLeft(), column, value, parentHasOR);
                    }
                    // else
                    // 此子语句不是 =,>,<等关系运算符(对应的类是SQLBinaryOpExpr)。比如between X and Y
                    // 或者 NOT,或者单独的子查询,这些情况,我们不做处理
                }
                if ((!canUpdate) && nodeOpExpr.getRight() != null) {
                    if (nodeOpExpr.getRight() instanceof SQLBinaryOpExpr) {
                        canUpdate = shardColCanBeUpdated(nodeOpExpr.getRight(), column, value, parentHasOR);
                    }
                    // else

View on GitHub (pinned to 65f8d8beb7)