apache/shardingsphere · error · UnsupportedSQLOperationException

unsupported SQL statement %s in sql federation

Error message

unsupported SQL statement %s in sql federation

What it means

SingleSQLFederationDecider.decide only knows how to decide federation for SelectStatementContext (and ExplainStatementContext by recursing into the wrapped statement). Any other SQLStatementContext type falls through to UnsupportedSQLOperationException naming the statement class. This indicates federation decision logic invoked for a statement kind the single-rule decider never handles.

Source

Thrown at kernel/single/core/src/main/java/org/apache/shardingsphere/single/decider/SingleSQLFederationDecider.java:54

import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/**
 * Single SQL federation decider.
 */
public final class SingleSQLFederationDecider implements SQLFederationDecider<SingleRule> {
    
    @Override
    public boolean decide(final SQLStatementContext sqlStatementContext, final List<Object> parameters, final RuleMetaData globalRuleMetaData,
                          final ShardingSphereDatabase database, final SingleRule rule, final Collection<DataNode> includedDataNodes) {
        if (sqlStatementContext instanceof SelectStatementContext) {
            return decide0(sqlStatementContext, database, rule, includedDataNodes);
        } else if (sqlStatementContext instanceof ExplainStatementContext) {
            ExplainStatementContext explainStatementContext = (ExplainStatementContext) sqlStatementContext;
            return decide(explainStatementContext.getExplainableSQLStatementContext(), parameters, globalRuleMetaData, database, rule, includedDataNodes);
        }
        throw new UnsupportedSQLOperationException(String.format("unsupported SQL statement %s in sql federation", sqlStatementContext.getSqlStatement().getClass().getSimpleName()));
    }
    
    private boolean decide0(final SQLStatementContext sqlStatementContext, final ShardingSphereDatabase database, final SingleRule rule, final Collection<DataNode> includedDataNodes) {
        Collection<QualifiedTable> singleTables = getSingleTables(sqlStatementContext, database, rule);
        if (singleTables.isEmpty()) {
            return false;
        }
        if (containsView(database, singleTables)) {
            return true;
        }
        if (!includedDataNodes.isEmpty() && !isInnerCommaJoin(sqlStatementContext.getSqlStatement())) {
            return true;
        }
        boolean result = rule.isAllTablesInSameComputeNode(includedDataNodes, singleTables, database);
        includedDataNodes.addAll(getTableDataNodes(rule, singleTables, database));
        return !result;
    }
    

View on GitHub (pinned to e952770a21)

Solutions

  1. Only invoke the decider for SELECT (or EXPLAIN SELECT) statement contexts; gate callers on sqlStatementContext instanceof SelectStatementContext first.
  2. Update ShardingSphere to a version whose decider handles the statement type you are feeding it.
  3. If hit inside the proxy during normal traffic, capture the SQL and report it — federation should not attempt non-query statements.

Example fix

// before
decider.decide(sqlStatementContext, parameters, globalRuleMetaData, database, rule, includedDataNodes);
// after
if (sqlStatementContext instanceof SelectStatementContext || sqlStatementContext instanceof ExplainStatementContext) {
    decider.decide(sqlStatementContext, parameters, globalRuleMetaData, database, rule, includedDataNodes);
}
Defensive patterns

Strategy: type-guard

Type guard

static boolean isFederationDecidable(SQLStatementContext ctx) {
    return ctx instanceof SelectStatementContext || ctx instanceof ExplainStatementContext;
}

Try / catch

try {
    federated = decider.decide(ctx, params, ruleMetaData, database, rule, dataNodes);
} catch (final UnsupportedSQLOperationException ex) {
    federated = false; // fall back to normal routing for non-query contexts
}

Prevention

When it happens

Trigger: The federation engine asks the decider about a non-SELECT statement context (INSERT/UPDATE/DELETE/DDL contexts), which should normally be filtered before federation. Reaching this throw means a caller invoked decide() directly or a new statement type was routed into federation decision without a guard.

Common situations: Custom code calling SQLFederationDecider.decide for arbitrary statements; version skew where a new statement context type reaches the decider; misconfigured sql-federation=true interacting with statement types not intended for federation.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/f8336325dd44500a. Report an issue: GitHub.