Skip to content

Cursor.nextset() does not update rowcount for the next result #863

Closed

Description

@phelipelui

Describe the bug

After Cursor.nextset() moves to the next result of a multi-statement batch, Cursor.rowcount still holds the value set by execute() for the first statement. The affected-row count of every later INSERT/UPDATE/DELETE in the batch therefore cannot be read through the DB API.

nextset() calls SQLMoreResults and refreshes description and messages, but it never calls SQLRowCount, unlike execute(). pyodbc refreshes rowcount there (Cursor_nextset calls SQLRowCount after SQLMoreResults), and nextset()'s docstring cites pyodbc parity.

This matters most for T-SQL batches with control flow. A WHILE loop that inserts rows sends one result per INSERT, and the only way to count the rows the batch changed is to read rowcount after each nextset(). Tools that report "N rows affected" per batch (migration runners, deployment CLIs) under-report, and a loop that inserted 5 rows shows 0 or 1.

No exception is raised.

To reproduce

import mssql_python
from mssql_python import ddbc_bindings

conn = mssql_python.connect(
    "Server=localhost,1433;Database=tempdb;UID=sa;PWD=<password>;"
    "Encrypt=yes;TrustServerCertificate=yes;"
)
cur = conn.cursor()
cur.execute("CREATE TABLE #t (id INT)")

cur.execute("""
    INSERT INTO #t VALUES (1);
    INSERT INTO #t VALUES (2), (3);
    UPDATE #t SET id = id + 10;
""")
seen = [cur.rowcount]
native = [ddbc_bindings.DDBCSQLRowCount(cur.hstmt)]
while cur.nextset():
    seen.append(cur.rowcount)
    native.append(ddbc_bindings.DDBCSQLRowCount(cur.hstmt))

print("cursor.rowcount:", seen)    # [1, 1, 1]
print("SQLRowCount:    ", native)  # [1, 2, 3]

With a loop, every INSERT of the WHILE is its own result:

cur.execute("""
    DECLARE @i INT = 1;
    WHILE @i <= 3
    BEGIN
        INSERT INTO #t SELECT TOP (@i) n FROM (VALUES (1), (2), (3)) AS v(n);
        SET @i = @i + 1;
    END;
""")
counts = [cur.rowcount]
while cur.nextset():
    counts.append(cur.rowcount)
print(counts)  # [1, 1, 1] -- expected [1, 2, 3]

Expected behavior

After each nextset() that returns True, rowcount reflects the result the cursor is now on, the same way it does after execute():

  • the affected-row count for an INSERT/UPDATE/DELETE/MERGE result;
  • -1 for a result set, which fetch*() then updates as it does today.

For the first example that is [1, 2, 3]. This matches pyodbc on the same batch.

Further technical details

  • Python version: 3.12
  • mssql-python: 1.16.0 (also seen on 1.4.0; the code on main at bd0aaf8 is the same)
  • SQL Server version: SQL Server 2022 (16.0.4305.5, RTM-CU27-GDR)
  • Operating system: Debian 12 (bookworm), in a container

Additional context

A fix is ready, and I can open a PR for it. After the describe step, nextset() would set rowcount the same way execute() does: -1 when the new result has columns, otherwise DDBCSQLRowCount(self.hstmt). It comes with two regression tests in tests/test_004_cursor.py.

I did not look at AsyncCursor.nextset(), which goes through py-core and may need its own check.

Activity

  1. github-actions commented on Oct 24, 2026

    @github-actions

    Hi LP Bispo (@phelipelui), thank you for opening this issue!

    Our team will review it shortly. We aim to triage all new issues within 24-48 hours and get back to you.

    If you have additional information to share, please feel free to update the issue.

    Thank you for your patience!

  2. added
    bugSomething isn't working
    triage doneIssues that are triaged by dev team and are in investigation.
    and removed
    triage neededFor new issues, not triaged yet.
    on Oct 28, 2026
  3. jahnvi480 commented on Oct 28, 2026

    @jahnvi480
    Contributor

    LP Bispo (@phelipelui) Thank you for raising the issue and also creating the PR to fix it. Your PR has been merged, the fix will be available in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

FIXEDbugSomething isn't workingtriage doneIssues that are triaged by dev team and are in investigation.under development

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions