Skip to content

Report -1 for statements that are not INSERT, UPDATE or DELETE - #374

Merged
Giorgi merged 2 commits into
Giorgi:developfrom
pengdows:fix/affected-row-counts
Oct 20, 2026
Merged

Giorgi merged 2 commits into
Giorgi:developfrom
pengdows:fix/affected-row-counts

Conversation

@alaricd

@alaricd alaricd commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Two affected-row counts disagreed with the ADO.NET contract:\n\n- ExecuteNonQuery now returns -1 for non-row-counting statements and counts INSERT, UPDATE, DELETE, COPY, and MERGE.\n- ExecuteReader().RecordsAffected counts those statements as well.\n- DML statements with RETURNING use the query result row count, including materialized and streaming results.\n\nTests cover non-DML, zero-row DML, MERGE, COPY, DML with RETURNING, and RecordsAffected through ExecuteReader. The focused ExecuteNonQueryTests suite passes 11/11.\n\nFound by the pengdows ADO.NET conformance suite, which runs the documented System.Data.Common contract against every provider.

@coveralls

coveralls commented Oct 20, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 39438113753

Coverage increased (+0.1%) to 92.624%

Details

  • Coverage increased (+0.1%) from the base build.
  • Patch coverage: 11 of 11 lines across 2 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 4026
Covered Lines: 3791
Line Coverage: 94.16%
Relevant Branches: 2305
Covered Branches: 2073
Branch Coverage: 89.93%
Branches in Coverage %: Yes
Coverage Strength: 1001240.48 hits per line

💛 - Coveralls

@Giorgi

Giorgi commented Oct 20, 2026

Copy link
Copy Markdown
Owner

Thanks. For INSERT, UPDATE, DELETE, SELECT, DDL and SET this matches Npgsql, but I found two problems. I ran the same statements against this branch, against develop, and with Npgsql 10.0.0 against PostgreSQL 18.3 (ExecuteNonQuery, and ExecuteReader → read everything → Close → RecordsAffected; DuckDB with UseStreamingMode both off and on, with the same results):

Statement develop (ExecuteNonQuery / RecordsAffected) this PR Npgsql
MERGE (1 update + 1 insert) 2 / -1 -1 / -1 2 / 2
COPY t FROM 'file.csv' (2 rows) 2 / -1 -1 / -1 2 / 2
COPY t TO 'file.csv' (3 rows) 3 / -1 -1 / -1 not tested
INSERT … RETURNING (2 rows) 0 / -1 0 / 0 2 / 2
UPDATE … RETURNING (3 rows) 0 / -1 0 / 0 3 / 3

1. MERGE and COPY now return -1

On develop, ExecuteNonQuery returns their row count. CountsRows accepts only Insert, Update and Delete, so both are now reported as -1.

MERGE also needs the bindings. DuckDB 1.5.6 returns DUCKDB_STATEMENT_TYPE_MERGE_INTO = 30 from duckdb_result_statement_type (see duckdb.h), but DuckDBStatementType stops at Multi = 27, so a MERGE arrives as an undefined value. Could you:

  • add CopyDatabase = 28, UpdateExtensions = 29 and MergeInto = 30 to DuckDBStatementType;
  • count MergeInto and Copy in CountsRows;
  • add tests for MERGE and COPY?

2. RETURNING reports 0

duckdb_rows_changed returns 0 for any result whose return type isn't CHANGED_ROWS (src/main/capi/result-c.cpp), and a statement with RETURNING produces a query result. So INSERT … RETURNING and UPDATE … RETURNING report 0, which by the contract means "no rows were affected". That is the optimistic-concurrency misreading the description mentions. It's not a regression (develop returns 0 from ExecuteNonQuery too), but the description gives RETURNING as a reason for the change. Could you either handle it, for example by counting the rows of the result for an INSERT, UPDATE or DELETE that returns a query result, or take RETURNING out of the description, so that it doesn't look covered?

Nit: ExecuteNonQueryTests.cs ends with an extra blank line after the closing }.

@alaricd

alaricd commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review feedback in 5327966:\n\n- Added the DuckDB 1.5.6 statement types CopyDatabase = 28, UpdateExtensions = 29, and MergeInto = 30 (and aligned the enum with the C API).\n- COPY and MERGE are now included in affected-row counting.\n- Query-result row counts are used for DML with RETURNING, so both ExecuteNonQuery and ExecuteReader().RecordsAffected report the returned row count in materialized and streaming modes.\n- Added focused MERGE, COPY, and RETURNING tests; the focused ExecuteNonQueryTests suite passes 11/11.\n- Removed the extra trailing blank line from ExecuteNonQueryTests.cs.\n\nThe behavior is still grounded in the pengdows ADO.NET conformance suite.

alaricd and others added 2 commits October 20, 2026 08:53
DbCommand.ExecuteNonQuery: "For UPDATE, INSERT, and DELETE statements,
the return value is the number of rows affected by the command. For all
other types of statements, the return value is -1."
DbDataReader.RecordsAffected: "-1 for SELECT statements; 0 if no rows
were affected". The reader returned -1 even after a DELETE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alaricd
alaricd force-pushed the fix/affected-row-counts branch from 5327966 to 2004f78 Compare October 20, 2026 13:55
@alaricd
alaricd force-pushed the fix/affected-row-counts branch from 2004f78 to 700ea93 Compare October 20, 2026 14:19
@Giorgi
Giorgi merged commit 227414e into Giorgi:develop Oct 20, 2026
11 of 12 checks passed

This branch is waiting to be deployed

1 waiting deployment
external — 700ea93e Waiting Oct 20, 2026 by alaricd via Authorize #701
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants