{"record":{"id":"691fe2f6b26004d2","repo":"apache/shardingsphere","slug":"query-did-not-return-a-result-set","errorCode":null,"errorMessage":"Query did not return a result set.","messagePattern":"Query did not return a result set\\.","errorType":"exception","errorClass":"QueryDidNotReturnResultSetException","httpStatus":null,"severity":"error","filePath":"mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPJdbcStatementExecutor.java","lineNumber":238,"sourceCode":"    }\n    \n    private void configureStatement(final Statement statement, final SQLExecutionRequest executionRequest) throws SQLException {\n        if (0 < executionRequest.getMaxRows()) {\n            statement.setMaxRows(resolveStatementMaxRows(executionRequest.getMaxRows()));\n        }\n        if (0 < executionRequest.getTimeoutMs()) {\n            statement.setQueryTimeout((executionRequest.getTimeoutMs() + 999) / 1000);\n        }\n    }\n    \n    private SQLExecutionResult executeStatement(final Statement statement, final SQLExecutionRequest executionRequest,\n                                                final ClassificationResult classificationResult) throws SQLException {\n        boolean hasResultSet = statement.execute(classificationResult.getNormalizedSql());\n        switch (classificationResult.getStatementClass()) {\n            case QUERY:\n            case EXPLAIN:\n                if (!hasResultSet) {\n                    throw new QueryDidNotReturnResultSetException();\n                }\n                return createResultSetResult(statement.getResultSet(), executionRequest, classificationResult);\n            case DML:\n                return hasResultSet\n                        ? createResultSetResult(statement.getResultSet(), executionRequest, classificationResult)\n                        : SQLExecutionResult.updateCount(classificationResult.getStatementClass(), classificationResult.getStatementType(), statement.getUpdateCount(),\n                                executionRequest.getMaxRows(), executionRequest.getTimeoutMs(), classificationResult.getNormalizedSql());\n            case DDL:\n            case DCL:\n                return SQLExecutionResult.statementAck(classificationResult.getStatementClass(), classificationResult.getStatementType(),\n                        executionRequest.getMaxRows(), executionRequest.getTimeoutMs(), classificationResult.getNormalizedSql());\n            default:\n                throw new StatementClassNotSupportedException();\n        }\n    }\n    \n    private SQLExecutionResult createResultSetResult(final ResultSet resultSet, final SQLExecutionRequest executionRequest, final ClassificationResult classificationResult) throws SQLException {\n        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPJdbcStatementExecutor.java#L220-L256","documentation":"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().","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rewrite the statement into a form your database returns a result set for (e.g. SELECT INTO -> separate CREATE + INSERT/SELECT).","For EXPLAIN variants that return no rows, use database_gateway_execute_explain_query so the facade's explain handling applies.","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.","Check for driver/proxy version mismatches if the same SQL used to work."],"exampleFix":"// before (SQL Server dialect)\nawait tools.call('database_gateway_execute_query', { sql: 'SELECT a, b INTO new_t FROM t' }); // no ResultSet -> error\n\n// after\nawait tools.call('database_gateway_execute_update', { sql: 'CREATE TABLE new_t (a INT, b INT)', execution_mode: 'execute' });\nawait tools.call('database_gateway_execute_update', { sql: 'INSERT INTO new_t SELECT a, b FROM t', execution_mode: 'execute' });","handlingStrategy":"validation","validationCode":"// Screen out statement forms known to return no result set on your dialect\nfunction returnsResultSet(sql, dialect) {\n  const upper = sql.trim().toUpperCase();\n  if (dialect === 'SQLServer' && /\\bINTO\\b/.test(upper) && upper.startsWith('SELECT')) return false;\n  return true;\n}\nif (!returnsResultSet(sql, dialect)) {\n  return tools.call('database_gateway_execute_update', { sql, execution_mode: 'execute' });\n}\nreturn tools.call('database_gateway_execute_query', { sql });","typeGuard":"function isPlainResultSetQuery(sql) {\n  const upper = sql.trim().toUpperCase();\n  return /^SELECT\\b/.test(upper) && !/\\bINTO\\b/.test(upper);\n}","tryCatchPattern":"try {\n  return await tools.call('database_gateway_execute_query', { sql });\n} catch (e) {\n  if (/did not return a result set/i.test(e.message)) {\n    // dialect divergence: reroute to update path or rewrite statement (e.g. SELECT INTO -> CREATE+INSERT)\n    return rewriteWithoutSelectInto(sql);\n  }\n  throw e;\n}","preventionTips":["Avoid dialect-specific non-result-set SELECT forms (SELECT ... INTO) via MCP tools.","Prefer the explain tool for EXPLAIN statements instead of raw execute_query.","Verify new SQL shapes with one dry call before wiring them into automated flows.","Keep driver and analyzer versions aligned with the target database version."],"tags":["mcp","sql","jdbc","result-set","dialect"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}