prestodb/presto · error · IllegalArgumentException

Unsupported join criteria

Error message

Unsupported join criteria

What it means

AstBuilder.visitJoin throws this IllegalArgumentException when a JOIN clause has a joinCriteria() that is neither ON <booleanExpression> nor USING (...). The parser only recognizes those two criteria forms, so anything else (e.g. a criteria context with all children null, possible with hand-modified parse trees or grammar drift) reaches the else branch.

Source

Thrown at presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java:1651

            right = (Relation) visit(context.right);
            return new Join(getLocation(context), Join.Type.CROSS, left, right, Optional.empty());
        }

        JoinCriteria criteria;
        if (context.NATURAL() != null) {
            right = (Relation) visit(context.right);
            criteria = new NaturalJoin();
        }
        else {
            right = (Relation) visit(context.rightRelation);
            if (context.joinCriteria().ON() != null) {
                criteria = new JoinOn((Expression) visit(context.joinCriteria().booleanExpression()));
            }
            else if (context.joinCriteria().USING() != null) {
                criteria = new JoinUsing(visit(context.joinCriteria().identifier(), Identifier.class));
            }
            else {
                throw new IllegalArgumentException("Unsupported join criteria");
            }
        }

        Join.Type joinType;
        if (context.joinType().LEFT() != null) {
            joinType = Join.Type.LEFT;
        }
        else if (context.joinType().RIGHT() != null) {
            joinType = Join.Type.RIGHT;
        }
        else if (context.joinType().FULL() != null) {
            joinType = Join.Type.FULL;
        }
        else {
            joinType = Join.Type.INNER;
        }

        return new Join(getLocation(context), joinType, left, right, Optional.of(criteria));

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Rewrite the join using ON <condition> or USING (col1, col2, ...).
  2. Replace NATURAL JOIN with an explicit ON clause comparing the shared columns.
  3. If building parse trees programmatically, ensure joinCriteria() is one of the grammar's recognized forms.
  4. In a fork, extend visitJoin to handle the new criteria kind.

Example fix

// before
SELECT * FROM a NATURAL JOIN b;
// after
SELECT * FROM a JOIN b ON a.id = b.id;
Defensive patterns

Strategy: validation

Validate before calling

// ensure every JOIN in the SQL text uses ON or USING
if (Pattern.compile("(?i)\\bJOIN\\b(?!\\s+(?:ON|USING|\\())").matcher(sql).find()) {
    throw new IllegalArgumentException("JOIN must use ON or USING criteria");
}

Type guard

boolean hasJoinCriteria(String joinClauseSql) {
    return Pattern.compile("(?i)JOIN\\s+(\\S+\\s+)?(ON|USING)\\s").matcher(joinClauseSql).find();
}

Try / catch

try {
    parser.createStatement(sql);
} catch (IllegalArgumentException e) {
    if (e.getMessage().equals("Unsupported join criteria")) {
        // rewrite NATURAL/custom joins into explicit ON clauses
        sql = rewriteNaturalJoins(sql);
        parser.createStatement(sql);
    } else throw e;
}

Prevention

When it happens

Trigger: Parsing a JOIN whose criteria token was altered or removed from the parse tree, or a custom grammar change that introduces a new criteria form (e.g. NATURAL variants) without updating visitJoin.

Common situations: Forked grammars, programmatic AST construction via the parser's generated contexts, or SQL dialects using join criteria keywords Presto does not support.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/7b4251d8041de75d. Report an issue: GitHub.