apache/shardingsphere · error · ExplainSQLSyntaxException
Generated explain_sql is not valid for the target database.
Error message
Generated explain_sql is not valid for the target database.
What it means
executeExplain wraps execution of a generated EXPLAIN statement; when the underlying execution fails with an MCPInvalidRequestException or MCPQueryFailedException whose JDBC error category is SYNTAX, the facade rethrows it as ExplainSQLSyntaxException — meaning the EXPLAIN statement synthesized for the user's SQL is not valid for the target database. Non-syntax failures are rethrown unchanged, so this error specifically means the dialect's EXPLAIN syntax/format is the problem, not the user's data or connection.
Source
Thrown at mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPSQLExecutionFacade.java:86
return sessionExecutionCoordinator.executeWithSessionLock(executionRequest.getSessionId(), () -> {
MCPDatabaseCapability databaseCapability = getDatabaseCapability(executionRequest);
return executeInternal(executionRequest, statementAnalyzer.analyze(executionRequest.getSql(), databaseCapability), databaseCapability);
});
}
private SQLExecutionResult execute(final SQLExecutionRequest executionRequest, final ClassificationResult classificationResult, final MCPDatabaseCapability databaseCapability) {
return sessionExecutionCoordinator.executeWithSessionLock(executionRequest.getSessionId(), () -> executeInternal(executionRequest, classificationResult, databaseCapability));
}
@Override
public SQLExecutionResult executeExplain(final SQLExecutionRequest executionRequest, final String sql) {
MCPDatabaseCapability databaseCapability = getDatabaseCapability(executionRequest);
ClassificationResult classificationResult = new ExplainSQLCandidateValidator(statementAnalyzer).validate(sql, executionRequest.getSql(), databaseCapability);
try {
return execute(executionRequest, classificationResult, databaseCapability);
} catch (final MCPInvalidRequestException | MCPQueryFailedException ex) {
if (MCPJDBCErrorCategory.SYNTAX == MCPJDBCExceptionClassifier.classify(databaseCapability.getDatabaseType(), ex)) {
throw new ExplainSQLSyntaxException(executionRequest.getDatabase(), executionRequest.getSchema(), sql, executionRequest.getSql(), ex);
}
throw ex;
}
}
private MCPDatabaseCapability getDatabaseCapability(final SQLExecutionRequest executionRequest) {
Optional<MCPDatabaseCapability> databaseCapability = databaseCapabilityProvider.provide(executionRequest.getDatabase());
ShardingSpherePreconditions.checkState(databaseCapability.isPresent(), DatabaseCapabilityNotFoundException::new);
return databaseCapability.orElseThrow();
}
private SQLExecutionResult executeInternal(final SQLExecutionRequest executionRequest, final ClassificationResult classificationResult,
final MCPDatabaseCapability databaseCapability) {
ShardingSpherePreconditions.checkContains(databaseCapability.getSupportedStatementClasses(), classificationResult.getStatementClass(),
StatementClassNotSupportedException::new);
checkCrossSchemaSql(executionRequest, databaseCapability, classificationResult);
return switch (classificationResult.getStatementClass()) {
case TRANSACTION_CONTROL, SAVEPOINT -> transactionStatementExecutor.execute(View on GitHub (pinned to e952770a21)
Solutions
- Simplify the SQL being explained (remove dialect-specific options like ANALYZE or FORMAT from the original statement).
- Verify the target database version supports EXPLAIN for that statement type by running the generated EXPLAIN directly in a SQL client.
- Retry with a plain SELECT/UPDATE form of the statement to get the execution plan differently.
- If the generated SQL looks valid for your engine, report a dialect capability bug including database type, version, and original SQL.
Example fix
// before
await tools.call('database_gateway_execute_explain_query', { sql: 'EXPLAIN ANALYZE SELECT * FROM t' }); // engine rejects -> ExplainSQLSyntaxException
// after (engine without EXPLAIN ANALYZE)
await tools.call('database_gateway_execute_explain_query', { sql: 'SELECT * FROM t' }); // let the tool synthesize a supported EXPLAIN Defensive patterns
Strategy: fallback
Validate before calling
// Pre-check EXPLAIN feature usage against a dialect allowlist
const EXPLAIN_FEATURES = { PostgreSQL: ['ANALYZE', 'FORMAT', 'VERBOSE'], MySQL: ['FORMAT', 'EXTENDED'], OpenGauss: ['ANALYZE', 'FORMAT'] };
function explainSupported(sql, dialect) {
const upper = sql.toUpperCase();
const allowed = EXPLAIN_FEATURES[dialect] ?? [];
const used = (upper.match(/\bANALYZE\b|\bVERBOSE\b|\bFORMAT\s+\w+/g) ?? []).map(s => s.trim());
return used.every(f => allowed.some(a => f.startsWith(a)));
}
if (!explainSupported(sql, dialect)) sql = sql.replace(/^\s*EXPLAIN\s+[^ ]*\s*/i, 'EXPLAIN '); Try / catch
try {
return await tools.call('database_gateway_execute_explain_query', { sql });
} catch (e) {
if (e.name === 'ExplainSQLSyntaxException') {
// fall back: strip EXPLAIN options or explain the bare statement
return tools.call('database_gateway_execute_explain_query', { sql: stripExplainOptions(sql) });
}
throw e;
} Prevention
- Send the bare statement and let the tool synthesize the dialect-correct EXPLAIN.
- Check the target engine's EXPLAIN option support before embedding options.
- Confirm generated EXPLAIN works by running it in a native client when adding new dialects.
- Pin the correct database argument so the right dialect capability set is used.
When it happens
Trigger: Calling database_gateway_execute_explain_query where the validator accepted the candidate EXPLAIN form but the target database rejects it: unsupported EXPLAIN options for the dialect (e.g. ANALYZE/FORMAT on engines without them), EXPLAIN of statement types the engine cannot explain, or a dialect capability mismatch between the validator and the actual server version.
Common situations: Running against an older/newer database version than the capability set assumes; exotic statements (some DDL, stored routine bodies) that engines refuse to EXPLAIN; proxy layers that rewrite EXPLAIN into unsupported forms.
Related errors
- Query did not return a result set.
- database_gateway_execute_query only supports parser-approved
- database_gateway_execute_update does not accept read-only SQ
- Statement class is not supported.
- Cross-schema SQL is not supported for database `%s`: `%s`.
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/f76326b4c3374669.
Report an issue: GitHub.