-
Notifications
You must be signed in to change notification settings - Fork 1k
Fix issue 4855: Incorrect affected rows reporting for DDL queries #5232
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
…erface Problem: When executing DDL queries (CREATE TABLE, DROP TABLE, VACUUM, etc.) in the ProxySQL Admin interface after DML operations, the affected rows count from the previous DML operation was incorrectly reported instead of 0. This is because SQLite's sqlite3_changes() function doesn't reset the counter for DDL statements. Root Cause: SQLite's sqlite3_changes() returns the number of rows affected by the most recent INSERT, UPDATE, or DELETE statement. For DDL statements that don't modify rows, SQLite doesn't reset this counter, so it continues to return the value from the last DML operation. Solution: - Added is_ddl_query_without_row_changes() function to identify DDL queries that don't affect row counts - Modified both execute_statement() and execute_statement_raw() in SQLite3DB to return 0 for affected_rows when executing DDL queries - The fix ensures that affected_rows is reset to 0 for: CREATE, DROP, ALTER, TRUNCATE, VACUUM, REINDEX, ANALYZE, CHECKPOINT, PRAGMA, BEGIN, COMMIT, ROLLBACK, SAVEPOINT, RELEASE, EXPLAIN Testing: - Created and ran comprehensive tests for DDL detection function - Verified build completes successfully - Confirmed the fix correctly identifies DDL vs DML queries Impact: This fix resolves the issue where Admin interface incorrectly shows affected rows for DDL operations, improving the accuracy and reliability of the ProxySQL Admin interface. Fixes #4855
PROBLEM: The initial fix used a DDL detection approach which required maintaining a list of query types that should return 0 affected rows. This approach was brittle and could miss edge cases like commented queries or complex statements. SOLUTION: Instead of detecting DDL queries, use sqlite3_total_changes64() to measure the actual change count before and after each query execution. The difference between total_changes before and after represents the true affected rows count for the current query, regardless of query type. CHANGES: - Added proxy_sqlite3_total_changes64 function pointer and initialization - Rewrote execute_statement() and execute_statement_raw() to use total_changes difference approach - This automatically handles all query types (DDL, DML, comments, etc.) - Added comprehensive TAP test covering INSERT, CREATE, DROP, VACUUM, UPDATE, and BEGIN operations BENEFITS: - More robust and accurate than DDL detection approach - Handles edge cases like commented queries automatically - No maintenance overhead for new query types - Simpler and cleaner implementation - Still fixes both Admin interface and SQLite3 Server This approach is mathematically sound: affected_rows = total_changes_after - total_changes_before, which gives the exact number of rows changed by the current query execution. Fixes #4855
- Updated main TAP test to remove proxy_sqlite3 wrapper dependency - Added standalone TAP test using raw SQLite functions - Both tests verify the sqlite3_total_changes64 difference approach works correctly - Main ProxySQL build confirms the fix is functional
- TAP test connects to ProxySQL Admin interface on port 6032 - Tests INSERT, CREATE TABLE, DROP TABLE, UPDATE, DELETE operations - Verifies that DDL queries return 0 affected rows after DML operations - Confirms the sqlite3_total_changes64 fix works correctly in Admin interface - This directly tests the issue reported in #4855
- Use CommandLine cl object with getEnv() for configuration - Remove hardcoded IP, ports, and credentials - Connect to both Admin interface and SQLite3 Server - Test DDL queries returning 0 affected rows after DML operations - Follow ProxySQL TAP test conventions and patterns
- Replace made-up fail()/pass() functions with ok() and diag() - Follow proper TAP test structure from ProxySQL TAP guide - Use plan(N), ok(condition, description), diag(), and return exit_status() - Maintain proper error handling and test organization
Improve the TAP test to be SQLite-compatible and comprehensive: - Remove TRUNCATE operations (not supported by SQLite) - Use individual DROP TABLE statements instead of multi-table DROP - Add VACUUM test to verify DDL affected rows are 0 - Update test plan to match actual number of assertions (14) - Use temporary tables instead of configuration tables - Test all major DDL operations: CREATE, DROP, ALTER, VACUUM - Test all major DML operations: INSERT, UPDATE, DELETE - Verify affected rows are correctly calculated for all query types - Add test for commented DDL queries - Include comprehensive cleanup with proper error handling The test now accurately verifies that the sqlite3_total_changes64() difference approach correctly fixes the affected rows calculation for both DDL and DML operations.
Summary of ChangesHello @renecannao, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a critical bug in the ProxySQL Admin interface where DDL queries were incorrectly reporting affected row counts. The solution involves a fundamental change in how affected rows are calculated for non-SELECT statements, moving from a potentially misleading Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
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.
Code Review
This pull request provides a solid fix for the incorrect reporting of affected rows for DDL queries. The use of sqlite3_total_changes64() is a robust solution to the problem. The implementation is clean and the accompanying test suite is comprehensive, covering various DDL and DML operations to ensure the fix is working as expected. I have a couple of minor suggestions for the new test file to improve its maintainability.
| if (mysql_query(admin, "CREATE TABLE test_table_4855 (id INT PRIMARY KEY, name VARCHAR(255))")) { | ||
| diag("Failed to execute CREATE TABLE query: %s", mysql_error(admin)); | ||
| mysql_close(admin); | ||
| return exit_status(); | ||
| } |
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.
This block of code for executing a query and handling errors is repeated multiple times throughout the test. To improve code readability and maintainability, consider abstracting this logic into a helper function. For example, you could create a function like execute_query(MYSQL *admin, const char *query, const char *fail_msg) and call it for each query. This would reduce code duplication and make the test logic easier to follow.
| diag("Additional cleanup DROP TABLE executed"); | ||
| mysql_close(admin); | ||
| return exit_status(); | ||
| } No newline at end of file |
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.
Include the regression test for issue 4855 in the g1 test group configuration to ensure it runs as part of the standard test suite.
Signed-off-by: René Cannaò <rene@proxysql.com>
|
|
retest this please |



Summary
Fixes issue #4855 where
mysql_affected_rows()in ProxySQL Admin interface was incorrectly reporting affected rows for DDL queries. After executing DML operations, DDL queries would return the affected rows count from previous DML operations instead of 0.Root Cause
The problem was caused by SQLite's
sqlite3_changes()function, which doesn't reset the counter for DDL statements that don't modify data (CREATE, DROP, ALTER, VACUUM, etc.).Solution
Implemented a robust mathematical approach using
sqlite3_total_changes64()difference:Core Changes:
proxy_sqlite3_total_changes64ininclude/sqlite3db.hlib/sqlite3db.cppexecute_statement()functions to calculate affected rows as the difference between total changes before and after query executionKey Benefits:
Testing
Added comprehensive TAP test
reg_test_4855_affected_rows_ddl-t.cppwith 14 test cases:Setup Tests:
DDL Tests (verify 0 affected rows):
DML Tests (verify correct affected rows):
Test Features:
Files Modified
include/sqlite3db.h: Added function pointer declarationlib/sqlite3db.cpp: Added function pointer initialization and modified affected rows calculationtest/tap/tests/reg_test_4855_affected_rows_ddl-t.cpp: Comprehensive test suiteTesting
The fix has been tested with:
Impact
This fix ensures that ProxySQL Admin interface accurately reports affected rows for all query types, resolving the issue where DDL queries incorrectly inherited affected rows counts from previous DML operations.