-
Notifications
You must be signed in to change notification settings - Fork 160
feat: return affected row count for INSERT/UPDATE/DELETE #213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR enhances database result reporting by adding rowCount to track affected/returned rows across all database connectors (PostgreSQL, MySQL, MariaDB, SQLite, SQL Server). The frontend now displays "N rows affected" for successful write operations instead of "No results returned", providing better user feedback.
Key changes:
- Added
extractAffectedRowsutility function for MySQL/MariaDB result parsing - Updated all connectors to return
rowCountalongsiderows - Modified tool handlers to use
rowCountfor thecountfield with fallback torows.length
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/multi-statement-result-parser.ts | Added extractAffectedRows function to calculate total affected/returned rows from MySQL/MariaDB results |
| src/tools/execute-sql.ts | Updated to use rowCount ?? rows.length for the count field |
| src/tools/custom-tool-handler.ts | Updated to use rowCount ?? rows.length for the count field |
| src/connectors/sqlite/index.ts | Added rowCount to return values, tracking changes for writes and rows.length for reads |
| src/connectors/postgres/index.ts | Added rowCount to return values using PostgreSQL's native rowCount field |
| src/connectors/mysql/index.ts | Integrated extractAffectedRows to populate rowCount |
| src/connectors/mariadb/index.ts | Integrated extractAffectedRows to populate rowCount |
| frontend/src/components/tool/ResultsTable.tsx | Updated to display "N rows affected" when rowCount > 0 and no rows returned |
| frontend/src/api/tools.ts | Updated to propagate rowCount from backend count field |
| // rowCount is total changes for writes, plus rows returned for reads | ||
| return { rows: allRows, rowCount: totalChanges + allRows.length }; |
Copilot
AI
Dec 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rowCount calculation for multi-statement queries is inconsistent with single-statement behavior. For single statements, rowCount represents either affected rows (for writes) OR returned rows (for reads), but not both. However, here it sums totalChanges (affected rows from writes) and allRows.length (returned rows from reads), mixing two different semantics.
This inconsistency could be confusing when displaying "N rows affected" in the frontend, as it would show a misleading count for mixed queries. Consider either:
- Only counting affected rows from write operations (totalChanges)
- Only counting returned rows from read operations (allRows.length)
- Documenting that multi-statement queries return a combined count
| // rowCount is total changes for writes, plus rows returned for reads | |
| return { rows: allRows, rowCount: totalChanges + allRows.length }; | |
| // For multi-statement queries, align rowCount semantics with single-statement behavior: | |
| // - If the batch is read-only, rowCount is the number of rows returned. | |
| // - If the batch includes any writes, rowCount is the total number of rows affected. | |
| const hasReads = readStatements.length > 0; | |
| const hasWrites = writeStatements.length > 0; | |
| const rowCount = hasWrites ? totalChanges : allRows.length; | |
| return { rows: allRows, rowCount }; |
| if (isMultiStatementResult(results)) { | ||
| let totalAffected = 0; | ||
| for (const result of results) { | ||
| if (isMetadataObject(result)) { | ||
| totalAffected += result.affectedRows || 0; | ||
| } else if (Array.isArray(result)) { | ||
| totalAffected += result.length; | ||
| } | ||
| } | ||
| return totalAffected; |
Copilot
AI
Dec 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extractAffectedRows function mixes two different semantics in multi-statement queries. For metadata objects (write operations), it counts affectedRows, but for array results (SELECT queries), it counts result.length (returned rows). This means a multi-statement query with both writes and reads will return a count that combines affected rows and returned rows, which is semantically inconsistent.
For example, "INSERT INTO users VALUES (1); SELECT * FROM users;" would return rowCount = 1 (affected) + row count from SELECT. This makes it unclear what "N rows affected" means in the UI.
Consider whether rowCount should represent:
- Only affected rows from write operations (skip SELECT results)
- Only returned rows from read operations (skip write metadata)
- A documented combined count with clear semantics
| // Accumulate rowCount for INSERT/UPDATE/DELETE statements | ||
| if (result.rowCount) { | ||
| totalRowCount += result.rowCount; |
Copilot
AI
Dec 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In PostgreSQL, the pg library's result.rowCount is set for both SELECT and write operations. For SELECT statements, rowCount equals the number of rows returned; for INSERT/UPDATE/DELETE, it's the number of affected rows.
This means when accumulating rowCount in multi-statement transactions that mix reads and writes, the totalRowCount will combine both returned rows and affected rows. This creates the same semantic inconsistency as in the SQLite and MySQL/MariaDB connectors, where the meaning of rowCount becomes ambiguous in mixed queries.
For consistency and clarity, consider whether to track only affected rows from write operations, or document this combined behavior explicitly.
| // Accumulate rowCount for INSERT/UPDATE/DELETE statements | |
| if (result.rowCount) { | |
| totalRowCount += result.rowCount; | |
| // Accumulate rowCount only for write operations (INSERT/UPDATE/DELETE) | |
| if (result.command && ["INSERT", "UPDATE", "DELETE"].includes(result.command.toUpperCase())) { | |
| totalRowCount += result.rowCount ?? 0; |
- Add rowCount to all database connectors (PostgreSQL, MySQL, MariaDB, SQLite, SQL Server) - Add extractAffectedRows utility for MySQL/MariaDB result parsing - Update execute-sql and custom-tool-handler to use rowCount for count field - Frontend now displays "N rows affected" for write operations instead of "No results returned" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add rowCount to all database connectors (PostgreSQL, MySQL, MariaDB, SQLite, SQL Server) - Add extractAffectedRows utility for MySQL/MariaDB result parsing - Update execute-sql and custom-tool-handler to use rowCount for count field - Frontend now displays "N rows affected" for write operations instead of "No results returned" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <[email protected]>
- Add rowCount to all database connectors (PostgreSQL, MySQL, MariaDB, SQLite, SQL Server) - Add extractAffectedRows utility for MySQL/MariaDB result parsing - Update execute-sql and custom-tool-handler to use rowCount for count field - Frontend now displays "N rows affected" for write operations instead of "No results returned" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <[email protected]>
- Add rowCount to all database connectors (PostgreSQL, MySQL, MariaDB, SQLite, SQL Server) - Add extractAffectedRows utility for MySQL/MariaDB result parsing - Update execute-sql and custom-tool-handler to use rowCount for count field - Frontend now displays "N rows affected" for write operations instead of "No results returned" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <[email protected]>
- Add rowCount to all database connectors (PostgreSQL, MySQL, MariaDB, SQLite, SQL Server) - Add extractAffectedRows utility for MySQL/MariaDB result parsing - Update execute-sql and custom-tool-handler to use rowCount for count field - Frontend now displays "N rows affected" for write operations instead of "No results returned" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <[email protected]>
🤖 Generated with Claude Code