apache/shardingsphere · error · MCPMultipleSQLStatementsException

Only one SQL statement is allowed.

Error message

Only one SQL statement is allowed.

What it means

Thrown by SQLStatementScanner.findStatementEndIndex as MCPMultipleSQLStatementsException when a `;` token is followed by any further token. The MCP execute tool intentionally accepts exactly one statement per call; a trailing semicolon is fine only if nothing (except lexer noise already filtered) comes after it.

Source

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

                continue;
            }
            if (startsWithExecutableCommentMarker(text.substring(currentIndex))) {
                return true;
            }
            int commentEndIndex = text.indexOf("*/", currentIndex + 2);
            currentIndex = -1 == commentEndIndex ? text.length() : commentEndIndex + 2;
        }
        return false;
    }
    
    private int findStatementEndIndex(final List<Token> tokens, final int sqlLength) {
        for (int index = 0; index < tokens.size(); index++) {
            Token each = tokens.get(index);
            if (!";".equals(each.getText())) {
                continue;
            }
            if (index + 1 < tokens.size()) {
                throw new MCPMultipleSQLStatementsException();
            }
            return each.getStartIndex();
        }
        return sqlLength;
    }
    
    private List<Token> getTokensBefore(final List<Token> tokens, final int stopIndex) {
        List<Token> result = new ArrayList<>();
        for (Token each : tokens) {
            if (each.getStartIndex() < stopIndex) {
                result.add(each);
            }
        }
        return result;
    }
    
    private List<Token> getVisibleTokens(final String sql, final List<Token> tokens, final boolean lineCommentsHandledByLexer) {
        List<Token> result = new ArrayList<>();

View on GitHub (pinned to e952770a21)

Solutions

  1. Split the batch on statement boundaries and submit each statement as its own execute_sql call
  2. Strip trailing semicolons and anything after them (including trailing comments) before submission
  3. Use a purpose-built batch/import path if you truly need multi-statement execution

Example fix

// before
execute_sql("UPDATE t SET a=1; UPDATE t SET b=2;")

// after
execute_sql("UPDATE t SET a=1")
execute_sql("UPDATE t SET b=2")
Defensive patterns

Strategy: validation

Validate before calling

// Exactly one statement: only one ';', and it must be last
String trimmed = sql.strip();
long semicolons = trimmed.chars().filter(c -> c == ';').count();
boolean trailingOnly = trimmed.endsWith(";") && trimmed.indexOf(';') == trimmed.length() - 1;
if (semicolons > 1 || (semicolons == 1 && !trailingOnly)) throw new IllegalArgumentException("Split into single statements");
if (trailingOnly) sql = trimmed.substring(0, trimmed.length() - 1);

Try / catch

try {
    executeSql(sql);
} catch (MCPMultipleSQLStatementsException e) {
    for (String each : splitStatements(sql)) executeSql(each);
}

Prevention

When it happens

Trigger: Any submitted SQL containing a `;` with subsequent tokens — e.g. `SELECT 1; SELECT 2`, `INSERT ...; COMMIT;`, or `SELECT 1; ` followed by a comment token that was not filtered. The loop throws at the first `;` that is not the last visible token.

Common situations: Batch scripts and migration files replayed whole into execute_sql; agents concatenating tool outputs with semicolons; clients that always append `;` plus a trailing comment.

Related errors


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