apache/shardingsphere · error · SelectMultipleDataSourcesWithCombineException
36
36
Error message
SELECT ... %s can not support route to multiple data sources.
What it means
SelectMultipleDataSourcesWithCombineException is thrown by ShardingSelectRouteContextChecker when a SELECT containing a combine operator (UNION / UNION ALL / INTERSECT / EXCEPT / MINUS) routes to more than one data source. Combining result sets requires a single merge point; ShardingSphere can merge combine results only when every branch is served by the same data source, checked here by comparing each route unit's data source logic name against the first unit's.
Source
Thrown at features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/route/engine/checker/dml/ShardingSelectRouteContextChecker.java:39
import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
import org.apache.shardingsphere.infra.route.context.RouteContext;
import org.apache.shardingsphere.infra.route.context.RouteUnit;
import org.apache.shardingsphere.infra.session.query.QueryContext;
import org.apache.shardingsphere.sharding.exception.syntax.SelectMultipleDataSourcesWithCombineException;
import org.apache.shardingsphere.sharding.route.engine.checker.ShardingRouteContextChecker;
import org.apache.shardingsphere.sharding.rule.ShardingRule;
import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
/**
* Sharding select route context checker.
*/
public final class ShardingSelectRouteContextChecker implements ShardingRouteContextChecker {
@Override
public void check(final ShardingRule shardingRule, final QueryContext queryContext, final ShardingSphereDatabase database, final ConfigurationProperties props, final RouteContext routeContext) {
SelectStatement selectStatement = (SelectStatement) queryContext.getSqlStatementContext().getSqlStatement();
if (selectStatement.getCombine().isPresent() && !isRouteToSingleDataSource(routeContext)) {
throw new SelectMultipleDataSourcesWithCombineException(selectStatement.getCombine().get().getCombineType().name());
}
}
private boolean isRouteToSingleDataSource(final RouteContext routeContext) {
if (routeContext.getRouteUnits().isEmpty()) {
return true;
}
boolean result = true;
String sampleDataSourceName = routeContext.getRouteUnits().iterator().next().getDataSourceMapper().getLogicName();
for (RouteUnit each : routeContext.getRouteUnits()) {
if (!each.getDataSourceMapper().getLogicName().equals(sampleDataSourceName)) {
result = false;
break;
}
}
return result;
}
}View on GitHub (pinned to e952770a21)
Solutions
- Add predicates so every branch routes to the same data source (e.g. filter each branch on the same sharding-key range).
- Move the involved tables into the same data source, or replicate the small/static table into every data source so all branches resolve locally.
- Execute each branch separately and combine in the application instead of in SQL.
Example fix
-- before: branches may land on different data sources SELECT id FROM t_order WHERE cust_id=?) UNION ALL SELECT id FROM t_refund WHERE cust_id=?; -- after: guarantee single data source per execution, or merge client-side -- (run two statements and union in application code)
Defensive patterns
Strategy: validation
Validate before calling
// Before executing a combined SELECT, verify all branches target one data source
String sql = "SELECT id FROM t_order WHERE cust_id=? UNION ALL SELECT id FROM t_refund WHERE cust_id=?";
boolean hasCombine = sql.toUpperCase(Locale.ROOT).matches(".*\\bUNION(\\s+ALL)?\\b.*|.*\\bINTERSECT\\b.*|.*\\bEXCEPT\\b.*");
if (hasCombine) {
// execute each branch separately with EXPLAIN and confirm identical data source in plans, else merge in app
} Try / catch
try {
rs = stmt.executeQuery(sql);
} catch (final SelectMultipleDataSourcesWithCombineException ex) {
// split into per-branch queries and merge results client-side
} Prevention
- Prefer merging UNION branches in application code for sharded schemas.
- Ensure tables combined in one query share data sources (or are broadcast tables).
When it happens
Trigger: SELECT ... UNION/INTERSECT/EXCEPT ... where the combined branches' routing touches two or more distinct data source logic names (isRouteToSingleDataSource returns false because some unit's DataSourceMapper logic name differs from the sample).
Common situations: UNION ALL over two sharded tables sharded by different keys landing on different data sources; a UNION of a sharded table with a single (broadcast/default) table stored in another data source; UNION queries that worked on one data source breaking after adding shards.
Related errors
- Sharding algorithm class '%s' should be implement '%s'.
- Could not load class: %s
- Invalid %s, datetime pattern should be '%s', value is '%s'.
- Invalid %s, datetime pattern should be '%s', value is '%s'.
- 40
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/03c075d8ffe379ed.
Report an issue: GitHub.