apache/shardingsphere · error · QueryDidNotReturnResultSetException

Query did not return a result set.

Error message

Query did not return a result set.

What it means

In MCPJdbcStatementExecutor.executeStatement, a statement classified as QUERY or EXPLAIN must return a ResultSet; if Statement.execute() reports no result set (hasResultSet == false) the executor throws QueryDidNotReturnResultSetException. It catches driver/classifier divergence — e.g. the analyzer called it a query but the target database treated the statement as an update — instead of NPE-ing on getResultSet().

Source

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

    }
    
    private void configureStatement(final Statement statement, final SQLExecutionRequest executionRequest) throws SQLException {
        if (0 < executionRequest.getMaxRows()) {
            statement.setMaxRows(resolveStatementMaxRows(executionRequest.getMaxRows()));
        }
        if (0 < executionRequest.getTimeoutMs()) {
            statement.setQueryTimeout((executionRequest.getTimeoutMs() + 999) / 1000);
        }
    }
    
    private SQLExecutionResult executeStatement(final Statement statement, final SQLExecutionRequest executionRequest,
                                                final ClassificationResult classificationResult) throws SQLException {
        boolean hasResultSet = statement.execute(classificationResult.getNormalizedSql());
        switch (classificationResult.getStatementClass()) {
            case QUERY:
            case EXPLAIN:
                if (!hasResultSet) {
                    throw new QueryDidNotReturnResultSetException();
                }
                return createResultSetResult(statement.getResultSet(), executionRequest, classificationResult);
            case DML:
                return hasResultSet
                        ? createResultSetResult(statement.getResultSet(), executionRequest, classificationResult)
                        : SQLExecutionResult.updateCount(classificationResult.getStatementClass(), classificationResult.getStatementType(), statement.getUpdateCount(),
                                executionRequest.getMaxRows(), executionRequest.getTimeoutMs(), classificationResult.getNormalizedSql());
            case DDL:
            case DCL:
                return SQLExecutionResult.statementAck(classificationResult.getStatementClass(), classificationResult.getStatementType(),
                        executionRequest.getMaxRows(), executionRequest.getTimeoutMs(), classificationResult.getNormalizedSql());
            default:
                throw new StatementClassNotSupportedException();
        }
    }
    
    private SQLExecutionResult createResultSetResult(final ResultSet resultSet, final SQLExecutionRequest executionRequest, final ClassificationResult classificationResult) throws SQLException {
        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();

View on GitHub (pinned to e952770a21)

Solutions

  1. Rewrite the statement into a form your database returns a result set for (e.g. SELECT INTO -> separate CREATE + INSERT/SELECT).
  2. For EXPLAIN variants that return no rows, use database_gateway_execute_explain_query so the facade's explain handling applies.
  3. Reproduce with a plain JDBC client to confirm the driver indeed returns no ResultSet; if it does, report a classifier bug with the exact SQL and database type.
  4. Check for driver/proxy version mismatches if the same SQL used to work.

Example fix

// before (SQL Server dialect)
await tools.call('database_gateway_execute_query', { sql: 'SELECT a, b INTO new_t FROM t' }); // no ResultSet -> error

// after
await tools.call('database_gateway_execute_update', { sql: 'CREATE TABLE new_t (a INT, b INT)', execution_mode: 'execute' });
await tools.call('database_gateway_execute_update', { sql: 'INSERT INTO new_t SELECT a, b FROM t', execution_mode: 'execute' });
Defensive patterns

Strategy: validation

Validate before calling

// Screen out statement forms known to return no result set on your dialect
function returnsResultSet(sql, dialect) {
  const upper = sql.trim().toUpperCase();
  if (dialect === 'SQLServer' && /\bINTO\b/.test(upper) && upper.startsWith('SELECT')) return false;
  return true;
}
if (!returnsResultSet(sql, dialect)) {
  return tools.call('database_gateway_execute_update', { sql, execution_mode: 'execute' });
}
return tools.call('database_gateway_execute_query', { sql });

Type guard

function isPlainResultSetQuery(sql) {
  const upper = sql.trim().toUpperCase();
  return /^SELECT\b/.test(upper) && !/\bINTO\b/.test(upper);
}

Try / catch

try {
  return await tools.call('database_gateway_execute_query', { sql });
} catch (e) {
  if (/did not return a result set/i.test(e.message)) {
    // dialect divergence: reroute to update path or rewrite statement (e.g. SELECT INTO -> CREATE+INSERT)
    return rewriteWithoutSelectInto(sql);
  }
  throw e;
}

Prevention

When it happens

Trigger: A SQL statement the analyzer classifies as QUERY/EXPLAIN but the JDBC driver executes without a result set: dialect-specific SELECT-like statements (SELECT ... INTO, some WITH ... DML on certain engines), database-specific EXPLAIN variants that return only update counts, or a driver version whose behavior for a statement differs from the parser's assumption.

Common situations: Porting SQL between dialects (e.g. SQL Server SELECT INTO, MySQL SELECT ... FOR UPDATE via odd drivers); non-standard EXPLAIN syntax; proxy/driver combinations that swallow result sets; statement text mutated by normalization before execution.

Related errors


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