Skip to content

Conversation

@renecannao
Copy link
Contributor

@renecannao renecannao commented Nov 24, 2025

Summary

This PR fixes SQLite 'table already exists' errors that occur during PROXYSQL STOP operations by adding 'IF NOT EXISTS' clauses to all CREATE TABLE statements. This is part of the broader work for issue #5218 (Verify dependencies between PR #5217 and PR #4960).

Problem (Issue #5221)

During PROXYSQL STOP execution, multiple SQLite errors were logged indicating that tables already exist when there's an attempt to create them:

ERROR: SQLITE error: table mysql_servers already exists --- CREATE TABLE mysql_servers...
ERROR: SQLITE error: table mysql_servers_incoming already exists --- CREATE TABLE mysql_servers_incoming...
ERROR: SQLITE error: table mysql_replication_hostgroups already exists --- CREATE TABLE mysql_replication_hostgroups...

Context

This fix addresses the table creation errors that were discovered while implementing the dependency verification for issue #5218. The errors were affecting our ability to properly test PROXYSQL STOP/START functionality with selective module configurations.

Root Cause

The issue is caused by:

  1. Module restarts during PROXYSQL STOP - Modules are reinitialized multiple times without proper cleanup
  2. In-memory SQLite databases - Tables persist across restarts in ':memory:' databases
  3. Multiple constructors - Both Base_HostGroups_Manager and MySQL_HostGroups_Manager initialize tables
  4. Missing existence checks - CREATE TABLE statements don't check if tables already exist

Solution

Added 'IF NOT EXISTS' clauses to all CREATE TABLE macros to prevent errors when tables already exist.

Files Changed

  • include/Base_HostGroups_Manager.h - Updated all table schemas with 'IF NOT EXISTS' and comprehensive Doxygen documentation
  • include/MySQL_HostGroups_Manager.h - Removed duplicate table definitions

Tables Fixed

  • MYHGM_MYSQL_SERVERS & MYHGM_MYSQL_SERVERS_INCOMING (DEBUG/non-DEBUG variants)
  • MYHGM_MYSQL_REPLICATION_HOSTGROUPS
  • MYHGM_MYSQL_GROUP_REPLICATION_HOSTGROUPS
  • MYHGM_MYSQL_GALERA_HOSTGROUPS
  • MYHGM_MYSQL_AWS_AURORA_HOSTGROUPS
  • MYHGM_MYSQL_HOSTGROUP_ATTRIBUTES
  • MYHGM_MYSQL_SERVERS_SSL_PARAMS

Benefits

  • Eliminates SQLite errors during normal PROXYSQL STOP operations
  • Cleaner error logs - No confusing 'table already exists' messages
  • Improved performance - No error handling overhead during shutdown
  • Maintains functionality - Zero impact on data integrity or normal operations
  • Future-proof - Prevents similar issues during module restarts

Documentation

Added comprehensive Doxygen documentation explaining:

  • Root cause analysis
  • Why the issue occurs
  • Implementation details
  • Impact and benefits
  • Reference to original issue

Testing

Impact

This is a safe, low-risk fix that:

…5221)

Add comprehensive Doxygen documentation and 'IF NOT EXISTS' clauses to prevent SQLite errors:

Root Cause:
- During PROXYSQL STOP, modules are restarted multiple times without proper table cleanup
- MySQL_HostGroups_Manager and Base_HostGroups_Manager constructors both create tables
- In-memory SQLite databases persist across restarts, causing 'table already exists' errors

Solution:
- Add 'IF NOT EXISTS' clauses to all 9 CREATE TABLE macros
- Comprehensive Doxygen documentation explaining the issue and fix
- Individual table documentation with @brief and @details

Tables Fixed:
- MYHGM_MYSQL_SERVERS & MYHGM_MYSQL_SERVERS_INCOMING (DEBUG/non-DEBUG variants)
- MYHGM_MYSQL_REPLICATION_HOSTGROUPS
- MYHGM_MYSQL_GROUP_REPLICATION_HOSTGROUPS
- MYHGM_MYSQL_GALERA_HOSTGROUPS
- MYHGM_MYSQL_AWS_AURORA_HOSTGROUPS
- MYHGM_MYSQL_HOSTGROUP_ATTRIBUTES
- MYHGM_MYSQL_SERVERS_SSL_PARAMS

Benefits:
- Eliminates SQLite error logging during normal PROXYSQL STOP operations
- Improves shutdown performance by removing error handling overhead
- Cleaner logs without confusing 'table already exists' messages
- Maintains data integrity and functionality

Files Modified:
- include/Base_HostGroups_Manager.h: Updated all table schemas with 'IF NOT EXISTS' and Doxygen docs
- include/MySQL_HostGroups_Manager.h: Removed duplicate table definitions
@gemini-code-assist
Copy link

Summary of Changes

Hello @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 significantly improves the stability and flexibility of ProxySQL by resolving SQLite 'table already exists' errors during shutdown sequences and enhancing the PROXYSQL STOP/START command's robustness. It also introduces granular control over module activation, allowing administrators to enable or disable MySQL and PostgreSQL worker threads, admin interfaces, and monitor modules independently. These changes contribute to a more reliable and configurable ProxySQL instance, particularly during operational changes and restarts.

Highlights

  • SQLite Error Resolution: Addressed and fixed 'table already exists' errors that occurred during PROXYSQL STOP operations by incorporating 'IF NOT EXISTS' clauses into all CREATE TABLE statements within the MySQL HostGroups Manager. This prevents errors when in-memory SQLite tables persist across module restarts.
  • Enhanced PROXYSQL STOP/START Robustness: Implemented a more robust handling mechanism for PROXYSQL STOP and PROXYSQL START commands. This includes a draining state for active admin queries during shutdown, proper reinitialization of modules, and null pointer protection for runtime queries when modules are stopped, preventing crashes and ensuring consistent behavior.
  • Granular Module Control: Introduced new command-line arguments and configuration options to enable or disable specific ProxySQL modules, including MySQL/PostgreSQL workers, admin interfaces, and monitor modules. This allows for more flexible deployment and resource management.
  • Code Refactoring and Documentation: Refactored SQL schema definitions into Base_HostGroups_Manager.h and added comprehensive Doxygen documentation explaining the root cause of the SQLite errors and the solution implemented. This improves code clarity and maintainability.
  • New Test Cases: Added new TAP test cases to validate the module enable/disable functionality and the improved PROXYSQL STOP/START query handling, ensuring the stability and correctness of these new features.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a 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 introduces two major improvements. First, it resolves SQLite 'table already exists' errors during PROXYSQL STOP by adding IF NOT EXISTS to all CREATE TABLE statements, which is a direct and effective fix. Second, and more substantially, it adds a state machine and graceful shutdown logic for the PROXYSQL STOP/START cycle to prevent crashes and instability, which is a critical enhancement for the reliability of ProxySQL. The changes are well-documented with extensive Doxygen comments, and the addition of new tests for module startup and PROXYSQL STOP behavior is commendable. My review found one critical typo in a CREATE TABLE statement and some dead code that can be removed for better maintainability. Overall, this is a high-quality contribution that significantly improves the robustness of ProxySQL.

/// @brief MySQL AWS Aurora hostgroups configuration table
/// @details Aurora-specific hostgroup management with dynamic topology detection and lag monitoring
#define MYHGM_MYSQL_AWS_AURORA_HOSTGROUPS "CREATE TABLE IF NOT EXISTS mysql_aws_aurora_hostgroups (writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY , reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>0) , " \
"active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , aurora_port INT NOT NUlL DEFAULT 3306 , domain_name VARCHAR NOT NULL DEFAULT '' , " \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

There is a typo in the CREATE TABLE statement. NUlL should be NULL. This will cause a SQL syntax error when trying to create the table.

										  "active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1 , aurora_port INT NOT NULL DEFAULT 3306 , domain_name VARCHAR NOT NULL DEFAULT '' , " \

Comment on lines 3008 to 3047
#if 0
{
// this block seems unnecessary, as we have enough fencing
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
// Check if this is a dangerous query that should be blocked during STOP states (issue 5186)
if (glovars.stop_state != STOP_STATE_RUNNING && sess->session_type == PROXYSQL_SESSION_ADMIN) {
// Block dangerous runtime_* queries that access destroyed modules
if (!strncasecmp(query_no_space, "SELECT COUNT(*) FROM runtime_mysql_query_rules", strlen("SELECT COUNT(*) FROM runtime_mysql_query_rules")) ||
!strncasecmp(query_no_space, "SELECT COUNT(*) FROM runtime_mysql_query_rules_fast_routing", strlen("SELECT COUNT(*) FROM runtime_mysql_query_rules_fast_routing")) ||
!strncasecmp(query_no_space, "SELECT COUNT(*) FROM runtime_mysql_users", strlen("SELECT COUNT(*) FROM runtime_mysql_users")) ||
!strncasecmp(query_no_space, "SELECT COUNT(*) FROM stats_mysql_query_digest", strlen("SELECT COUNT(*) FROM stats_mysql_query_digest")) ||
!strncasecmp(query_no_space, "SELECT * FROM runtime_mysql_query_rules", strlen("SELECT * FROM runtime_mysql_query_rules")) ||
!strncasecmp(query_no_space, "SELECT * FROM runtime_mysql_query_rules_fast_routing", strlen("SELECT * FROM runtime_mysql_query_rules_fast_routing")) ||
!strncasecmp(query_no_space, "SELECT * FROM runtime_mysql_users", strlen("SELECT * FROM runtime_mysql_users")) ||
!strncasecmp(query_no_space, "SELECT * FROM stats_mysql_query_digest", strlen("SELECT * FROM stats_mysql_query_digest"))) {

//l_free(query_length, query); // ASAN correctly reports a double free

// Return empty resultset instead of crashing
SQLite3_result *resultset = new SQLite3_result(1);
resultset->add_column_definition(SQLITE_TEXT, "COUNT(*)");

// Add a single row with 0 for COUNT(*) queries
SQLite3_row *row = new SQLite3_row(1);
char *field_val = strdup("0");
row->fields[0] = field_val;
resultset->add_row(row);

sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot);
delete resultset;
delete row;
free(field_val);

run_query = false;
goto __run_query;
}
}
needs_vacuum = SPA->GenericRefreshStatistics(query_no_space,query_no_space_length, ( sess->session_type == PROXYSQL_SESSION_ADMIN ? true : false ) );
}

#endif // 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code is disabled with #if 0 and the inline comment suggests it's no longer necessary. To improve code clarity and maintainability, it would be best to remove this dead code.

@renecannao renecannao changed the base branch from v3.0 to v3.0-5218 November 24, 2025 10:42
@noizu noizu added this to the Release 3.0.4 milestone Nov 25, 2025
@renecannao
Copy link
Contributor Author

retest this please

…5221)

Root Cause:
- During PROXYSQL STOP, modules are restarted multiple times without proper table cleanup
- MySQL_HostGroups_Manager and PgSQL_HostGroups_Manager constructors both create tables
- In-memory SQLite databases persist across restarts, causing 'table already exists' errors

Solution:
- Add 'IF NOT EXISTS' clauses to all CREATE TABLE macros in both managers
- Applied fix to the actual table definitions used by the code, not commented-out code

Files Modified:
- include/MySQL_HostGroups_Manager.h: Updated 9 CREATE TABLE macros
- include/PgSQL_HostGroups_Manager.h: Updated 4 CREATE TABLE macros

Benefits:
- Eliminates SQLite error logging during normal PROXYSQL STOP operations
- Improves shutdown performance by removing error handling overhead
- Cleaner logs without confusing 'table already exists' messages
- Maintains data integrity and functionality
- Removed 'pgsql_thread___enable_load_data_local_infile' assignment
- This appears to be a MySQL-specific variable that shouldn't be in PgSQL code
- Cleans up dead code and improves code clarity
… code

- Removed large block of commented-out code (89 lines)
- Code contained MySQL-specific logic that doesn't belong in PgSQL module
- Removes dead code for SELECT VERSION_COMMENT, SELECT USER(), and LOAD DATA LOCAL INFILE
- Improves code readability and reduces maintenance burden
@sonarqubecloud
Copy link

@renecannao
Copy link
Contributor Author

retest this please

@renecannao renecannao merged commit c467a4a into v3.0-5218 Nov 28, 2025
144 of 154 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants