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

  1. Simplify the SQL being explained (remove dialect-specific options like ANALYZE or FORMAT from the original statement).
  2. Verify the target database version supports EXPLAIN for that statement type by running the generated EXPLAIN directly in a SQL client.
  3. Retry with a plain SELECT/UPDATE form of the statement to get the execution plan differently.
  4. 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

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


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