Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[r2dbc] getRowsUpdated() returns 0 for successful INSERT…SELECT — needs reliable written_rows

Open
#2,860 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
java
Domain
databases

Research direction

Start in ClickHouseResult and trace how ClickHouseResponseSummary.getProgress(), getStatistics(), and the top-level getWrittenRows() supply UpdateCount. Reproduce an INSERT INTO … SELECT query using the HTTP transport, then compare getRowsUpdated() with the final written_rows value. Done means the chosen authoritative post-completion value is exposed reliably, with regression coverage for a successful INSERT…SELECT.

Written by the indexing model from the issue text.

Description

Summary

ClickHouseResult.getRowsUpdated() in clickhouse-r2dbc returns 0 for
successful INSERT INTO … SELECT FROM … queries that did write rows. This
makes it impossible to reliably distinguish "INSERT…SELECT wrote 0 rows
because the SELECT produced none" from "INSERT…SELECT wrote N rows but the
driver reported 0" at the application layer.

The same row count appears correctly in system.query_log.written_rows
server-side, and the HTTP X-ClickHouse-Summary header also carries an
accurate written_rows once the query finishes. The information exists; the
driver just doesn't expose it via the standard R2DBC Result.getRowsUpdated()
contract for this query shape.

Reproduction

  • Driver: com.clickhouse:clickhouse-r2dbc:0.9.0 (also reproduces on 0.8.x)
  • Server: ClickHouse 25.3
  • Query shape: INSERT INTO target_table (...) SELECT ... FROM source_table WHERE ...
  • Connection settings: async_insert=1, wait_for_async_insert=1
    (per docs, async_insert is a no-op for INSERT…SELECT, but we set it
    globally for the INSERT VALUES path on the same connection)
Flux.from(statement.execute())
    .flatMap(Result::getRowsUpdated)   // emits 0 even when N rows were inserted
    .reduce(0L, Long::sum)
    // observed: returns 0

Verifying server-side after the query finishes:

SELECT written_rows
FROM system.query_log
WHERE query_id = '...' AND type = 'QueryFinish';
-- returns N (the correct count)

Root cause

Looking at ClickHouseResult constructor (current main):

Mono<? extends UpdateCount> updatedCount = Mono.just(response)
    .map(ClickHouseResponse::getSummary)
    .map(ClickHouseResponseSummary::getProgress)
    .map(ClickHouseResponseSummary.Progress::getWrittenRows)
    .map(UpdateCount::new);

The driver reads written_rows from Summary.getProgress(), which is the
interim progress event snapshot — not the final summary. For
INSERT…SELECT queries, a definitive post-completion written_rows is
typically reflected in Summary.getStatistics() (or in a final progress
event that doesn't always land before the subscriber observes completion).

ClickHouseResponseSummary exposes both getProgress() and getStatistics(),
and the top-level getWrittenRows() delegates to progress.

Use case

Detecting at the application layer when an INSERT…SELECT wrote zero rows
(to surface inconsistency conditions before committing dependent state).
Since getRowsUpdated() can return 0 even on success, the check fires
false positives.

Asks

Any one of the following would unblock us:

  1. Source getRowsUpdated() from Summary.getStatistics() (or whichever
    field is authoritative post-completion) instead of from Summary.getProgress().
  2. Expose the raw ClickHouseResponseSummary from ClickHouseResult (or a
    similar handle), so callers can read the final fields themselves.
  3. Document the current semantics so applications know not to rely on
    getRowsUpdated() for INSERT…SELECT.

Happy to send a PR for (1) or (2) — please confirm which direction you'd
prefer.

Environment

  • clickhouse-r2dbc: 0.9.0
  • clickhouse-client / clickhouse-http-client: 0.9.0
  • ClickHouse server: 25.3.x
  • Connection: HTTP transport
Dominant language
Java
Stars
1.6k
Forks
637
Avg merge
2d 17h
Merged PRs (30d)
29

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ClickHouse/clickhouse-java

All issues in ClickHouse/clickhouse-java

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.