matrixorigin / matrixorigin/matrixone
[Bug]: statement_info result_count is 1 when KILL QUERY returns no rows
- Dominant language
- Go
- Stars
- 1.9k
- Forks
- 311
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 768
Description
## Description
`system.statement_info.result_count` is recorded as `1` for a scalar `SELECT` canceled by `KILL QUERY`, even though the client receives an error and zero result rows.
## Environment
- Branch: `main`
- Commit: `8e616a693458652cc26b3c4be45c6602dff298d4`
- Deployment: local two-CN cluster, `./mo-service -launch etc/launch-multi-cn/launch.toml`
- Date: 2026-08-26
## Steps to reproduce
Session 1:
```sql
SET disable_agg_statement = 1;
/*stmt_cancel_result_count*/ SELECT SLEEP(20);
```
While the query is running, obtain its connection ID from `SHOW FULL PROCESSLIST` and cancel it from Session 2:
```sql
KILL QUERY ;
```
Then query the final statement record:
```sql
SELECT status, err_code, error, result_count, connection_id
FROM system.statement_info
WHERE statement LIKE '/*stmt_cancel_result_count%';
```
## Actual behavior
The client exits with code 1, prints `ERROR 1105 (HY000): context canceled`, and writes zero bytes to stdout. The final record is:
```text
status err_code error result_count
Failed 100 context canceled 1
```
## Expected behavior
`result_count` should be `0` because no result row was sent to the client.
## Stability and controls
- Reproducer: 3/3; all three canceled queries recorded `Failed`, `context canceled`, and `result_count=1`, while each client result file was empty.
- Additional minimal run: client exit code `1`, stdout `0` bytes, same incorrect `result_count=1`.
- Passing control: a successful scalar `SELECT` records `result_count=1`.
- Failing controls: duplicate-key, missing-table, and syntax failures record `result_count=0`.
- The database remains usable after every cancellation; no panic, hang, or data mutation is involved.
## Evidence
```text
round 1: Failed | 100 | context canceled | result_count=1 | client stdout=0 bytes
round 2: Failed | 100 | context canceled | result_count=1 | client stdout=0 bytes
round 3: Failed | 100 | context canceled | result_count=1 | client stdout=0 bytes
```
## Code analysis
`pkg/frontend/session.go` defines `sentRows` as the number of rows sent to the client. `pkg/frontend/mysql_cmd_executor.go:getDataFromPipeline` increments it with `bat.RowCount()` after `RespResult`, and `pkg/frontend/util.go:finishStatementAccounting` passes the value to `StatementInfo.EndStatement` even when the statement ends with an error.
The observed behavior suggests that the canceled scalar expression contributes a one-row pipeline batch before the cancellation error reaches terminal statement accounting, although no row is delivered to the client. The fix should make `result_count` follow successfully delivered protocol rows, including cancellation/error paths.
## Regression coverage
Add a multi-session motr scenario: run a blocking scalar `SELECT`, cancel it through a second connection, assert the client receives an error with zero rows, then assert the final `statement_info` row is `Failed` with `result_count=0`.
## Related
- No matching open or closed issue was found using `statement_info`, `result_count`, `KILL QUERY`, and `context canceled` searches.
Contributor guide
Research direction
Start with pkg/frontend/session.go, pkg/frontend/mysql_cmd_executor.go:getDataFromPipeline, and pkg/frontend/util.go:finishStatementAccounting to trace sentRows through cancellation and statement finalization. Run the provided two-session KILL QUERY reproducer and add the described multi-session motr scenario. Done means the canceled scalar SELECT records Failed with result_count=0 while successful scalar SELECT behavior remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, sql
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100