apache/shardingsphere · error · MCPUnsupportedSQLStatementException

Statement is not supported by the MCP contract.

Error message

Statement is not supported by the MCP contract.

What it means

SQLStatementObjectExtractor walks parsed statements to collect referenced object names; in extractSequenceTargets for DROP SEQUENCE, each dropped name may be a String or a SimpleTableSegment, but any other AST node type triggers MCPUnsupportedSQLStatementException. It is a defensive guard ensuring every object reference in an accepted statement can be extracted for cross-schema checking — an unextractable DROP SEQUENCE form is treated as unsupported rather than silently skipping schema validation.

Source

Thrown at mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementObjectExtractor.java:194

            for (IdentifierValue each : ((DropSchemaStatement) sqlStatement).getSchemaNames()) {
                addNamespaceIdentifier(each, result);
            }
        }
    }
    
    private void extractSequenceTargets(final SQLStatement sqlStatement, final Collection<SQLStatementObjectName> result) {
        if (sqlStatement instanceof CreateSequenceStatement) {
            addName(((CreateSequenceStatement) sqlStatement).getSequenceName(), result);
        } else if (sqlStatement instanceof AlterSequenceStatement) {
            addName(((AlterSequenceStatement) sqlStatement).getSequenceName(), result);
        } else if (sqlStatement instanceof DropSequenceStatement) {
            for (Object each : ((DropSequenceStatement) sqlStatement).getSequenceNames()) {
                if (each instanceof String) {
                    addName((String) each, result);
                } else if (each instanceof SimpleTableSegment) {
                    addTable((SimpleTableSegment) each, result);
                } else {
                    throw new MCPUnsupportedSQLStatementException();
                }
            }
        }
    }
    
    private void extractMergeTables(final SQLStatement sqlStatement, final Collection<SQLStatementObjectName> result) {
        if (sqlStatement instanceof MergeStatement) {
            addTableSegment(((MergeStatement) sqlStatement).getSource(), result);
        }
    }
    
    private void extractCommonTableExpressionTables(final SQLStatement sqlStatement, final Collection<SQLStatementObjectName> result) {
        findWithSegment(sqlStatement).ifPresent(with -> {
            for (CommonTableExpressionSegment each : with.getCommonTableExpressions()) {
                TableExtractor extractor = new TableExtractor();
                extractor.extractTablesFromSelect(each.getSubquery().getSelect());
                addTableSegments(extractor.getTableContext(), result);
            }

View on GitHub (pinned to e952770a21)

Solutions

  1. Split multi-name DROP SEQUENCE statements into one sequence per statement.
  2. Use plain unqualified sequence names and select the schema via the tool's schema argument.
  3. If a single simple DROP SEQUENCE fails, capture the dialect and statement and report it as an extractor gap.

Example fix

// before
await tools.call('database_gateway_execute_update', { sql: 'DROP SEQUENCE seq_a, seq_b', execution_mode: 'execute' }); // unextractable form -> unsupported

// after
await tools.call('database_gateway_execute_update', { sql: 'DROP SEQUENCE seq_a', execution_mode: 'execute' });
await tools.call('database_gateway_execute_update', { sql: 'DROP SEQUENCE seq_b', execution_mode: 'execute' });
Defensive patterns

Strategy: validation

Validate before calling

// One sequence per DROP statement
function splitDropSequence(sql) {
  const m = sql.match(/^\s*DROP\s+SEQUENCE\s+(.+?)\s*;?\s*$/i);
  if (!m) return [sql];
  return m[1].split(',').map(name => `DROP SEQUENCE ${name.trim()}`);
}
for (const stmt of splitDropSequence(sql)) {
  await tools.call('database_gateway_execute_update', { sql: stmt, execution_mode });
}

Type guard

function isSimpleDropSequence(sql) {
  return /^\s*DROP\s+SEQUENCE\s+[A-Za-z_][\w$]*\s*;?\s*$/i.test(sql);
}

Try / catch

try {
  return await tools.call('database_gateway_execute_update', { sql, execution_mode });
} catch (e) {
  if (/not supported by the MCP contract/.test(e.message) && /^\s*DROP\s+SEQUENCE\b/i.test(sql) && sql.includes(',')) {
    for (const one of sql.split(/,(?![^()]*\))/)) await tools.call('database_gateway_execute_update', { sql: one.trim(), execution_mode });
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: A DROP SEQUENCE statement whose parsed sequence-name AST contains a node type other than String or SimpleTableSegment for the target dialect — unusual qualified names or dialect-specific name forms in DROP SEQUENCE lists.

Common situations: Multi-name DROP SEQUENCE ... a, b, c statements; dialect-specific quoted/qualified sequence identifiers; grammar/parser versions that produce a different name segment type than the extractor expects.

Related errors


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