Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b67c7c1
feat: Implement PostgreSQL cluster synchronization for issue #5147
renecannao Nov 27, 2025
d96be35
fix: Add pgsql_servers_v2 to runtime_checksums_values table and creat…
renecannao Nov 28, 2025
e0dec1c
fix: Complete pgsql_servers_v2 checksum integration in runtime_checks…
renecannao Nov 28, 2025
958d250
fix: Correct PostgreSQL query rules cluster sync implementation
renecannao Nov 28, 2025
7a08167
fix: Correct PostgreSQL checksum structure field names
renecannao Nov 28, 2025
87a64b7
fix: Add missing PostgreSQL includes and fix type conversion warnings
renecannao Nov 28, 2025
187b71e
fix: Correct TAP test syntax according to TAP_TESTS_GUIDE.md
renecannao Nov 28, 2025
697b68e
docs: Add comprehensive Doxygen documentation for PostgreSQL cluster …
renecannao Nov 28, 2025
2444456
refactor: Add memory management helper to reduce code duplication
renecannao Nov 28, 2025
1d73967
refactor: Add safe_update_peer_info helper function
renecannao Nov 28, 2025
9ec6bef
refactor: Eliminate massive duplication in set_checksums() and fix cr…
renecannao Nov 29, 2025
a3130ca
feat: Complete PostgreSQL cluster synchronization with pgsql_variable…
renecannao Nov 29, 2025
e2d6411
Refactor ProxySQL_Cluster: Eliminate code duplication and modernize a…
renecannao Nov 29, 2025
2c9bb51
refactor: Optimize process_component_checksum() and eliminate repetit…
renecannao Nov 29, 2025
2c08e77
refactor: Implement loop-based sync decision optimization for admin_v…
renecannao Nov 29, 2025
c2a05ae
refactor: Apply enabled_check() pattern to ChecksumModuleInfo for uni…
renecannao Nov 29, 2025
c97cca0
refactor: unify ChecksumModuleInfo and SyncModuleConfig structures
renecannao Nov 29, 2025
c37481a
feat: add missing PostgreSQL variables sync metrics counters
renecannao Nov 29, 2025
4503c58
refactor: unify duplicate get_peer_to_sync_* variables functions
renecannao Nov 29, 2025
1beb5b9
fix: address review comments for PostgreSQL cluster sync PR
renecannao Jan 11, 2026
a8a7b56
fix: correct MySQL variables DELETE query variable name
renecannao Jan 11, 2026
ab2c4f3
feat: add PostgreSQL variables to unified cluster sync
renecannao Jan 11, 2026
5af4011
feat: add CLUSTER_SYNC_INTERFACES_PGSQL interface filtering
renecannao Jan 11, 2026
1b58c78
feat: implement PostgreSQL variables cluster sync core functionality
renecannao Jan 11, 2026
086edfe
feat: add PostgreSQL replication hostgroups and hostgroup attributes …
renecannao Jan 12, 2026
d64b4c8
fix: resolve PostgreSQL cluster sync compilation issues
renecannao Jan 12, 2026
d11620e
refactor: remove redundant pgsql_variables sync logic
renecannao Jan 12, 2026
777a829
refactor: implement unified pull framework for cluster sync
renecannao Jan 12, 2026
5d61766
refactor: implement comprehensive memory management framework
renecannao Jan 12, 2026
ddf3aa0
refactor: extract magic strings to namespace-based constants
renecannao Jan 13, 2026
3618e01
Merge branch 'v3.0' into fix/postgresql-cluster-sync
renecannao Jan 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
271 changes: 264 additions & 7 deletions include/ProxySQL_Cluster.hpp

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions include/proxysql_admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ class ProxySQL_Admin {
int cluster_mysql_variables_diffs_before_sync;
int cluster_admin_variables_diffs_before_sync;
int cluster_ldap_variables_diffs_before_sync;
int cluster_pgsql_variables_diffs_before_sync;
int cluster_pgsql_query_rules_diffs_before_sync;
int cluster_pgsql_servers_diffs_before_sync;
int cluster_pgsql_users_diffs_before_sync;
int cluster_mysql_servers_sync_algorithm;
bool cluster_mysql_query_rules_save_to_disk;
bool cluster_mysql_servers_save_to_disk;
Expand All @@ -321,6 +325,10 @@ class ProxySQL_Admin {
bool cluster_mysql_variables_save_to_disk;
bool cluster_admin_variables_save_to_disk;
bool cluster_ldap_variables_save_to_disk;
bool cluster_pgsql_variables_save_to_disk;
bool cluster_pgsql_query_rules_save_to_disk;
bool cluster_pgsql_servers_save_to_disk;
bool cluster_pgsql_users_save_to_disk;
int stats_mysql_connection_pool;
int stats_mysql_connections;
int stats_mysql_query_cache;
Expand Down Expand Up @@ -516,6 +524,7 @@ class ProxySQL_Admin {
bool checksum_mysql_variables;
bool checksum_admin_variables;
bool checksum_ldap_variables;
bool checksum_pgsql_variables;
} checksum_variables;
template<enum SERVER_TYPE pt>
void public_add_active_users(enum cred_username_type usertype, char *user=NULL) {
Expand Down Expand Up @@ -617,6 +626,7 @@ class ProxySQL_Admin {
// void flush_admin_variables__from_disk_to_memory(); // commented in 2.3 because unused
void flush_admin_variables__from_memory_to_disk();
void flush_ldap_variables__from_memory_to_disk();
void flush_pgsql_variables__from_memory_to_disk();
void load_mysql_servers_to_runtime(const incoming_servers_t& incoming_servers = {}, const runtime_mysql_servers_checksum_t& peer_runtime_mysql_server = {},
const mysql_servers_v2_checksum_t& peer_mysql_server_v2 = {});
void save_mysql_servers_from_runtime();
Expand Down
1 change: 1 addition & 0 deletions include/proxysql_glovars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#define CLUSTER_SYNC_INTERFACES_ADMIN "('admin-mysql_ifaces','admin-restapi_port','admin-telnet_admin_ifaces','admin-telnet_stats_ifaces','admin-web_port','admin-pgsql_ifaces')"
#define CLUSTER_SYNC_INTERFACES_MYSQL "('mysql-interfaces')"
#define CLUSTER_SYNC_INTERFACES_PGSQL "('pgsql-interfaces')"

#include <memory>
#include <string.h>
Expand Down
13 changes: 13 additions & 0 deletions lib/Admin_FlushVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,10 @@ void ProxySQL_Admin::flush_GENERIC_variables__checksum__database_to_runtime(cons
if (GloVars.cluster_sync_interfaces == false) {
q += " AND variable_name NOT IN " + string(CLUSTER_SYNC_INTERFACES_ADMIN);
}
} else if (modname == "pgsql") {
if (GloVars.cluster_sync_interfaces == false) {
q += " AND variable_name NOT IN " + string(CLUSTER_SYNC_INTERFACES_PGSQL);
}
}
q += " ORDER BY variable_name";
admindb->execute_statement(q.c_str(), &error , &cols , &affected_rows , &resultset);
Expand All @@ -399,6 +403,8 @@ void ProxySQL_Admin::flush_GENERIC_variables__checksum__database_to_runtime(cons
checkvar = &GloVars.checksums_values.mysql_variables;
} else if (modname == "ldap") {
checkvar = &GloVars.checksums_values.ldap_variables;
} else if (modname == "pgsql") {
checkvar = &GloVars.checksums_values.pgsql_variables;
}
assert(checkvar != NULL);
checkvar->set_checksum(buf);
Expand Down Expand Up @@ -889,6 +895,13 @@ void ProxySQL_Admin::flush_pgsql_variables___database_to_runtime(SQLite3DB* db,
q += " AND variable_name NOT IN " + string(CLUSTER_SYNC_INTERFACES_MYSQL);
}
q += " ORDER BY variable_name";

// PostgreSQL variables filtering
q += ";\nSELECT variable_name, variable_value FROM runtime_global_variables WHERE variable_name LIKE 'pgsql-\%' AND variable_name NOT IN ('pgsql-interfaces')";
if (GloVars.cluster_sync_interfaces == false) {
q += " AND variable_name NOT IN " + string(CLUSTER_SYNC_INTERFACES_PGSQL);
}
q += " ORDER BY variable_name";
admindb->execute_statement(q.c_str(), &error, &cols, &affected_rows, &resultset);
Comment on lines +900 to 905

Choose a reason for hiding this comment

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

high

In flush_mysql_variables___database_to_runtime, a second query for pgsql variables is appended to the mysql query string q, separated by a semicolon. The admindb->execute_statement method is unlikely to support multiple SQL statements in a single call and return a combined result set; it typically prepares and executes only the first statement. As a result, the checksum for mysql_variables will be calculated incorrectly as it won't include the pgsql_variables. This logic should be separated, likely into the flush_pgsql_variables___database_to_runtime function.

uint64_t hash1 = resultset->raw_checksum();
uint32_t d32[2];
Expand Down
30 changes: 30 additions & 0 deletions lib/PgSQL_Variables_Validator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,3 +639,33 @@ const pgsql_variable_validator pgsql_variable_validator_search_path = {
.validate = &pgsql_variable_validate_search_path,
.params = {}
};


/**
* @brief Validates an integer variable for PostgreSQL.
*
* This function checks if the provided value is a valid integer representation
* and falls within the specified range. The range is defined by the params
* parameter.
*
* @param value The value to validate.
* @param params The parameter structure containing the integer range.
* @param session Unused parameter.
* @param transformed_value If not null, will be set to null.
* @return true if the value is a valid integer representation within the specified range, false otherwise.
*/
bool pgsql_variable_validate_integer(const char* value, const params_t* params, PgSQL_Session* session, char** transformed_value) {
(void)session;
if (transformed_value) *transformed_value = nullptr;
char* end = nullptr;
long num = strtol(value, &end, 10);
if (end == value || *end != '\0') return false;
if (num < params->int_range.min || num > params->int_range.max) return false;
return true;
}
Comment on lines +657 to +665
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing errno check for integer overflow/underflow.

strtol sets errno = ERANGE when the input overflows long, returning LONG_MAX or LONG_MIN. Without checking this, extremely large inputs may pass validation incorrectly if the clamped value falls within the specified range.

Compare with pgsql_variable_validate_maintenance_work_mem at lines 189-194 which properly checks errno.

Proposed fix
 bool pgsql_variable_validate_integer(const char* value, const params_t* params, PgSQL_Session* session, char** transformed_value) {
    (void)session;
    if (transformed_value) *transformed_value = nullptr;
    char* end = nullptr;
+   errno = 0;
    long num = strtol(value, &end, 10);
-   if (end == value || *end != '\0') return false;
+   if (end == value || *end != '\0' || errno == ERANGE) return false;
    if (num < params->int_range.min || num > params->int_range.max) return false;
    return true;
 }
πŸ€– Prompt for AI Agents
In @lib/PgSQL_Variables_Validator.cpp around lines 657 - 665, In
pgsql_variable_validate_integer, set errno = 0 before calling strtol and after
the call check for errno == ERANGE (and optionally that num == LONG_MAX or
LONG_MIN) and return false if overflow/underflow occurred; keep the existing
checks for end == value and *end != '\0' and the range check against
params->int_range.min / params->int_range.max so that extremely large inputs
that clamped to LONG_MAX/LONG_MIN are rejected.


const pgsql_variable_validator pgsql_variable_validator_integer = {
.type = VARIABLE_TYPE_INT,
.validate = &pgsql_variable_validate_integer,
.params = {}
};
Loading