Skip to content

Per-server SSL parameters for PostgreSQL backends#5583

Merged
renecannao merged 19 commits into
v3.0from
v3.0_pgsql_ssl_backend_5582
Apr 9, 2026
Merged

Per-server SSL parameters for PostgreSQL backends#5583
renecannao merged 19 commits into
v3.0from
v3.0_pgsql_ssl_backend_5582

Conversation

@rahim-kanji

@rahim-kanji rahim-kanji commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds per-server SSL configuration for PostgreSQL backends, closing the long-standing gap between the MySQL and PostgreSQL backend SSL stories. Mirrors the existing mysql_servers_ssl_params design as closely as possible so the two protocol sides stay symmetric.

Problem

Until now, every PostgreSQL backend that ProxySQL connects to with use_ssl=1 was forced to share a single global SSL configuration (the pgsql-ssl_p2s_* variables) — one CA, one client cert, one key, one cipher list, one protocol range, for the entire instance. That made it impossible to:

  • run heterogeneous Postgres fleets behind one ProxySQL when the clusters are signed by different CAs (e.g. internal CA + RDS / Cloud SQL / Aurora),
  • use mTLS with per-service or per-tenant client certificates,
  • apply different TLS protocol or cipher policies per backend,
  • configure per-server CRLs.

The MySQL side already solved this with mysql_servers_ssl_params. PostgreSQL had no equivalent.

What this PR adds

A new admin table pgsql_servers_ssl_params, fully integrated into the PgSQL admin → runtime → connection → monitor pipeline.

Schema — keyed by (hostname, port, username) with an empty-username fallback row, exactly like the MySQL table:

hostname, port (default 5432), username,
ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl, ssl_crlpath, ssl_cipher,
ssl_protocol_version_range, comment
PRIMARY KEY (hostname, port, username)

ssl_protocol_version_range accepts either a range (TLSv1.2-TLSv1.3) or a single pin (TLSv1.3), and is mapped to libpq's ssl_min_protocol_version /
ssl_max_protocol_version.

Lookup semantics — exact (host, port, username) match → empty-username fallback for the same (host, port) → falls back to the existing global pgsql-ssl_p2s_*
variables. The override is all-or-nothing per row, matching what the backend connection path actually does (the monitor's earlier per-field fallback was inconsistent and has
been aligned).

Changes

New files

  • include/Servers_SslParams.h — standalone header with the base Servers_SslParams class (virtual destructor) plus MySQLServers_SslParams and PgSQLServers_SslParams
    derived classes. Extracted into its own header to break a circular include between cpp.h, mysql_connection.h, and Base_HostGroups_Manager.h. Removes the duplicate
    definition that previously lived in MySQL_HostGroups_Manager.h.
  • docs/pgsql_servers_ssl_params.md — user documentation: schema, column reference, range/pin format, lookup hierarchy, usage examples, admin commands, prerequisites, notes on
    connection pooling and /* create_new_connection=1 */.

Schema definitions

  • include/PgSQL_HostGroups_Manager.h — adds MYHGM_PgSQL_SERVERS_SSL_PARAMS (HGM-side in-memory table), the PgSQL_Servers_SSL_Params_map + mutex, the
    incoming_pgsql_servers_ssl_params pointer, the private generate_pgsql_servers_ssl_params_table() and the public get_Server_SSL_Params(hostname, port, username).
  • include/ProxySQL_Admin_Tables_Definitions.h — adds ADMIN_SQLITE_TABLE_PGSQL_SERVERS_SSL_PARAMS and ADMIN_SQLITE_TABLE_RUNTIME_PGSQL_SERVERS_SSL_PARAMS (admin-side
    definitions; same schema as the HGM-side, duplicated by the same convention every other pgsql_* table follows).

HostGroups Manager

  • lib/PgSQL_HostGroups_Manager.cpp
    • constructor: creates the new table in mydb alongside the existing pgsql tables.
    • generate_pgsql_servers_ssl_params_table() — populates PgSQL_Servers_SSL_Params_map from the staged incoming rows, mirroring the MySQL implementation.
    • get_Server_SSL_Params() — exact match → empty-username fallback → nullptr.
    • save_incoming_pgsql_table() and dump_table_pgsql() — handle pgsql_servers_ssl_params.
    • commit() — promotes SSL params to runtime after the hostgroup_attributes block.

Connection path

  • lib/PgSQL_Connection.cpp
    • connect_start() — looks up per-server SSL params for the resolved (hostname, port, username), applies all libpq fields if a row is found, otherwise falls back to the
      global pgsql-ssl_p2s_* variables. Parses ssl_protocol_version_range for range vs pin.
    • PgSQL_Backend_Kill_Args constructor — applies the same per-server override after the global init so cancel/terminate connections honor per-server SSL too.

Monitor

  • lib/PgSQL_Monitor.cppmon_srv_t population now consults per-server SSL params first via a small lambda, then falls back to globals. Aligned with the backend connection's
    all-or-nothing behavior (was previously per-field).

Admin plumbing

  • include/proxysql_admin.h — extends incoming_pgsql_servers_t with incoming_pgsql_servers_ssl_params and bumps the constructor from 4 to 5 SQLite3_result* parameters.
  • lib/ProxySQL_Admin.cpp
    • adds pgsql_servers_ssl_params to the pgsql_servers_tablenames vector — without this, LOAD/SAVE PGSQL SERVERS TO/FROM DISK would silently ignore the new table. (Caught
      by code review.)
    • loads SSL params in load_pgsql_servers_to_runtime().
    • dumps SSL params in save_pgsql_servers_runtime_to_database().
    • constructs incoming_pgsql_servers_t with the new parameter.
  • lib/Admin_Bootstrap.cpp — registers pgsql_servers_ssl_params and runtime_pgsql_servers_ssl_params in the admin tables list, and pgsql_servers_ssl_params in the config
    tables list.

Tests

Unit tests — test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp (new, 45 tests)

Covers the standalone class layer and the HGM lookup layer end to end:

  • base-class constructors (string and char* overloads),
  • getMapKey() formatting,
  • derived-class inheritance (both protocols share the same fields and key logic),
  • map storage and retrieval,
  • get_Server_SSL_Params() lookup paths: exact match, empty-username fallback, total miss, copy semantics on the returned object.

Uses test_init_query_processor() before test_init_hostgroups() (GloPTH must exist before commit() is called — discovered the hard way via a segfault).

Integration tests — test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp (new, 31 tests)

Two parts, run against a real ProxySQL connected to a real PostgreSQL backend:

  • Part 1 — Admin CRUD (21 tests): table existence, INSERT/SELECT, PRIMARY KEY enforcement, LOAD PGSQL SERVERS TO RUNTIME, multi-row handling, SAVE/LOAD ... TO/FROM DISK,
    DELETE, UPDATE, default-port behavior.
  • Part 2 — End-to-end SSL (10 tests): baseline SSL connection, runtime promotion, TLS protocol pin failure, override-causes-failure cases, fallback to globals when no
    per-server row exists.

The E2E tests use the /* create_new_connection=1 */ query annotation to force ProxySQL to open a fresh backend connection, bypassing the connection pool — without this, pooled
connections from earlier tests masked the override behavior. (This was the key reliability fix; thanks to the pointer at ProxySQL's own annotation docs.)

Connects via the PgSQL admin port (6132) using libpq, per project convention (PgSQL tests use libpq, never the MySQL client).

Closes #5296
Closes #5582

Summary by CodeRabbit

  • Documentation

    • Added comprehensive guide for per-backend PostgreSQL SSL/TLS parameters: schema, examples, accepted protocol-range formats, valid tokens, lookup order, runtime vs configured behavior, and usage notes.
  • New Features

    • Per-server (host:port:username) PostgreSQL SSL settings (CA/cert/key/CRL, CRL dir, comment).
    • TLS protocol-range/pinning (min/max) for new pooled connections; empty values defer to libpq/global defaults.
    • Admin persistence and runtime tables plus a cluster query for runtime SSL params.
  • Tests

    • New unit and integration TAP tests covering constructors, parsing, CRUD, runtime/disk sync, lookup fallbacks, copying semantics, and TLS pinning effects.

… includes

Servers_SslParams, MySQLServers_SslParams, and PgSQLServers_SslParams
are now in Servers_SslParams.h with minimal dependencies (<string> only).
This avoids the circular include issue between cpp.h, mysql_connection.h,
and Base_HostGroups_Manager.h that caused incomplete type errors.
…r fallback

- Add pgsql_servers_ssl_params to pgsql_servers_tablenames so SAVE/LOAD
  PGSQL SERVERS TO/FROM DISK correctly persists and restores SSL params.
- Fix monitor SSL fallback to use per-server params directly (empty
  fields omitted) instead of per-field fallback to globals, matching
  the backend connection behavior.
Covers table schema, column reference, ssl_protocol_version_range format
(range, pin, empty default), lookup hierarchy, usage examples (basic,
per-user, TLS restriction, multi-server), admin commands, and prerequisites.
@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new pgsql_servers_ssl_params admin/runtime table, in-memory cache, and lookup API; integrates per-server PostgreSQL SSL params (including TLS min/max) into connection and monitor flows, persists runtime/admin variants, updates admin/cluster handlers, and adds unit and integration tests.

Changes

Cohort / File(s) Summary
Docs
docs/pgsql_servers_ssl_params.md
New documentation describing pgsql_servers_ssl_params schema, lookup precedence, TLS token formats, examples, and runtime/disk operations.
Core SSL types
include/Servers_SslParams.h, include/mysql_connection.h
Add Servers_SslParams base, PgSQLServers_SslParams (parses tls range into min/max), and include header where previously forward-declared.
PgSQL hostgroup declarations
include/PgSQL_HostGroups_Manager.h, include/ProxySQL_Admin_Tables_Definitions.h, include/PgSQL_Connection.h, include/proxysql_admin.h
Declare new table macros, add map+mutex for SSL params, incoming result handle, API get_Server_SSL_Params(), generator declaration, and add TLS min/max fields to PgSQL SSL config structures/constructors.
Hostgroup implementation
lib/PgSQL_HostGroups_Manager.cpp, lib/Admin_Bootstrap.cpp
Register new tables at bootstrap, implement generate_pgsql_servers_ssl_params_table(), populate in-memory map, wire into commit/dump/save flows, and include new incoming result routing.
Connection & monitor
lib/PgSQL_Connection.cpp, lib/PgSQL_Monitor.cpp, include/PgSQL_Connection.h
Connection and monitor now consult per-server SSL params (fallback to globals), propagate ssl_min_protocol_version/ssl_max_protocol_version, and update backend-kill SSL handling and cleanup.
Admin persistence & cluster
lib/ProxySQL_Admin.cpp, include/ProxySQL_Cluster.hpp, lib/Admin_Handler.cpp
Persist/load pgsql_servers_ssl_params for admin/runtime, add PROXY_SELECT cluster query for runtime table, and intercept admin cluster query to return runtime data.
Tests & harness
test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp, test/tap/tests/pgsql-servers_ssl_params-t.cpp, test/tap/tests/unit/Makefile, test/tap/groups/groups.json, test/tap/test_helpers/test_globals.cpp
Add unit/integration tests covering constructors, TLS parsing, map lookup (exact/wildcard), admin CRUD, runtime persistence, backend SSL behavior and monitor counters; register tests and enable SQLite URI parsing in test init.
Type cleanup
include/Base_HostGroups_Manager.h, include/MySQL_HostGroups_Manager.h
Remove prior MySQLServers_SslParams declarations (consolidated into new Servers_SslParams.h).

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Admin Interface
    participant HGM as PgSQL_HostGroups_Manager
    participant Map as SSL_Params_Map
    participant Conn as PgSQL_Connection
    participant libpq as libpq

    Admin->>HGM: load/save pgsql_servers_ssl_params (SQLite3_result)
    HGM->>HGM: generate_pgsql_servers_ssl_params_table()
    HGM->>Map: populate (key = hostname:port:username) -> PgSQLServers_SslParams

    Conn->>HGM: get_Server_SSL_Params(hostname, port, username)
    HGM->>Map: lookup by computed key
    Map-->>HGM: return params or NULL
    HGM-->>Conn: return heap copy or NULL

    alt per-server params found
        Note over Conn: override global pgsql-ssl_p2s_* with per-server fields
        Conn->>Conn: include ssl_min_protocol_version / ssl_max_protocol_version if non-empty
    else fallback to globals
        Note over Conn: use global pgsql-ssl_p2s_* values
    end

    Conn->>libpq: PQconnectdb(conninfo with SSL params)
    libpq-->>Conn: connection result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested reviewers

  • renecannao

Poem

🐇 I nibbled through rows, finding each host and key,

Per-server certs hop in, no more one-size-for-me.
Host, port, user — each gets its own little den,
TLS min and max tucked snug — secure dreams again.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Per-server SSL parameters for PostgreSQL backends' accurately summarizes the main change: adding per-server SSL configuration support for PostgreSQL, which is the core feature of this PR.
Linked Issues check ✅ Passed The PR comprehensively addresses both #5296 and #5582 by implementing per-server SSL parameters for PostgreSQL backends with new pgsql_servers_ssl_params table, matching MySQL's mysql_servers_ssl_params parity and supporting distinct CAs, mTLS, per-backend TLS policies, and CRLs.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing per-server PostgreSQL SSL parameters: new headers, schema definitions, connection logic, monitoring integration, admin plumbing, and comprehensive tests. No unrelated refactoring or tangential modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v3.0_pgsql_ssl_backend_5582

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rahim-kanji rahim-kanji changed the title V3.0 pgsql ssl backend 5582 Per-server SSL parameters for PostgreSQL backends Apr 7, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

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 per-server SSL configuration for PostgreSQL backend connections via the new pgsql_servers_ssl_params table, mirroring existing MySQL functionality. The changes include the addition of a Servers_SslParams base class, updates to the PostgreSQL hostgroup manager for parameter lookup, and logic in PgSQL_Connection to apply these settings during connection establishment. Feedback highlights an incorrect constructor implementation in the new SSL params class that fails to initialize members, potential performance overhead from heap allocations during lookups, and fragile parsing logic for TLS version ranges.

Comment thread include/Servers_SslParams.h Outdated
Comment on lines +60 to +62
Servers_SslParams(string _h, int _p, string _u) {
Servers_SslParams(_h, _p, _u, "", "", "", "", "", "", "", "", "");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

This constructor implementation is incorrect. In C++, calling a constructor from the body of another constructor creates a temporary object of that type and immediately destroys it; it does not initialize the current instance's members. You should use a delegating constructor in the initializer list instead.

	Servers_SslParams(string _h, int _p, string _u) : Servers_SslParams(_h, _p, _u, "", "", "", "", "", "", "", "", "") {}

std::lock_guard<std::mutex> lock(PgSQL_Servers_SSL_Params_map_mutex);
auto it = PgSQL_Servers_SSL_Params_map.find(MapKey);
if (it != PgSQL_Servers_SSL_Params_map.end()) {
PgSQLServers_SslParams * PSSP = new PgSQLServers_SslParams(it->second);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The get_Server_SSL_Params method performs a heap allocation (new PgSQLServers_SslParams) for every lookup. Since this is called during the connection establishment phase, it adds unnecessary overhead. Consider returning the object by value or returning a pointer to a persistent object if thread safety can be ensured, although returning by value is likely the cleanest approach here given the small size of the object.

Comment thread lib/PgSQL_Connection.cpp Outdated
Comment on lines +987 to +988
string min_ver = tls_ver.substr(0, dash_pos);
string max_ver = tls_ver.substr(dash_pos + 1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The parsing of ssl_protocol_version_range is fragile. If the string contains a trailing or leading dash (e.g., TLSv1.2-), substr will return an empty string for one of the versions. It would be safer to verify that both min_ver and max_ver are non-empty before appending them to the connection info string.

…groups.json

Renames test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp to
pgsql-servers_ssl_params-t.cpp to drop the duplicated "pgsql-" prefix,
updates the @file header to match, and registers both the integration
test and the existing pgsql_servers_ssl_params_unit-t in
test/tap/groups/groups.json so CI actually runs them. The integration
test joins the same group set used by other PgSQL admin/SSL tests
(legacy-g4 and the four mysql-*-g4 variants); the unit test joins
unit-tests-g1 alongside the other pgsql_*_unit-t entries.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/PgSQL_Connection.cpp (1)

2975-3005: ⚠️ Potential issue | 🟠 Major

The kill path does not honor the same override semantics as connect_start().

Here ssl_config is seeded from the global pgsql_thread___ssl_p2s_* values first, then only non-empty per-server fields overwrite them. That leaks global SSL material into pg_terminate_backend() for rows that intentionally leave fields empty, which is the opposite of the all-or-nothing row semantics used in connect_start(). This path also still drops per-server TLS policy fields like ssl_protocol_version_range, so terminate-connection can use a different TLS configuration than the live backend session.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/PgSQL_Connection.cpp` around lines 2975 - 3005, The kill/terminate path
must match connect_start() semantics: do not pre-seed ssl_config from globals
(pgsql_thread___ssl_p2s_*) and then only overwrite non-empty per-server fields;
instead call PgHGM->get_Server_SSL_Params(hostname, port, username) and if it
returns a params row, replace ssl_config entirely with that row's values
(including empty strings) so per-server rows are all-or-nothing; also copy over
the additional TLS policy fields (e.g., ssl_protocol_version_range and any other
policy members on PgSQLServers_SslParams) into ssl_config so
pg_terminate_backend() uses the same TLS settings as connect_start(). Ensure you
update the logic around ssl_config, PgSQLServers_SslParams usage, and refrain
from using strdup/free on globals before deciding which source to apply.
🧹 Nitpick comments (8)
docs/pgsql_servers_ssl_params.md (1)

79-87: Make the non-merge behavior explicit.

These sections still leave room to read the global pgsql-ssl_p2s_* values as per-column fallbacks after a row match. If the implementation is the all-or-nothing behavior described in the PR, please say that directly here so operators do not create partial rows expecting inheritance.

📝 Suggested wording
-- Empty fields in `pgsql_servers_ssl_params` are omitted from the libpq connection string (libpq defaults apply for those fields).
+- Empty fields in a matched `pgsql_servers_ssl_params` row are omitted from the libpq connection string (libpq defaults apply for those fields).
+- ProxySQL does not merge empty columns from a matched row with `pgsql-ssl_p2s_*`; the global settings are only consulted when no row matches.

Also applies to: 191-193

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/pgsql_servers_ssl_params.md` around lines 79 - 87, Clarify that SSL
parameter lookup is all-or-nothing: when a row matches (either Exact match
(hostname, port, username) or Wildcard fallback (hostname, port, '')), ProxySQL
uses the entire matching row and does not merge or inherit individual columns
from the global pgsql-ssl_p2s_* variables; only if no row matches at all are the
global pgsql-ssl_p2s_* variables applied. Update the Lookup Hierarchy wording
(and the equivalent text near the later pgsql-ssl_p2s_* section) to state this
non-merge behavior explicitly so operators know partial/column-level inheritance
does not occur.
lib/PgSQL_HostGroups_Manager.cpp (1)

3988-3989: Use the project's pthread mutexes for the new SSL params map.

These new synchronization points extend the std::mutex / std::lock_guard pattern, but the repository standard for new synchronization in C++ code is pthread_mutex_*.

As per coding guidelines "Use pthread mutexes for synchronization and std::atomic<> for counters".

Also applies to: 4029-4030

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/PgSQL_HostGroups_Manager.cpp` around lines 3988 - 3989, Replace the
std::mutex/std::lock_guard usage with the project's pthread mutex pattern:
change the PgSQL_Servers_SSL_Params_map_mutex to a pthread_mutex_t (and ensure
pthread.h is included/initialized as the project expects), then replace the
std::lock_guard<std::mutex> lock(...) block around
PgSQL_Servers_SSL_Params_map.clear() with explicit
pthread_mutex_lock(&PgSQL_Servers_SSL_Params_map_mutex) before the clear and
pthread_mutex_unlock(...) after; apply the same change for the analogous block
at the second occurrence (around lines 4029-4030) so both synchronization points
use pthread_mutex_* APIs instead of std::mutex.
include/PgSQL_HostGroups_Manager.h (3)

49-49: Use UPPER_SNAKE_CASE for the new table macro name.

MYHGM_PgSQL_SERVERS_SSL_PARAMS breaks the macro naming rule; please rename to MYHGM_PGSQL_SERVERS_SSL_PARAMS for consistency with the enforced convention.

As per coding guidelines, "Constants and macros must use UPPER_SNAKE_CASE."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/PgSQL_HostGroups_Manager.h` at line 49, Rename the macro
MYHGM_PgSQL_SERVERS_SSL_PARAMS to follow UPPER_SNAKE_CASE by changing its
identifier to MYHGM_PGSQL_SERVERS_SSL_PARAMS; update the `#define` that currently
declares the CREATE TABLE string (the macro value stays the same) so all
references to MYHGM_PgSQL_SERVERS_SSL_PARAMS in the codebase compile against the
new macro name and maintain consistency with the project's macro naming
convention.

512-513: Align SSL params cache members with synchronization and naming guidelines.

The new members use std::mutex and non-snake-case member names. Please switch to pthread_mutex_t and snake_case names for both fields.

As per coding guidelines, "Use pthread mutexes for synchronization" and "Member variables must use snake_case."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/PgSQL_HostGroups_Manager.h` around lines 512 - 513, Replace the
std::mutex and non-snake-case member names with pthread mutex and snake_case
names: change PgSQL_Servers_SSL_Params_map_mutex (std::mutex) to pthread_mutex_t
pgsql_servers_ssl_params_map_mutex and change PgSQL_Servers_SSL_Params_map to
pgsql_servers_ssl_params_map (std::unordered_map<std::string,
PgSQLServers_SslParams>); ensure the pthread mutex is properly initialized
(e.g., PTHREAD_MUTEX_INITIALIZER or pthread_mutex_init in the class constructor)
and destroyed (pthread_mutex_destroy in the destructor) where the class that
declares these members is defined.

781-781: Clarify ownership for returned SSL params and standardize to std::unique_ptr for consistency.

This API returns a raw pointer to newly allocated objects, requiring explicit caller cleanup. While current call sites do include cleanup paths (mysql_connection.cpp:970-971, MySQL_Session.cpp:347-350), some have already migrated to std::unique_ptr (MySQL_Monitor.cpp:1579, PgSQL_Monitor.cpp:447, PgSQL_Connection.cpp:968/2982). Standardizing on std::unique_ptr with const char* parameters would make ownership explicit across all callers and prevent accidental leaks in future maintenance.

💡 Suggested API change
- PgSQLServers_SslParams * get_Server_SSL_Params(char *hostname, int port, char *username);
+ std::unique_ptr<PgSQLServers_SslParams> get_Server_SSL_Params(const char *hostname, int port, const char *username);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/PgSQL_HostGroups_Manager.h` at line 781, Change the API so ownership
is explicit: update the declaration of get_Server_SSL_Params to return
std::unique_ptr<PgSQLServers_SslParams> and take const char* for hostname and
username (and keep int port); update the corresponding implementation/definition
to match the new signature and include <memory>; then update all callers (e.g.,
places referenced in mysql_connection.cpp, MySQL_Session.cpp, MySQL_Monitor.cpp,
PgSQL_Monitor.cpp, PgSQL_Connection.cpp) to accept the returned std::unique_ptr,
constructing/consuming it directly or moving it where needed and remove any
manual delete calls.
lib/ProxySQL_Admin.cpp (1)

7718-7760: Consider deduplicating the PgSQL/MySQL SSL-param round-trip logic.

The new pgsql_servers_ssl_params save/load blocks are almost a copy of the existing MySQL *_servers_ssl_params path. Pulling the shared insert/bind/load flow into a small helper would make future schema changes much harder to miss in one protocol path.

Also applies to: 8114-8128

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/ProxySQL_Admin.cpp` around lines 7718 - 7760, The pgsql/mysql SSL param
blocks duplicate the same insert/bind/iterate flow; create a small helper (e.g.,
save_server_ssl_params or dump_and_save_ssl_params) that accepts the destination
table base name ("pgsql_servers_ssl_params" / "mysql_servers_ssl_params"), a
function to obtain the source resultset (e.g., PgHGM->dump_table_pgsql or the
MySQL equivalent), and the admindb prepare/execute helpers; move the
prepare_v2/statement, the loop that uses
proxy_sqlite3_bind_text/proxy_sqlite3_bind_int64, SAFE_SQLITE3_STEP2,
proxy_sqlite3_clear_bindings and proxy_sqlite3_reset into that helper and call
it for both paths (replace the current uses of resultset, dump_table_pgsql, the
prepared StrQuery, and the bind loop with a single helper invocation).
test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp (1)

27-73: Cover the 3-argument constructor too.

The constructor section never exercises Servers_SslParams(string, int, string), so regressions in the default-empty SSL initialization path will still leave this binary green. Add one small case for that overload and bump plan(45) accordingly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp` around lines 27 -
73, Add a test that exercises the 3-argument Servers_SslParams(string, int,
string) constructor (e.g., create Servers_SslParams p("host", 5432, "user")) and
assert that SSL-related members (ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl,
ssl_crlpath, ssl_cipher, tls_version) are default/empty and comment is empty;
place it alongside test_base_constructor_string/test_base_constructor_charptr
(e.g., as test_three_arg_constructor) and update the test plan count from 45 to
46.
include/Servers_SslParams.h (1)

23-23: Rename MapKey to map_key before this API spreads.

This new field is the only member here not using snake_case, so it bakes an avoidable inconsistency into every caller of the shared SSL params type. As per coding guidelines, "**/*.{cpp,h,hpp}: Member variables must use snake_case`".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/Servers_SslParams.h` at line 23, Rename the struct/class member
MapKey to snake_case map_key: update the declaration of MapKey to map_key in
Servers_SslParams (the header member currently declared as "string MapKey"),
then update all uses (constructors, initializers, assignments,
serialization/deserialization, accessors, tests and any caller code) to
reference map_key instead of MapKey to keep naming consistent; ensure any
generated bindings or macros that refer to the old name are also adjusted and
run a build to catch remaining references.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/Servers_SslParams.h`:
- Around line 60-62: The 3-arg constructor currently creates a temporary instead
of delegating, leaving the object uninitialized; replace the body with a
delegating-constructor initializer so the current object is initialized. Change
Servers_SslParams(string _h, int _p, string _u) { Servers_SslParams(...); } to
use constructor delegation: Servers_SslParams(string _h, int _p, string _u) :
Servers_SslParams(_h, _p, _u, "", "", "", "", "", "", "", "", "") {} so the real
12-arg constructor initializes this instance.

In `@lib/PgSQL_Connection.cpp`:
- Around line 967-1004: The per-server SSL columns ssl_capath and ssl_cipher are
never added to the connection string when get_Server_SSL_Params() returns a row;
update the builder in PgSQL_Connection.cpp to check ssl_params->ssl_capath and
ssl_params->ssl_cipher (like the other ssl_* fields) and call
append_conninfo_param(conninfo, "ssl_capath", ...) and
append_conninfo_param(conninfo, "ssl_cipher", ...) when non-empty, and also
ensure the existing fallback branch uses the global
pgsql_thread___ssl_p2s_capath and pgsql_thread___ssl_p2s_cipher variables to
append the same keys when ssl_params is null; refer to ssl_params,
get_Server_SSL_Params, and append_conninfo_param to locate where to add these
checks.

In `@lib/PgSQL_HostGroups_Manager.cpp`:
- Around line 1521-1526: The pgsql_servers_ssl_params table regeneration isn't
folded into the module checksum; update gen_global_pgsql_servers_v2_checksum()
to include pgsql_servers_ssl_params in the checksum computation (alongside
pgsql_replication_hostgroups and pgsql_hostgroup_attributes) so changes to SSL
params affect global_checksum_v2; ensure the function reads/serializes the
pgsql_servers_ssl_params contents the same way other tables are folded (same
ordering and fields) and update any associated comments/tests that assert the
checksum composition (references: gen_global_pgsql_servers_v2_checksum,
pgsql_servers_ssl_params, global_checksum_v2,
generate_pgsql_servers_ssl_params_table).

In `@lib/PgSQL_Monitor.cpp`:
- Around line 443-470: The monitor path is discarding per-server TLS version
info; update the lambda that returns mon_srv_t::ssl_opts_t to include
ssl_params->tls_version when ssl_params is present and propagate the same
default source for non-SSL rows, then extend the mon_srv_t::ssl_opts_t structure
to add a tls_version field and update mon_srv_t::build_conn_str() to parse and
apply tls_version using the same ssl_min_protocol_version /
ssl_max_protocol_version range-parsing and enforcement logic used in
PgSQL_Connection.cpp (reuse the same parsing functions or logic to avoid
divergence).

In `@test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp`:
- Around line 426-441: The test_monitor_ssl_with_per_server_params currently
only toggles the global use_ssl and never inserts a per-server record, so it
doesn't exercise the per-server lookup; update
test_monitor_ssl_with_per_server_params to insert a row into
pgsql_servers_ssl_params for the backend under test (matching host/port or
server id used by the test), setting the per-server use_ssl and any required
ssl_* fields before calling "LOAD PGSQL SERVERS TO RUNTIME" (use exec_ok to run
the INSERT and then the LOAD), then sample PgSQL_Monitor_ssl_connections_OK as
before to verify the counter increases; keep references to cleanup_ssl_params,
pgsql_servers_ssl_params, use_ssl, test_monitor_ssl_with_per_server_params, and
PgSQL_Monitor_ssl_connections_OK so the change is localized and clearly tests
the per-server path.
- Line 449: The TAP plan is one too high—update the planned assertion count from
plan(31) to plan(30) (and similarly adjust the other plan instances around the
478-486 range) so the test harness matches the actual assertions run;
alternatively, if you intended to exercise the monitor, call
test_monitor_ssl_with_per_server_params(a) from main(), but the minimal fix is
to change plan(31) to plan(30) to match the 30 assertions actually executed.
- Around line 286-287: The SELECT queries use existing pooled connections and
must force a fresh backend connection; update the PQexec calls that run "SELECT
1" (e.g., the PGresult* res = PQexec(backend.get(), "SELECT 1") instances in
this test and the similar occurrences around lines 417-418) to include the proxy
hint to create a new connection by prefixing the SQL with "/*
create_new_connection=1 */" so the test validates the just-loaded SSL config
rather than a pooled session.

---

Outside diff comments:
In `@lib/PgSQL_Connection.cpp`:
- Around line 2975-3005: The kill/terminate path must match connect_start()
semantics: do not pre-seed ssl_config from globals (pgsql_thread___ssl_p2s_*)
and then only overwrite non-empty per-server fields; instead call
PgHGM->get_Server_SSL_Params(hostname, port, username) and if it returns a
params row, replace ssl_config entirely with that row's values (including empty
strings) so per-server rows are all-or-nothing; also copy over the additional
TLS policy fields (e.g., ssl_protocol_version_range and any other policy members
on PgSQLServers_SslParams) into ssl_config so pg_terminate_backend() uses the
same TLS settings as connect_start(). Ensure you update the logic around
ssl_config, PgSQLServers_SslParams usage, and refrain from using strdup/free on
globals before deciding which source to apply.

---

Nitpick comments:
In `@docs/pgsql_servers_ssl_params.md`:
- Around line 79-87: Clarify that SSL parameter lookup is all-or-nothing: when a
row matches (either Exact match (hostname, port, username) or Wildcard fallback
(hostname, port, '')), ProxySQL uses the entire matching row and does not merge
or inherit individual columns from the global pgsql-ssl_p2s_* variables; only if
no row matches at all are the global pgsql-ssl_p2s_* variables applied. Update
the Lookup Hierarchy wording (and the equivalent text near the later
pgsql-ssl_p2s_* section) to state this non-merge behavior explicitly so
operators know partial/column-level inheritance does not occur.

In `@include/PgSQL_HostGroups_Manager.h`:
- Line 49: Rename the macro MYHGM_PgSQL_SERVERS_SSL_PARAMS to follow
UPPER_SNAKE_CASE by changing its identifier to MYHGM_PGSQL_SERVERS_SSL_PARAMS;
update the `#define` that currently declares the CREATE TABLE string (the macro
value stays the same) so all references to MYHGM_PgSQL_SERVERS_SSL_PARAMS in the
codebase compile against the new macro name and maintain consistency with the
project's macro naming convention.
- Around line 512-513: Replace the std::mutex and non-snake-case member names
with pthread mutex and snake_case names: change
PgSQL_Servers_SSL_Params_map_mutex (std::mutex) to pthread_mutex_t
pgsql_servers_ssl_params_map_mutex and change PgSQL_Servers_SSL_Params_map to
pgsql_servers_ssl_params_map (std::unordered_map<std::string,
PgSQLServers_SslParams>); ensure the pthread mutex is properly initialized
(e.g., PTHREAD_MUTEX_INITIALIZER or pthread_mutex_init in the class constructor)
and destroyed (pthread_mutex_destroy in the destructor) where the class that
declares these members is defined.
- Line 781: Change the API so ownership is explicit: update the declaration of
get_Server_SSL_Params to return std::unique_ptr<PgSQLServers_SslParams> and take
const char* for hostname and username (and keep int port); update the
corresponding implementation/definition to match the new signature and include
<memory>; then update all callers (e.g., places referenced in
mysql_connection.cpp, MySQL_Session.cpp, MySQL_Monitor.cpp, PgSQL_Monitor.cpp,
PgSQL_Connection.cpp) to accept the returned std::unique_ptr,
constructing/consuming it directly or moving it where needed and remove any
manual delete calls.

In `@include/Servers_SslParams.h`:
- Line 23: Rename the struct/class member MapKey to snake_case map_key: update
the declaration of MapKey to map_key in Servers_SslParams (the header member
currently declared as "string MapKey"), then update all uses (constructors,
initializers, assignments, serialization/deserialization, accessors, tests and
any caller code) to reference map_key instead of MapKey to keep naming
consistent; ensure any generated bindings or macros that refer to the old name
are also adjusted and run a build to catch remaining references.

In `@lib/PgSQL_HostGroups_Manager.cpp`:
- Around line 3988-3989: Replace the std::mutex/std::lock_guard usage with the
project's pthread mutex pattern: change the PgSQL_Servers_SSL_Params_map_mutex
to a pthread_mutex_t (and ensure pthread.h is included/initialized as the
project expects), then replace the std::lock_guard<std::mutex> lock(...) block
around PgSQL_Servers_SSL_Params_map.clear() with explicit
pthread_mutex_lock(&PgSQL_Servers_SSL_Params_map_mutex) before the clear and
pthread_mutex_unlock(...) after; apply the same change for the analogous block
at the second occurrence (around lines 4029-4030) so both synchronization points
use pthread_mutex_* APIs instead of std::mutex.

In `@lib/ProxySQL_Admin.cpp`:
- Around line 7718-7760: The pgsql/mysql SSL param blocks duplicate the same
insert/bind/iterate flow; create a small helper (e.g., save_server_ssl_params or
dump_and_save_ssl_params) that accepts the destination table base name
("pgsql_servers_ssl_params" / "mysql_servers_ssl_params"), a function to obtain
the source resultset (e.g., PgHGM->dump_table_pgsql or the MySQL equivalent),
and the admindb prepare/execute helpers; move the prepare_v2/statement, the loop
that uses proxy_sqlite3_bind_text/proxy_sqlite3_bind_int64, SAFE_SQLITE3_STEP2,
proxy_sqlite3_clear_bindings and proxy_sqlite3_reset into that helper and call
it for both paths (replace the current uses of resultset, dump_table_pgsql, the
prepared StrQuery, and the bind loop with a single helper invocation).

In `@test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp`:
- Around line 27-73: Add a test that exercises the 3-argument
Servers_SslParams(string, int, string) constructor (e.g., create
Servers_SslParams p("host", 5432, "user")) and assert that SSL-related members
(ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl, ssl_crlpath, ssl_cipher,
tls_version) are default/empty and comment is empty; place it alongside
test_base_constructor_string/test_base_constructor_charptr (e.g., as
test_three_arg_constructor) and update the test plan count from 45 to 46.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1818ad6a-bf2a-44fb-a78e-9d99645ecc3a

📥 Commits

Reviewing files that changed from the base of the PR and between d7a26b7 and 8aa3855.

📒 Files selected for processing (16)
  • docs/pgsql_servers_ssl_params.md
  • include/Base_HostGroups_Manager.h
  • include/MySQL_HostGroups_Manager.h
  • include/PgSQL_HostGroups_Manager.h
  • include/ProxySQL_Admin_Tables_Definitions.h
  • include/Servers_SslParams.h
  • include/mysql_connection.h
  • include/proxysql_admin.h
  • lib/Admin_Bootstrap.cpp
  • lib/PgSQL_Connection.cpp
  • lib/PgSQL_HostGroups_Manager.cpp
  • lib/PgSQL_Monitor.cpp
  • lib/ProxySQL_Admin.cpp
  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
  • test/tap/tests/unit/Makefile
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
💤 Files with no reviewable changes (2)
  • include/MySQL_HostGroups_Manager.h
  • include/Base_HostGroups_Manager.h
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: CI-builds / builds (debian12,-dbg)
  • GitHub Check: CI-builds / builds (ubuntu22,-tap)
  • GitHub Check: CI-builds / builds (ubuntu24,-tap-genai-gcov)
  • GitHub Check: run / trigger
  • GitHub Check: claude-review
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{cpp,h,hpp}: Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)
Member variables must use snake_case
Constants and macros must use UPPER_SNAKE_CASE
C++17 is required; use conditional compilation via #ifdef PROXYSQLGENAI, #ifdef PROXYSQL31, etc. for feature flags
Use pthread mutexes for synchronization and std::atomic<> for counters

Files:

  • lib/Admin_Bootstrap.cpp
  • include/ProxySQL_Admin_Tables_Definitions.h
  • include/mysql_connection.h
  • lib/PgSQL_Monitor.cpp
  • lib/PgSQL_Connection.cpp
  • include/proxysql_admin.h
  • lib/PgSQL_HostGroups_Manager.cpp
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
  • include/PgSQL_HostGroups_Manager.h
  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
  • lib/ProxySQL_Admin.cpp
  • include/Servers_SslParams.h
**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Use RAII for resource management and jemalloc for memory allocation

Files:

  • lib/Admin_Bootstrap.cpp
  • lib/PgSQL_Monitor.cpp
  • lib/PgSQL_Connection.cpp
  • lib/PgSQL_HostGroups_Manager.cpp
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
  • lib/ProxySQL_Admin.cpp
lib/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

One class per file is the typical convention

Files:

  • lib/Admin_Bootstrap.cpp
  • lib/PgSQL_Monitor.cpp
  • lib/PgSQL_Connection.cpp
  • lib/PgSQL_HostGroups_Manager.cpp
  • lib/ProxySQL_Admin.cpp
include/**/*.{h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Include guards must follow the pattern #ifndef _CLASS*_H

Files:

  • include/ProxySQL_Admin_Tables_Definitions.h
  • include/mysql_connection.h
  • include/proxysql_admin.h
  • include/PgSQL_HostGroups_Manager.h
  • include/Servers_SslParams.h
test/tap/tests/unit/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h and link against libproxysql.a via the custom test harness

Files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
test/tap/tests/{test_*,*-t}.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Files:

  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
🧠 Learnings (11)
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Admin interface uses SQLite3 backend for SQL-based configuration and schema versions are tracked in ProxySQL_Admin_Tables_Definitions.h

Applied to files:

  • lib/Admin_Bootstrap.cpp
  • docs/pgsql_servers_ssl_params.md
  • include/ProxySQL_Admin_Tables_Definitions.h
  • include/proxysql_admin.h
  • include/PgSQL_HostGroups_Manager.h
  • lib/ProxySQL_Admin.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Feature tiers are controlled by build flags: PROXYSQL31=1 for v3.1.x, PROXYSQLGENAI=1 for v4.0.x; PROXYSQLGENAI=1 implies PROXYSQL31=1

Applied to files:

  • lib/Admin_Bootstrap.cpp
  • include/ProxySQL_Admin_Tables_Definitions.h
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/unit/**/*.cpp : Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h and link against libproxysql.a via the custom test harness

Applied to files:

  • test/tap/tests/unit/Makefile
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
📚 Learning: 2026-04-01T21:27:00.297Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5557
File: test/tap/tests/unit/gtid_set_unit-t.cpp:14-17
Timestamp: 2026-04-01T21:27:00.297Z
Learning: In ProxySQL's unit test directory (test/tap/tests/unit/), test_globals.h and test_init.h are only required for tests that depend on the ProxySQL runtime globals/initialization (i.e., tests that exercise components linked against libproxysql.a). Pure data-structure or utility tests (e.g., ezoption_parser_unit-t.cpp, gtid_set_unit-t.cpp, gtid_trxid_interval_unit-t.cpp) only need tap.h and the relevant project header — omitting test_globals.h and test_init.h is correct and intentional in these cases.

Applied to files:

  • test/tap/tests/unit/Makefile
  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
  • lib/ProxySQL_Admin.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : C++17 is required; use conditional compilation via `#ifdef` PROXYSQLGENAI, `#ifdef` PROXYSQL31, etc. for feature flags

Applied to files:

  • include/ProxySQL_Admin_Tables_Definitions.h
  • include/mysql_connection.h
  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
  • lib/ProxySQL_Admin.cpp
  • include/Servers_SslParams.h
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)

Applied to files:

  • include/mysql_connection.h
  • lib/ProxySQL_Admin.cpp
  • include/Servers_SslParams.h
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : Use pthread mutexes for synchronization and std::atomic<> for counters

Applied to files:

  • lib/PgSQL_Connection.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.cpp : Use RAII for resource management and jemalloc for memory allocation

Applied to files:

  • lib/PgSQL_Connection.cpp
📚 Learning: 2026-04-01T21:27:00.297Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5557
File: test/tap/tests/unit/gtid_set_unit-t.cpp:14-17
Timestamp: 2026-04-01T21:27:00.297Z
Learning: In ProxySQL unit tests under test/tap/tests/unit/, include test_globals.h and test_init.h only for tests that depend on ProxySQL runtime globals/initialization (i.e., tests that exercise components linked against libproxysql.a). For “pure” data-structure/utility tests (e.g., ezoption_parser_unit-t.cpp, gtid_set_unit-t.cpp, gtid_trxid_interval_unit-t.cpp) that do not require runtime globals/initialization, it is correct to omit test_globals.h and test_init.h and instead include only tap.h plus the relevant project header(s).

Applied to files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/{test_*,*-t}.cpp : Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Applied to files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
📚 Learning: 2026-01-20T09:34:19.124Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:39-48
Timestamp: 2026-01-20T09:34:19.124Z
Learning: In ProxySQL's TAP test suite, resource leaks (e.g., not calling mysql_close() on early return paths) are commonly tolerated because test processes are short-lived and OS frees resources on exit. This pattern applies to all C++ test files under test/tap/tests. When reviewing, recognize this as a project-wide test convention and focus on test correctness and isolation rather than insisting on fixing such leaks in these test files.

Applied to files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
  • test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp
🪛 Clang (14.0.6)
test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp

[error] 7-7: 'tap.h' file not found

(clang-diagnostic-error)

test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp

[error] 11-11: 'unistd.h' file not found

(clang-diagnostic-error)

include/Servers_SslParams.h

[error] 4-4: 'string' file not found

(clang-diagnostic-error)

🪛 Cppcheck (2.20.0)
test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp

[error] 149-149: Common realloc mistake

(memleakOnRealloc)


[warning] 86-86: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)


[warning] 31-31: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)


[warning] 138-138: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)

🔇 Additional comments (7)
include/ProxySQL_Admin_Tables_Definitions.h (1)

318-320: Schema split is consistent with the rest of the admin/runtime tables.

The new persisted and runtime definitions mirror the existing SSL params shape cleanly, which should keep LOAD/SAVE handling predictable.

include/proxysql_admin.h (1)

206-210: incoming_pgsql_servers_t is plumbed cleanly.

Adding the extra resultset handle to both the struct and constructor keeps the new table bundled with the rest of the PgSQL server snapshot, and stale call sites will fail loudly at compile time.

lib/Admin_Bootstrap.cpp (1)

820-821: Bootstrap registration looks complete.

Registering the table in both tables_defs_admin and tables_defs_config covers the runtime activation and disk persistence paths.

Also applies to: 847-847

test/tap/tests/unit/Makefile (1)

291-292: Good to have the new unit test in the default target.

Wiring pgsql_servers_ssl_params_unit-t into UNIT_TESTS keeps the new SSL lookup coverage in the normal unit-test build.

lib/PgSQL_HostGroups_Manager.cpp (1)

2925-2939: No action needed. The member variable incoming_pgsql_servers_ssl_params is properly initialized with an in-class initializer = nullptr in the class declaration (PgSQL_HostGroups_Manager.h, line 564), so the code at lines 2925–2939 is safe.

			> Likely an incorrect or invalid review comment.
include/PgSQL_HostGroups_Manager.h (1)

562-564: Good defensive initialization for incoming SSL params resultset.

Declaring the generator and initializing incoming_pgsql_servers_ssl_params to nullptr is clean and safe.

lib/ProxySQL_Admin.cpp (1)

149-157: Good wiring for the new PgSQL SSL params table.

Adding pgsql_servers_ssl_params to the generic PgSQL server table set and threading incoming_pgsql_servers_ssl_params through incoming_pgsql_servers_t keeps the disk/main copy helpers and the explicit runtime load path aligned with the existing MySQL flow.

Also applies to: 886-897

Comment thread include/Servers_SslParams.h Outdated
Comment thread lib/PgSQL_Connection.cpp
Comment on lines +967 to +1004
std::unique_ptr<PgSQLServers_SslParams> ssl_params {
PgHGM->get_Server_SSL_Params(parent->address, parent->port, userinfo->username)
};
if (ssl_params != nullptr) {
// Use per-server SSL params
if (ssl_params->ssl_key.length() > 0)
append_conninfo_param(conninfo, "sslkey", (char*)ssl_params->ssl_key.c_str());
if (ssl_params->ssl_cert.length() > 0)
append_conninfo_param(conninfo, "sslcert", (char*)ssl_params->ssl_cert.c_str());
if (ssl_params->ssl_ca.length() > 0)
append_conninfo_param(conninfo, "sslrootcert", (char*)ssl_params->ssl_ca.c_str());
if (ssl_params->ssl_crl.length() > 0)
append_conninfo_param(conninfo, "sslcrl", (char*)ssl_params->ssl_crl.c_str());
if (ssl_params->ssl_crlpath.length() > 0)
append_conninfo_param(conninfo, "sslcrldir", (char*)ssl_params->ssl_crlpath.c_str());
// Parse ssl_protocol_version_range (format: "TLSv1.2-TLSv1.3" or "TLSv1.3")
if (ssl_params->tls_version.length() > 0) {
string tls_ver = ssl_params->tls_version;
size_t dash_pos = tls_ver.find('-');
if (dash_pos != string::npos) {
string min_ver = tls_ver.substr(0, dash_pos);
string max_ver = tls_ver.substr(dash_pos + 1);
append_conninfo_param(conninfo, "ssl_min_protocol_version", (char*)min_ver.c_str());
append_conninfo_param(conninfo, "ssl_max_protocol_version", (char*)max_ver.c_str());
} else {
// Single version = pin to that version
append_conninfo_param(conninfo, "ssl_min_protocol_version", (char*)tls_ver.c_str());
append_conninfo_param(conninfo, "ssl_max_protocol_version", (char*)tls_ver.c_str());
}
}
} else {
// Fall back to global SSL settings
append_conninfo_param(conninfo, "sslkey", pgsql_thread___ssl_p2s_key);
append_conninfo_param(conninfo, "sslcert", pgsql_thread___ssl_p2s_cert);
append_conninfo_param(conninfo, "sslrootcert", pgsql_thread___ssl_p2s_ca);
append_conninfo_param(conninfo, "sslcrl", pgsql_thread___ssl_p2s_crl);
append_conninfo_param(conninfo, "sslcrldir", pgsql_thread___ssl_p2s_crlpath);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

ssl_capath and ssl_cipher are silently ignored on the main connect path.

Once get_Server_SSL_Params() finds a row, global fallback is disabled, but this builder still never consumes the per-server ssl_capath and ssl_cipher columns. A row that only sets either of those values becomes a no-op on the actual backend connection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/PgSQL_Connection.cpp` around lines 967 - 1004, The per-server SSL columns
ssl_capath and ssl_cipher are never added to the connection string when
get_Server_SSL_Params() returns a row; update the builder in
PgSQL_Connection.cpp to check ssl_params->ssl_capath and ssl_params->ssl_cipher
(like the other ssl_* fields) and call append_conninfo_param(conninfo,
"ssl_capath", ...) and append_conninfo_param(conninfo, "ssl_cipher", ...) when
non-empty, and also ensure the existing fallback branch uses the global
pgsql_thread___ssl_p2s_capath and pgsql_thread___ssl_p2s_cipher variables to
append the same keys when ssl_params is null; refer to ssl_params,
get_Server_SSL_Params, and append_conninfo_param to locate where to add these
checks.

Comment thread lib/PgSQL_HostGroups_Manager.cpp
Comment thread lib/PgSQL_Monitor.cpp
Comment on lines +286 to +287
PGresult* res = PQexec(backend.get(), "SELECT 1");
ok(PQresultStatus(res) == PGRES_TUPLES_OK, "Baseline: SELECT 1 succeeds");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Force a fresh backend connection in these positive-path checks.

Unlike Line 361 and Line 396, these queries do not use /* create_new_connection=1 */. ProxySQL can satisfy them from a pooled backend connection opened under earlier settings, so they can pass without proving the just-loaded SSL config was applied.

🔁 Proposed fix
-		PGresult* res = PQexec(backend.get(), "SELECT 1");
+		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");
...
-		PGresult* res = PQexec(backend.get(), "SELECT 1");
+		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");

Also applies to: 417-418

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-pgsql_servers_ssl_params-t.cpp` around lines 286 - 287,
The SELECT queries use existing pooled connections and must force a fresh
backend connection; update the PQexec calls that run "SELECT 1" (e.g., the
PGresult* res = PQexec(backend.get(), "SELECT 1") instances in this test and the
similar occurrences around lines 417-418) to include the proxy hint to create a
new connection by prefixing the SQL with "/* create_new_connection=1 */" so the
test validates the just-loaded SSL config rather than a pooled session.

Comment thread test/tap/tests/pgsql-servers_ssl_params-t.cpp Outdated
Comment thread test/tap/tests/pgsql-servers_ssl_params-t.cpp Outdated
Calls sqlite3_config(SQLITE_CONFIG_URI, 1) at the top of
test_globals_init(), mirroring src/main.cpp. Without this,
SQLite3DB::open("file:mem_mydb?mode=memory", ...) used by both
HostGroups Manager constructors falls back to literal-filename
behavior in unit tests and creates a stray on-disk file in the
test cwd instead of an in-memory database. The daemon already
sets this flag before any component is constructed; the test
harness now does the same.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
test/tap/tests/pgsql-servers_ssl_params-t.cpp (2)

286-287: ⚠️ Potential issue | 🟠 Major

Force a fresh backend connection in these success-path checks.

These SELECT 1 calls can be satisfied by a pooled backend session, so they do not necessarily prove the just-loaded SSL state was used. Prefix them with /* create_new_connection=1 */ like the negative-path checks.

🔁 Minimal fix
-		PGresult* res = PQexec(backend.get(), "SELECT 1");
+		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");
...
-		PGresult* res = PQexec(backend.get(), "SELECT 1");
+		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");

Also applies to: 417-418

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp` around lines 286 - 287, The
success-path checks calling PQexec via the existing backend connection
(PGresult* res = PQexec(backend.get(), "SELECT 1")) must force a fresh backend
by prefixing the SQL with the same connection-forcing comment used in
negative-path checks; change the call to use "/* create_new_connection=1 */
SELECT 1" so PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1") is
used instead, and apply the same change to the other identical success check
later in the file (the other PQexec(backend.get(), "SELECT 1") occurrence).

426-441: ⚠️ Potential issue | 🟠 Major

The monitor path is still untested.

test_monitor_ssl_with_per_server_params() is never called from main(), and the helper itself clears pgsql_servers_ssl_params and only toggles global use_ssl. Even if you wire it in, it still will not cover the new per-server monitor lookup. Please insert a matching pgsql_servers_ssl_params row for the selected backend, load it to runtime, and then invoke this helper from main().

Also applies to: 478-486

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp` around lines 426 - 441, The
helper test_monitor_ssl_with_per_server_params currently clears
pgsql_servers_ssl_params and only toggles the global use_ssl flag but is never
invoked from main(), so the per-server monitor path is untested; modify the test
to insert a matching row into the pgsql_servers_ssl_params table for the backend
under test (use exec_ok to run an INSERT INTO pgsql_servers_ssl_params ...
referencing the target server), call exec_ok to load those SSL params into
runtime (e.g., "LOAD PGSQL SERVERS SSL_PARAMS TO RUNTIME"), then invoke
test_monitor_ssl_with_per_server_params() from main(); repeat the same
insertion+load+call for the duplicate case referenced around lines 478-486 so
the per-server monitor lookup is exercised for both tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp`:
- Around line 102-122: Add an end-to-end check in
test_per_server_params_promoted_to_runtime() that actually exercises file-based
SSL params: call create_bogus_cert_file() before forcing a new client
connection, configure the server's runtime_pgsql_servers_ssl_params to point
ssl_ca/ssl_cert/ssl_key at BOGUS_CERT_PATH (the strings used by
PgSQL_Connection.cpp), then force a fresh connection (not a reused one) and run
a simple query asserting it fails due to the invalid cert; finally call
remove_bogus_cert_file() to clean up. Ensure the test forces a new connection
instance (so PgSQL_Connection.cpp builds the libpq conninfo) and asserts the
expected failure rather than exiting earlier.

---

Duplicate comments:
In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp`:
- Around line 286-287: The success-path checks calling PQexec via the existing
backend connection (PGresult* res = PQexec(backend.get(), "SELECT 1")) must
force a fresh backend by prefixing the SQL with the same connection-forcing
comment used in negative-path checks; change the call to use "/*
create_new_connection=1 */ SELECT 1" so PQexec(backend.get(), "/*
create_new_connection=1 */ SELECT 1") is used instead, and apply the same change
to the other identical success check later in the file (the other
PQexec(backend.get(), "SELECT 1") occurrence).
- Around line 426-441: The helper test_monitor_ssl_with_per_server_params
currently clears pgsql_servers_ssl_params and only toggles the global use_ssl
flag but is never invoked from main(), so the per-server monitor path is
untested; modify the test to insert a matching row into the
pgsql_servers_ssl_params table for the backend under test (use exec_ok to run an
INSERT INTO pgsql_servers_ssl_params ... referencing the target server), call
exec_ok to load those SSL params into runtime (e.g., "LOAD PGSQL SERVERS
SSL_PARAMS TO RUNTIME"), then invoke test_monitor_ssl_with_per_server_params()
from main(); repeat the same insertion+load+call for the duplicate case
referenced around lines 478-486 so the per-server monitor lookup is exercised
for both tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 06204c9f-25db-4921-8884-c8c3ad03a8bb

📥 Commits

Reviewing files that changed from the base of the PR and between 8aa3855 and 4b2334e.

📒 Files selected for processing (3)
  • test/tap/groups/groups.json
  • test/tap/test_helpers/test_globals.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: CI-builds / builds (debian12,-dbg)
  • GitHub Check: CI-builds / builds (ubuntu22,-tap)
  • GitHub Check: CI-builds / builds (ubuntu24,-tap-genai-gcov)
  • GitHub Check: claude-review
  • GitHub Check: run / trigger
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{cpp,h,hpp}: Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)
Member variables must use snake_case
Constants and macros must use UPPER_SNAKE_CASE
C++17 is required; use conditional compilation via #ifdef PROXYSQLGENAI, #ifdef PROXYSQL31, etc. for feature flags
Use pthread mutexes for synchronization and std::atomic<> for counters

Files:

  • test/tap/test_helpers/test_globals.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Use RAII for resource management and jemalloc for memory allocation

Files:

  • test/tap/test_helpers/test_globals.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
test/tap/tests/{test_*,*-t}.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
🧠 Learnings (10)
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/unit/**/*.cpp : Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h and link against libproxysql.a via the custom test harness

Applied to files:

  • test/tap/test_helpers/test_globals.cpp
  • test/tap/groups/groups.json
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-04-01T21:27:00.297Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5557
File: test/tap/tests/unit/gtid_set_unit-t.cpp:14-17
Timestamp: 2026-04-01T21:27:00.297Z
Learning: In ProxySQL's unit test directory (test/tap/tests/unit/), test_globals.h and test_init.h are only required for tests that depend on the ProxySQL runtime globals/initialization (i.e., tests that exercise components linked against libproxysql.a). Pure data-structure or utility tests (e.g., ezoption_parser_unit-t.cpp, gtid_set_unit-t.cpp, gtid_trxid_interval_unit-t.cpp) only need tap.h and the relevant project header — omitting test_globals.h and test_init.h is correct and intentional in these cases.

Applied to files:

  • test/tap/test_helpers/test_globals.cpp
  • test/tap/groups/groups.json
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : C++17 is required; use conditional compilation via `#ifdef` PROXYSQLGENAI, `#ifdef` PROXYSQL31, etc. for feature flags

Applied to files:

  • test/tap/test_helpers/test_globals.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Feature tiers are controlled by build flags: PROXYSQL31=1 for v3.1.x, PROXYSQLGENAI=1 for v4.0.x; PROXYSQLGENAI=1 implies PROXYSQL31=1

Applied to files:

  • test/tap/test_helpers/test_globals.cpp
  • test/tap/groups/groups.json
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Admin interface uses SQLite3 backend for SQL-based configuration and schema versions are tracked in ProxySQL_Admin_Tables_Definitions.h

Applied to files:

  • test/tap/test_helpers/test_globals.cpp
📚 Learning: 2026-01-20T07:40:34.938Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:24-28
Timestamp: 2026-01-20T07:40:34.938Z
Learning: In ProxySQL test files, calling `mysql_error(NULL)` after `mysql_init()` failure is safe because the MariaDB client library implementation returns an empty string for NULL handles (not undefined behavior).

Applied to files:

  • test/tap/test_helpers/test_globals.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/{test_*,*-t}.cpp : Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-03-26T16:39:02.446Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5548
File: lib/mysql_connection.cpp:1837-1843
Timestamp: 2026-03-26T16:39:02.446Z
Learning: In ProxySQL's lib/mysql_connection.cpp, `SHOW WARNINGS` detection for both `update_warning_count_from_connection()` and the `add_eof()` call in `ASYNC_USE_RESULT_CONT` intentionally uses `myds->sess->CurrentQuery.QueryParserArgs.digest_text` (comment-stripped digest text). This means the fix/feature does not work when `mysql-query_digests_keep_comment=1` (digest_text contains comments) or `mysql-query_digests=0` (digest_text is unavailable) — these configurations are explicitly excluded from the regression test for `reg_test_5306-show_warnings_with_comment-t`. This design is consistent across the codebase and is an accepted, documented limitation.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-02-13T09:29:39.713Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5372
File: test/tap/tap/mcp_client.cpp:355-385
Timestamp: 2026-02-13T09:29:39.713Z
Learning: In ProxySQL MCP implementation (test/tap/tap/mcp_client.cpp), the `check_server()` method uses the ping endpoint which is designed to work without authentication. The `ping` method at the `config` endpoint should not require the `Authorization: Bearer` header, unlike tool invocation endpoints which do require authentication when `auth_token_` is set.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-01-20T09:34:19.124Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:39-48
Timestamp: 2026-01-20T09:34:19.124Z
Learning: In ProxySQL's TAP test suite, resource leaks (e.g., not calling mysql_close() on early return paths) are commonly tolerated because test processes are short-lived and OS frees resources on exit. This pattern applies to all C++ test files under test/tap/tests. When reviewing, recognize this as a project-wide test convention and focus on test correctness and isolation rather than insisting on fixing such leaks in these test files.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
🪛 Clang (14.0.6)
test/tap/tests/pgsql-servers_ssl_params-t.cpp

[error] 11-11: 'unistd.h' file not found

(clang-diagnostic-error)

🔇 Additional comments (1)
test/tap/test_helpers/test_globals.cpp (1)

223-237: Check the return value of sqlite3_config() for error handling.

The stated concern about initialization order in sqlite3db_unit-t.cpp is incorrect—the test correctly calls test_init_minimal() before constructing SQLite3DB(). However, sqlite3_config(SQLITE_CONFIG_URI, 1) in test_globals.cpp at line 237 ignores the return value. Unlike sqlite3-t.cpp which checks for SQLITE_MISUSE, this silently discards configuration failures that could leave URI parsing disabled. Either verify the return value or document why failures are acceptable.

			> Likely an incorrect or invalid review comment.

Comment on lines +102 to +122
/**
* @brief Create a bogus cert file that exists but has invalid content.
*
* libpq will attempt to parse this file and fail with "no start line",
* which proves that per-server SSL params are actually being applied.
* A nonexistent file path is simply ignored by libpq when the backend
* doesn't require client certificates.
*/
static const char* BOGUS_CERT_PATH = "/tmp/proxysql_test_bogus_cert.pem";

static void create_bogus_cert_file() {
FILE* f = fopen(BOGUS_CERT_PATH, "w");
if (f) {
fprintf(f, "this is not a valid certificate\n");
fclose(f);
}
}

static void remove_bogus_cert_file() {
unlink(BOGUS_CERT_PATH);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

The file-based SSL params never get exercised end-to-end.

create_bogus_cert_file() is defined, but test_per_server_params_promoted_to_runtime() stops at runtime_pgsql_servers_ssl_params. If lib/PgSQL_Connection.cpp stopped appending ssl_ca / ssl_cert / ssl_key to libpq conninfo, this test would still pass because the only end-to-end failures here come from ssl_protocol_version_range. Please add a forced new-connection check that uses a readable bogus cert/key path and asserts the query fails.

Also applies to: 294-330

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp` around lines 102 - 122, Add an
end-to-end check in test_per_server_params_promoted_to_runtime() that actually
exercises file-based SSL params: call create_bogus_cert_file() before forcing a
new client connection, configure the server's runtime_pgsql_servers_ssl_params
to point ssl_ca/ssl_cert/ssl_key at BOGUS_CERT_PATH (the strings used by
PgSQL_Connection.cpp), then force a fresh connection (not a reused one) and run
a simple query asserting it fails due to the invalid cert; finally call
remove_bogus_cert_file() to clean up. Ensure the test forces a new connection
instance (so PgSQL_Connection.cpp builds the libpq conninfo) and asserts the
expected failure rather than exiting earlier.

…range

- Drop ssl_capath and ssl_cipher columns (no libpq equivalents)
- Pre-parse ssl_protocol_version_range into ssl_min/max_protocol_version
  at construction time instead of on every backend connection
- Fix Servers_SslParams 3-arg delegating constructor
- Update tests, docs, and all consumers (Connection, Monitor, Kill, Admin)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (2)
test/tap/tests/pgsql-servers_ssl_params-t.cpp (2)

285-288: ⚠️ Potential issue | 🟠 Major

Force a fresh backend on these success-path checks.

Both SELECT 1 calls can be satisfied by an already pooled backend connection, so the test can pass without proving the just-loaded SSL settings were applied. Prefix them with /* create_new_connection=1 */.

🔁 Minimal fix
-		PGresult* res = PQexec(backend.get(), "SELECT 1");
+		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");
...
-		PGresult* res = PQexec(backend.get(), "SELECT 1");
+		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");

Also applies to: 416-420

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp` around lines 285 - 288, The
success-path SELECT 1 checks may use a pooled backend and not verify newly
applied SSL settings; update the PQexec calls that run "SELECT 1" (where
`backend` is used and `PQexec(backend.get(), "SELECT 1")`) to force a fresh
connection by prefixing the query string with the comment "/*
create_new_connection=1 */" (i.e. call PQexec(backend.get(), "/*
create_new_connection=1 */ SELECT 1")); apply the same change to the other
analogous CHECK block around the `SELECT 1` at the later occurrence.

304-330: ⚠️ Potential issue | 🟠 Major

Exercise the file-based SSL params through a real connection.

This helper only proves the row is copied into runtime_pgsql_servers_ssl_params. If the connection path stops forwarding ssl_ca / ssl_cert / ssl_key into libpq conninfo, this test still passes. Use create_bogus_cert_file(), point one of the file params at BOGUS_CERT_PATH, force a fresh backend connection, and assert the query fails.

🧹 Nitpick comments (3)
include/PgSQL_HostGroups_Manager.h (1)

782-782: Make the SSL lookup ownership explicit in the API.

This returns a heap-allocated copy, and the new callers already wrap it in std::unique_ptr. Returning std::unique_ptr<PgSQLServers_SslParams> directly would encode the ownership contract in the type system and remove an easy leak footgun for future callers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/PgSQL_HostGroups_Manager.h` at line 782, Change the API to convey
ownership by returning a smart pointer: modify the declaration of
get_Server_SSL_Params to return std::unique_ptr<PgSQLServers_SslParams> instead
of a raw PgSQLServers_SslParams* (i.e., std::unique_ptr<PgSQLServers_SslParams>
get_Server_SSL_Params(char *hostname, int port, char *username);), update the
corresponding implementation to allocate and return a std::unique_ptr (or use
std::make_unique) and include <memory>, and update all callers to accept the
std::unique_ptr result (removing manual delete/ownership code) so ownership is
explicit in the type system.
lib/PgSQL_Monitor.cpp (1)

446-477: Salt the monitor pool key with the SSL policy.

ssl_opts_t now changes the conninfo, but pooled monitor connections are still reused by addr:port only. That means a runtime CA/cert/TLS-policy change won't take effect until the old pooled connection ages out. Consider including a stable SSL-options fingerprint in the pool key, or flushing mon_conn_pool when SSL params are refreshed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/PgSQL_Monitor.cpp` around lines 446 - 477, The monitor pool key currently
only uses addr:port so SSL changes aren't reflected; modify the mon_conn_pool
keying to include a stable fingerprint derived from mon_srv_t::ssl_opts_t (e.g.,
hash of ssl_key/ssl_cert/ssl_ca/ssl_crl/ssl_crlpath/min/max versions) or,
alternatively, flush relevant entries from mon_conn_pool when SSL params are
refreshed; update the code that builds the pool key (where ssl_opts_t is
constructed) to compute and attach this fingerprint and/or add a hook in the SSL
refresh path to remove connections for that server from mon_conn_pool so new
connections use the updated TLS policy.
include/Servers_SslParams.h (1)

9-23: These exposed names don't match the repo's C++ naming rules.

The new public API introduces Servers_SslParams, MySQLServers_SslParams, PgSQLServers_SslParams, and MapKey, but the repository requires protocol-prefixed class names and snake_case member names. This is easiest to fix before more call sites depend on the current names.

As per coding guidelines "Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)" and "Member variables must use snake_case".

Also applies to: 71-76

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/Servers_SslParams.h` around lines 9 - 23, The public names violate
naming rules: rename class Servers_SslParams and its protocol-specific variants
to include protocol prefixes and PascalCase (e.g., MySQL_SslParams,
PgSQL_SslParams or per repo convention MySQL_SslParams / PgSQL_SslParams), and
convert all public member variables (hostname, port, username, ssl_ca, ssl_cert,
ssl_key, ssl_capath, ssl_crl, ssl_crlpath, ssl_cipher, tls_version, comment,
MapKey) to snake_case (e.g., hostname -> hostname, port -> port, username ->
username, ssl_ca -> ssl_ca, ssl_cert -> ssl_cert, ssl_key -> ssl_key, ssl_capath
-> ssl_ca_path, ssl_crl -> ssl_crl, ssl_crlpath -> ssl_crl_path, ssl_cipher ->
ssl_cipher, tls_version -> tls_version, comment -> comment, MapKey -> map_key)
and update all references; ensure class declarations and any derived/related
classes (MySQLServers_SslParams, PgSQLServers_SslParams) are renamed
consistently to the protocol-prefixed PascalCase form and run a project-wide
refactor to update call sites and headers/forward declarations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/PgSQL_HostGroups_Manager.h`:
- Around line 513-514: Rename the two members to follow snake_case and replace
std::mutex with the project-standard pthread_mutex_t: change
PgSQL_Servers_SSL_Params_map_mutex -> pgsql_servers_ssl_params_map_mutex (type
pthread_mutex_t) and PgSQL_Servers_SSL_Params_map ->
pgsql_servers_ssl_params_map (keep the same unordered_map type), and ensure
pthread_mutex_init is called where the class is constructed and
pthread_mutex_destroy in the destructor (or appropriate init/teardown function)
so callers using pgsql_servers_ssl_params_map_mutex will compile and follow
project conventions.

In `@include/Servers_SslParams.h`:
- Line 23: getMapKey() currently returns a cached MapKey which can become stale
when delimiter or identity fields change; either remove the MapKey member and
compute/return the key on every call in getMapKey(), or implement proper cache
invalidation by storing the delimiter (and/or a generation/version) alongside
MapKey and clearing/updating MapKey whenever hostname, port, or username are
modified; apply the same change to the other cached key usage referenced around
lines 63-67 so the cached value cannot be returned stale.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp`:
- Around line 478-489: The test currently compares ok_after to ok_before but
getMonitorValue() can return -1 on failure, making the assertion vacuously pass;
update the test to first verify both ok_before and ok_after are valid by
checking they are not -1 (e.g., assert ok_before != -1 and ok_after != -1 with a
TAP failure message indicating monitor read failure) and only then perform the
existing ok(ok_after == ok_before, ...) assertion about monitor behavior using
the validated values from getMonitorValue().
- Around line 393-401: The test currently initializes query_failed=true so a
nullptr backend can falsely make the override test pass; change the logic by (1)
adding an explicit ok(backend != nullptr, "createNewConnection(BACKEND) returned
a connection") immediately after obtaining backend to count the connection
assertion, and (2) initialize query_failed=false and only set query_failed =
(PQresultStatus(res) != PGRES_TUPLES_OK) after calling PQexec inside the
existing if (backend) block so a missing backend cannot satisfy the later
ok(query_failed, ...) check; reference createNewConnection, backend,
query_failed, PQexec and the surrounding ok(...) assertion.

In `@test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp`:
- Around line 316-317: The TAP plan count in main() is off by one: update the
plan(...) call (the plan(67) invocation in main) to the correct total of 68 so
the test harness expects all 68 assertions; locate the plan(...) call in the
main function and change its argument from 67 to 68.

---

Duplicate comments:
In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp`:
- Around line 285-288: The success-path SELECT 1 checks may use a pooled backend
and not verify newly applied SSL settings; update the PQexec calls that run
"SELECT 1" (where `backend` is used and `PQexec(backend.get(), "SELECT 1")`) to
force a fresh connection by prefixing the query string with the comment "/*
create_new_connection=1 */" (i.e. call PQexec(backend.get(), "/*
create_new_connection=1 */ SELECT 1")); apply the same change to the other
analogous CHECK block around the `SELECT 1` at the later occurrence.

---

Nitpick comments:
In `@include/PgSQL_HostGroups_Manager.h`:
- Line 782: Change the API to convey ownership by returning a smart pointer:
modify the declaration of get_Server_SSL_Params to return
std::unique_ptr<PgSQLServers_SslParams> instead of a raw PgSQLServers_SslParams*
(i.e., std::unique_ptr<PgSQLServers_SslParams> get_Server_SSL_Params(char
*hostname, int port, char *username);), update the corresponding implementation
to allocate and return a std::unique_ptr (or use std::make_unique) and include
<memory>, and update all callers to accept the std::unique_ptr result (removing
manual delete/ownership code) so ownership is explicit in the type system.

In `@include/Servers_SslParams.h`:
- Around line 9-23: The public names violate naming rules: rename class
Servers_SslParams and its protocol-specific variants to include protocol
prefixes and PascalCase (e.g., MySQL_SslParams, PgSQL_SslParams or per repo
convention MySQL_SslParams / PgSQL_SslParams), and convert all public member
variables (hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_capath,
ssl_crl, ssl_crlpath, ssl_cipher, tls_version, comment, MapKey) to snake_case
(e.g., hostname -> hostname, port -> port, username -> username, ssl_ca ->
ssl_ca, ssl_cert -> ssl_cert, ssl_key -> ssl_key, ssl_capath -> ssl_ca_path,
ssl_crl -> ssl_crl, ssl_crlpath -> ssl_crl_path, ssl_cipher -> ssl_cipher,
tls_version -> tls_version, comment -> comment, MapKey -> map_key) and update
all references; ensure class declarations and any derived/related classes
(MySQLServers_SslParams, PgSQLServers_SslParams) are renamed consistently to the
protocol-prefixed PascalCase form and run a project-wide refactor to update call
sites and headers/forward declarations.

In `@lib/PgSQL_Monitor.cpp`:
- Around line 446-477: The monitor pool key currently only uses addr:port so SSL
changes aren't reflected; modify the mon_conn_pool keying to include a stable
fingerprint derived from mon_srv_t::ssl_opts_t (e.g., hash of
ssl_key/ssl_cert/ssl_ca/ssl_crl/ssl_crlpath/min/max versions) or, alternatively,
flush relevant entries from mon_conn_pool when SSL params are refreshed; update
the code that builds the pool key (where ssl_opts_t is constructed) to compute
and attach this fingerprint and/or add a hook in the SSL refresh path to remove
connections for that server from mon_conn_pool so new connections use the
updated TLS policy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9c5c5ccd-169c-4260-9f7c-62609fd44f38

📥 Commits

Reviewing files that changed from the base of the PR and between 4b2334e and e68f8bb.

📒 Files selected for processing (11)
  • docs/pgsql_servers_ssl_params.md
  • include/PgSQL_Connection.h
  • include/PgSQL_HostGroups_Manager.h
  • include/ProxySQL_Admin_Tables_Definitions.h
  • include/Servers_SslParams.h
  • lib/PgSQL_Connection.cpp
  • lib/PgSQL_HostGroups_Manager.cpp
  • lib/PgSQL_Monitor.cpp
  • lib/ProxySQL_Admin.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
✅ Files skipped from review due to trivial changes (2)
  • docs/pgsql_servers_ssl_params.md
  • include/ProxySQL_Admin_Tables_Definitions.h
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/PgSQL_HostGroups_Manager.cpp
  • lib/ProxySQL_Admin.cpp
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: CI-builds / builds (ubuntu24,-tap-genai-gcov)
  • GitHub Check: CI-builds / builds (ubuntu22,-tap)
  • GitHub Check: CI-builds / builds (debian12,-dbg)
  • GitHub Check: run / trigger
  • GitHub Check: claude-review
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{cpp,h,hpp}: Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)
Member variables must use snake_case
Constants and macros must use UPPER_SNAKE_CASE
C++17 is required; use conditional compilation via #ifdef PROXYSQLGENAI, #ifdef PROXYSQL31, etc. for feature flags
Use pthread mutexes for synchronization and std::atomic<> for counters

Files:

  • include/PgSQL_Connection.h
  • include/PgSQL_HostGroups_Manager.h
  • lib/PgSQL_Connection.cpp
  • lib/PgSQL_Monitor.cpp
  • include/Servers_SslParams.h
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
include/**/*.{h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Include guards must follow the pattern #ifndef _CLASS*_H

Files:

  • include/PgSQL_Connection.h
  • include/PgSQL_HostGroups_Manager.h
  • include/Servers_SslParams.h
**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Use RAII for resource management and jemalloc for memory allocation

Files:

  • lib/PgSQL_Connection.cpp
  • lib/PgSQL_Monitor.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
lib/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

One class per file is the typical convention

Files:

  • lib/PgSQL_Connection.cpp
  • lib/PgSQL_Monitor.cpp
test/tap/tests/{test_*,*-t}.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
test/tap/tests/unit/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h and link against libproxysql.a via the custom test harness

Files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Admin interface uses SQLite3 backend for SQL-based configuration and schema versions are tracked in ProxySQL_Admin_Tables_Definitions.h
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Admin interface uses SQLite3 backend for SQL-based configuration and schema versions are tracked in ProxySQL_Admin_Tables_Definitions.h

Applied to files:

  • include/PgSQL_HostGroups_Manager.h
📚 Learning: 2026-03-26T16:39:02.446Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5548
File: lib/mysql_connection.cpp:1837-1843
Timestamp: 2026-03-26T16:39:02.446Z
Learning: In ProxySQL's lib/mysql_connection.cpp, `SHOW WARNINGS` detection for both `update_warning_count_from_connection()` and the `add_eof()` call in `ASYNC_USE_RESULT_CONT` intentionally uses `myds->sess->CurrentQuery.QueryParserArgs.digest_text` (comment-stripped digest text). This means the fix/feature does not work when `mysql-query_digests_keep_comment=1` (digest_text contains comments) or `mysql-query_digests=0` (digest_text is unavailable) — these configurations are explicitly excluded from the regression test for `reg_test_5306-show_warnings_with_comment-t`. This design is consistent across the codebase and is an accepted, documented limitation.

Applied to files:

  • lib/PgSQL_Connection.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : Use pthread mutexes for synchronization and std::atomic<> for counters

Applied to files:

  • lib/PgSQL_Connection.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.cpp : Use RAII for resource management and jemalloc for memory allocation

Applied to files:

  • lib/PgSQL_Connection.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)

Applied to files:

  • include/Servers_SslParams.h
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : C++17 is required; use conditional compilation via `#ifdef` PROXYSQLGENAI, `#ifdef` PROXYSQL31, etc. for feature flags

Applied to files:

  • include/Servers_SslParams.h
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/unit/**/*.cpp : Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h and link against libproxysql.a via the custom test harness

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
📚 Learning: 2026-04-01T21:27:03.216Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5557
File: test/tap/tests/unit/gtid_set_unit-t.cpp:14-17
Timestamp: 2026-04-01T21:27:03.216Z
Learning: In ProxySQL's unit test directory (test/tap/tests/unit/), test_globals.h and test_init.h are only required for tests that depend on the ProxySQL runtime globals/initialization (i.e., tests that exercise components linked against libproxysql.a). Pure data-structure or utility tests (e.g., ezoption_parser_unit-t.cpp, gtid_set_unit-t.cpp, gtid_trxid_interval_unit-t.cpp) only need tap.h and the relevant project header — omitting test_globals.h and test_init.h is correct and intentional in these cases.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/{test_*,*-t}.cpp : Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
📚 Learning: 2026-02-13T09:29:39.713Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5372
File: test/tap/tap/mcp_client.cpp:355-385
Timestamp: 2026-02-13T09:29:39.713Z
Learning: In ProxySQL MCP implementation (test/tap/tap/mcp_client.cpp), the `check_server()` method uses the ping endpoint which is designed to work without authentication. The `ping` method at the `config` endpoint should not require the `Authorization: Bearer` header, unlike tool invocation endpoints which do require authentication when `auth_token_` is set.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-01-20T09:34:19.124Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:39-48
Timestamp: 2026-01-20T09:34:19.124Z
Learning: In ProxySQL's TAP test suite, resource leaks (e.g., not calling mysql_close() on early return paths) are commonly tolerated because test processes are short-lived and OS frees resources on exit. This pattern applies to all C++ test files under test/tap/tests. When reviewing, recognize this as a project-wide test convention and focus on test correctness and isolation rather than insisting on fixing such leaks in these test files.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
📚 Learning: 2026-04-01T21:27:00.297Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5557
File: test/tap/tests/unit/gtid_set_unit-t.cpp:14-17
Timestamp: 2026-04-01T21:27:00.297Z
Learning: In ProxySQL unit tests under test/tap/tests/unit/, include test_globals.h and test_init.h only for tests that depend on ProxySQL runtime globals/initialization (i.e., tests that exercise components linked against libproxysql.a). For “pure” data-structure/utility tests (e.g., ezoption_parser_unit-t.cpp, gtid_set_unit-t.cpp, gtid_trxid_interval_unit-t.cpp) that do not require runtime globals/initialization, it is correct to omit test_globals.h and test_init.h and instead include only tap.h plus the relevant project header(s).

Applied to files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
🪛 Clang (14.0.6)
include/Servers_SslParams.h

[error] 4-4: 'string' file not found

(clang-diagnostic-error)

test/tap/tests/pgsql-servers_ssl_params-t.cpp

[error] 11-11: 'unistd.h' file not found

(clang-diagnostic-error)

test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp

[error] 7-7: 'tap.h' file not found

(clang-diagnostic-error)

🪛 Cppcheck (2.20.0)
test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp

[error] 149-149: Common realloc mistake

(memleakOnRealloc)


[warning] 86-86: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)


[warning] 31-31: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)


[warning] 138-138: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)

Comment on lines +513 to +514
std::mutex PgSQL_Servers_SSL_Params_map_mutex;
std::unordered_map<std::string, PgSQLServers_SslParams> PgSQL_Servers_SSL_Params_map;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use the project-standard mutex and member naming here.

These new members introduce std::mutex and mixed-case member names in a header. Please switch them to the repository's pthread_mutex_t + snake_case pattern before new call sites and helpers build on top of this shape. As per coding guidelines Member variables must use snake_case and Use pthread mutexes for synchronization and std::atomic<> for counters.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/PgSQL_HostGroups_Manager.h` around lines 513 - 514, Rename the two
members to follow snake_case and replace std::mutex with the project-standard
pthread_mutex_t: change PgSQL_Servers_SSL_Params_map_mutex ->
pgsql_servers_ssl_params_map_mutex (type pthread_mutex_t) and
PgSQL_Servers_SSL_Params_map -> pgsql_servers_ssl_params_map (keep the same
unordered_map type), and ensure pthread_mutex_init is called where the class is
constructed and pthread_mutex_destroy in the destructor (or appropriate
init/teardown function) so callers using pgsql_servers_ssl_params_map_mutex will
compile and follow project conventions.

string ssl_cipher;
string tls_version;
string comment;
string MapKey;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

getMapKey() can return a stale key.

The first call permanently fixes MapKey, but the API still accepts a delimiter and the identity fields remain mutable. A later call with a different del — or a post-construction change to hostname / port / username — returns the wrong key.

Also applies to: 63-67

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/Servers_SslParams.h` at line 23, getMapKey() currently returns a
cached MapKey which can become stale when delimiter or identity fields change;
either remove the MapKey member and compute/return the key on every call in
getMapKey(), or implement proper cache invalidation by storing the delimiter
(and/or a generation/version) alongside MapKey and clearing/updating MapKey
whenever hostname, port, or username are modified; apply the same change to the
other cached key usage referenced around lines 63-67 so the cached value cannot
be returned stale.

Comment on lines +393 to +401
auto backend = createNewConnection(BACKEND);
bool query_failed = true;
if (backend) {
PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");
query_failed = (PQresultStatus(res) != PGRES_TUPLES_OK);
PQclear(res);
}

ok(query_failed,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't let a failed client connection count as a passing override test.

query_failed starts as true, so if createNewConnection(BACKEND) returns nullptr the final assertion still passes without exercising the backend path. Add an explicit ok(backend != nullptr, ...) here; that's also the reason main() is currently one assertion short of plan(34).

✅ Minimal fix
 	auto backend = createNewConnection(BACKEND);
+	ok(backend != nullptr, "Override: client connection to ProxySQL established");
 	bool query_failed = true;
 	if (backend) {
 		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp` around lines 393 - 401, The
test currently initializes query_failed=true so a nullptr backend can falsely
make the override test pass; change the logic by (1) adding an explicit
ok(backend != nullptr, "createNewConnection(BACKEND) returned a connection")
immediately after obtaining backend to count the connection assertion, and (2)
initialize query_failed=false and only set query_failed = (PQresultStatus(res)
!= PGRES_TUPLES_OK) after calling PQexec inside the existing if (backend) block
so a missing backend cannot satisfy the later ok(query_failed, ...) check;
reference createNewConnection, backend, query_failed, PQexec and the surrounding
ok(...) assertion.

Comment on lines +478 to +489
long ok_before = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK");
diag("With TLSv1 per-server pin, ssl OK before wait: %ld", ok_before);

usleep(3000000); // 3 seconds — multiple monitor cycles

long ok_after = getMonitorValue(admin, "PgSQL_Monitor_ssl_connections_OK");
diag("With TLSv1 per-server pin, ssl OK after wait: %ld (delta=%ld)",
ok_after, ok_after - ok_before);

ok(ok_after == ok_before,
"Monitor per-server: SSL OK counter does NOT advance when "
"per-server row pins ssl_protocol_version_range to TLSv1");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fail if the monitor counter cannot be read.

getMonitorValue() returns -1 on query failure. In that case ok_after == ok_before is true and this negative-path assertion passes without proving anything about monitor behavior.

🩹 Preserve a single TAP assertion while rejecting read failures
-	ok(ok_after == ok_before,
+	ok(ok_before >= 0 && ok_after >= 0 && ok_after == ok_before,
 		"Monitor per-server: SSL OK counter does NOT advance when "
 		"per-server row pins ssl_protocol_version_range to TLSv1");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp` around lines 478 - 489, The
test currently compares ok_after to ok_before but getMonitorValue() can return
-1 on failure, making the assertion vacuously pass; update the test to first
verify both ok_before and ok_after are valid by checking they are not -1 (e.g.,
assert ok_before != -1 and ok_after != -1 with a TAP failure message indicating
monitor read failure) and only then perform the existing ok(ok_after ==
ok_before, ...) assertion about monitor behavior using the validated values from
getMonitorValue().

Comment thread test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp Outdated
- Define CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS macro for remote node fetch
- Add Admin_Handler interception so cluster peers can query the table
- Add pgsql_servers_ssl_params to get_current_pgsql_table() lookup
- Checksum computation was already in place via CUCFT1 in commit()
Tests the PROXY_SELECT cluster query via MySQL admin port:
- Inserts SSL params via PgSQL admin, loads to runtime
- Connects to MySQL admin port and executes the cluster query
- Verifies returned row has correct hostname, ssl_ca, and
  ssl_protocol_version_range values

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
test/tap/tests/pgsql-servers_ssl_params-t.cpp (3)

416-425: ⚠️ Potential issue | 🟠 Major

Don't let a failed client connection satisfy the override test.

query_failed starts as true, and there is no assertion that createNewConnection(BACKEND) succeeded. A frontend connect failure therefore makes this negative-path check pass without exercising the backend path; it's also why plan(37) is currently one assertion too high.

💡 Tighten the assertion and fix the plan mismatch at the root cause
 	auto backend = createNewConnection(BACKEND);
-	bool query_failed = true;
+	ok(backend != nullptr, "Override: client connection to ProxySQL established");
+	bool query_failed = false;
 	if (backend) {
 		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");
 		query_failed = (PQresultStatus(res) != PGRES_TUPLES_OK);
 		PQclear(res);
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp` around lines 416 - 425, The
test currently lets a failed createNewConnection(BACKEND) make query_failed
remain true and falsely satisfy the override negative-path; add an explicit
assertion that the backend connection succeeded (e.g. ok(backend, "Connected to
backend for override test")) before executing PQexec, and only compute
query_failed from the PQexec/PQresultStatus path when backend is non-null (or
initialize query_failed to false and set it true on PQexec failure). Also adjust
the test plan count (plan(...)) to remove the spurious passing assertion so the
total assertions match the real checks.

502-513: ⚠️ Potential issue | 🟠 Major

Validate the monitor reads before comparing them.

getMonitorValue() returns -1 on query failure. If both reads fail, ok_after == ok_before still passes without proving that the per-server monitor path was exercised.

💡 Keep this as one TAP assertion
-	ok(ok_after == ok_before,
+	ok(ok_before >= 0 && ok_after >= 0 && ok_after == ok_before,
 		"Monitor per-server: SSL OK counter does NOT advance when "
 		"per-server row pins ssl_protocol_version_range to TLSv1");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp` around lines 502 - 513,
Replace the separate equality check with a single TAP assertion that also
verifies both monitor reads succeeded: ensure you use getMonitorValue to
populate ok_before and ok_after and then assert ok(ok_before != -1 && ok_after
!= -1 && ok_after == ok_before, "Monitor per-server: SSL OK counter does NOT
advance when per-server row pins ssl_protocol_version_range to TLSv1 and monitor
reads succeeded"); keep the diag(...) calls to print ok_before/ok_after for
debugging but change the ok(...) call to reference ok_before, ok_after and
getMonitorValue so failed reads (-1) cause the assertion to fail rather than
silently passing.

111-123: ⚠️ Potential issue | 🟠 Major

Exercise the file-based SSL params end-to-end, not just the runtime table.

create_bogus_cert_file() is never used, and this test stops after asserting that the row landed in runtime_pgsql_servers_ssl_params. If PgSQL_Connection stopped appending ssl_ca/ssl_cert/ssl_key to libpq conninfo, this suite would still pass.

🧪 Minimal extension
 	exec_ok(admin, "LOAD PGSQL SERVERS TO RUNTIME");
 
 	// Verify the params appear in the runtime table for the correct server
 	std::stringstream verify;
@@
 	}
 	PQclear(res);
+
+	create_bogus_cert_file();
+	std::stringstream bad_paths;
+	bad_paths << "UPDATE pgsql_servers_ssl_params SET "
+		"ssl_ca='" << BOGUS_CERT_PATH << "', "
+		"ssl_cert='" << BOGUS_CERT_PATH << "', "
+		"ssl_key='" << BOGUS_CERT_PATH << "' "
+		"WHERE hostname='" << hostname << "' AND port=" << port;
+	exec_ok(admin, bad_paths.str().c_str());
+	exec_ok(admin, "LOAD PGSQL SERVERS TO RUNTIME");
+
+	auto backend = createNewConnection(BACKEND);
+	ok(backend != nullptr, "Per-server file params: client connection to ProxySQL established");
+	if (backend) {
+		PGresult* res = PQexec(backend.get(), "/* create_new_connection=1 */ SELECT 1");
+		ok(PQresultStatus(res) != PGRES_TUPLES_OK,
+			"Per-server file params: bogus ssl_ca/ssl_cert/ssl_key fail end-to-end");
+		PQclear(res);
+	}
+	remove_bogus_cert_file();
 }

Also applies to: 317-353

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/ProxySQL_Cluster.hpp`:
- Around line 49-50: The cluster query macro
CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS currently omits the ssl_capath and
ssl_cipher columns, causing changes to those fields to be ignored; update the
macro so the SELECT from runtime_pgsql_servers_ssl_params includes ssl_capath
and ssl_cipher (in the same ordering scheme as the other ssl fields) so the
fetched rowset/checksum reflects all PgSQL SSL columns stored in
pgsql_servers_ssl_params.

In `@lib/Admin_Handler.cpp`:
- Around line 3453-3464: The code is deleting resultset unconditionally which
frees a shared "current table" snapshot returned by
PgHGM->get_current_pgsql_table(); change the ownership handling to only delete
the fallback dump returned by PgHGM->dump_table_pgsql() while leaving the
resultset returned by get_current_pgsql_table() intact. Specifically, when
calling PgHGM->get_current_pgsql_table("pgsql_servers_ssl_params") keep that
pointer alive (do not delete), but if you had to call
PgHGM->dump_table_pgsql("pgsql_servers_ssl_params") as a fallback, delete that
dump after sess->SQLite3_to_MySQL(...) as the MySQL-path does; update the logic
around resultset, sess->SQLite3_to_MySQL(...), and delete resultset so only the
dump_table_pgsql() result is freed and run_query handling remains correct.

---

Duplicate comments:
In `@test/tap/tests/pgsql-servers_ssl_params-t.cpp`:
- Around line 416-425: The test currently lets a failed
createNewConnection(BACKEND) make query_failed remain true and falsely satisfy
the override negative-path; add an explicit assertion that the backend
connection succeeded (e.g. ok(backend, "Connected to backend for override
test")) before executing PQexec, and only compute query_failed from the
PQexec/PQresultStatus path when backend is non-null (or initialize query_failed
to false and set it true on PQexec failure). Also adjust the test plan count
(plan(...)) to remove the spurious passing assertion so the total assertions
match the real checks.
- Around line 502-513: Replace the separate equality check with a single TAP
assertion that also verifies both monitor reads succeeded: ensure you use
getMonitorValue to populate ok_before and ok_after and then assert ok(ok_before
!= -1 && ok_after != -1 && ok_after == ok_before, "Monitor per-server: SSL OK
counter does NOT advance when per-server row pins ssl_protocol_version_range to
TLSv1 and monitor reads succeeded"); keep the diag(...) calls to print
ok_before/ok_after for debugging but change the ok(...) call to reference
ok_before, ok_after and getMonitorValue so failed reads (-1) cause the assertion
to fail rather than silently passing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c7031fe9-f80c-4de1-9ea7-036784ee69dd

📥 Commits

Reviewing files that changed from the base of the PR and between e68f8bb and ca75d56.

📒 Files selected for processing (4)
  • include/ProxySQL_Cluster.hpp
  • lib/Admin_Handler.cpp
  • lib/PgSQL_HostGroups_Manager.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
✅ Files skipped from review due to trivial changes (1)
  • lib/PgSQL_HostGroups_Manager.cpp
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{cpp,h,hpp}: Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)
Member variables must use snake_case
Constants and macros must use UPPER_SNAKE_CASE
C++17 is required; use conditional compilation via #ifdef PROXYSQLGENAI, #ifdef PROXYSQL31, etc. for feature flags
Use pthread mutexes for synchronization and std::atomic<> for counters

Files:

  • include/ProxySQL_Cluster.hpp
  • lib/Admin_Handler.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
include/**/*.{h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Include guards must follow the pattern #ifndef _CLASS*_H

Files:

  • include/ProxySQL_Cluster.hpp
**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Use RAII for resource management and jemalloc for memory allocation

Files:

  • lib/Admin_Handler.cpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
lib/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

One class per file is the typical convention

Files:

  • lib/Admin_Handler.cpp
test/tap/tests/{test_*,*-t}.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
🧠 Learnings (11)
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : C++17 is required; use conditional compilation via `#ifdef` PROXYSQLGENAI, `#ifdef` PROXYSQL31, etc. for feature flags

Applied to files:

  • include/ProxySQL_Cluster.hpp
  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Feature tiers are controlled by build flags: PROXYSQL31=1 for v3.1.x, PROXYSQLGENAI=1 for v4.0.x; PROXYSQLGENAI=1 implies PROXYSQL31=1

Applied to files:

  • include/ProxySQL_Cluster.hpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)

Applied to files:

  • include/ProxySQL_Cluster.hpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Admin interface uses SQLite3 backend for SQL-based configuration and schema versions are tracked in ProxySQL_Admin_Tables_Definitions.h

Applied to files:

  • include/ProxySQL_Cluster.hpp
  • lib/Admin_Handler.cpp
📚 Learning: 2026-04-01T21:27:03.216Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5557
File: test/tap/tests/unit/gtid_set_unit-t.cpp:14-17
Timestamp: 2026-04-01T21:27:03.216Z
Learning: In ProxySQL's unit test directory (test/tap/tests/unit/), test_globals.h and test_init.h are only required for tests that depend on the ProxySQL runtime globals/initialization (i.e., tests that exercise components linked against libproxysql.a). Pure data-structure or utility tests (e.g., ezoption_parser_unit-t.cpp, gtid_set_unit-t.cpp, gtid_trxid_interval_unit-t.cpp) only need tap.h and the relevant project header — omitting test_globals.h and test_init.h is correct and intentional in these cases.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/unit/**/*.cpp : Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h and link against libproxysql.a via the custom test harness

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/{test_*,*-t}.cpp : Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-03-26T16:39:02.446Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5548
File: lib/mysql_connection.cpp:1837-1843
Timestamp: 2026-03-26T16:39:02.446Z
Learning: In ProxySQL's lib/mysql_connection.cpp, `SHOW WARNINGS` detection for both `update_warning_count_from_connection()` and the `add_eof()` call in `ASYNC_USE_RESULT_CONT` intentionally uses `myds->sess->CurrentQuery.QueryParserArgs.digest_text` (comment-stripped digest text). This means the fix/feature does not work when `mysql-query_digests_keep_comment=1` (digest_text contains comments) or `mysql-query_digests=0` (digest_text is unavailable) — these configurations are explicitly excluded from the regression test for `reg_test_5306-show_warnings_with_comment-t`. This design is consistent across the codebase and is an accepted, documented limitation.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-02-13T09:29:39.713Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5372
File: test/tap/tap/mcp_client.cpp:355-385
Timestamp: 2026-02-13T09:29:39.713Z
Learning: In ProxySQL MCP implementation (test/tap/tap/mcp_client.cpp), the `check_server()` method uses the ping endpoint which is designed to work without authentication. The `ping` method at the `config` endpoint should not require the `Authorization: Bearer` header, unlike tool invocation endpoints which do require authentication when `auth_token_` is set.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-01-20T09:34:19.124Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:39-48
Timestamp: 2026-01-20T09:34:19.124Z
Learning: In ProxySQL's TAP test suite, resource leaks (e.g., not calling mysql_close() on early return paths) are commonly tolerated because test processes are short-lived and OS frees resources on exit. This pattern applies to all C++ test files under test/tap/tests. When reviewing, recognize this as a project-wide test convention and focus on test correctness and isolation rather than insisting on fixing such leaks in these test files.

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
📚 Learning: 2026-01-20T07:40:34.938Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:24-28
Timestamp: 2026-01-20T07:40:34.938Z
Learning: In ProxySQL test files, calling `mysql_error(NULL)` after `mysql_init()` failure is safe because the MariaDB client library implementation returns an empty string for NULL handles (not undefined behavior).

Applied to files:

  • test/tap/tests/pgsql-servers_ssl_params-t.cpp
🪛 Clang (14.0.6)
test/tap/tests/pgsql-servers_ssl_params-t.cpp

[error] 11-11: 'unistd.h' file not found

(clang-diagnostic-error)

Comment on lines +49 to +50
/* @brief Query to be intercepted by 'ProxySQL_Admin' for 'runtime_pgsql_servers_ssl_params'. See top comment for details. */
#define CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS "PROXY_SELECT hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_crl, ssl_crlpath, ssl_protocol_version_range, comment FROM runtime_pgsql_servers_ssl_params ORDER BY hostname, port, username"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Include all PgSQL SSL columns in the cluster query.

This query omits ssl_capath and ssl_cipher, so changes isolated to those fields never affect the fetched resultset/checksum and can be skipped by cluster sync even though pgsql_servers_ssl_params stores them.

💡 Expand the fetched rowset
-#define CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS "PROXY_SELECT hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_crl, ssl_crlpath, ssl_protocol_version_range, comment FROM runtime_pgsql_servers_ssl_params ORDER BY hostname, port, username"
+#define CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS "PROXY_SELECT hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl, ssl_crlpath, ssl_cipher, ssl_protocol_version_range, comment FROM runtime_pgsql_servers_ssl_params ORDER BY hostname, port, username"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* @brief Query to be intercepted by 'ProxySQL_Admin' for 'runtime_pgsql_servers_ssl_params'. See top comment for details. */
#define CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS "PROXY_SELECT hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_crl, ssl_crlpath, ssl_protocol_version_range, comment FROM runtime_pgsql_servers_ssl_params ORDER BY hostname, port, username"
/* `@brief` Query to be intercepted by 'ProxySQL_Admin' for 'runtime_pgsql_servers_ssl_params'. See top comment for details. */
`#define` CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS "PROXY_SELECT hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl, ssl_crlpath, ssl_cipher, ssl_protocol_version_range, comment FROM runtime_pgsql_servers_ssl_params ORDER BY hostname, port, username"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/ProxySQL_Cluster.hpp` around lines 49 - 50, The cluster query macro
CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS currently omits the ssl_capath and
ssl_cipher columns, causing changes to those fields to be ignored; update the
macro so the SELECT from runtime_pgsql_servers_ssl_params includes ssl_capath
and ssl_cipher (in the same ordering scheme as the other ssl fields) so the
fetched rowset/checksum reflects all PgSQL SSL columns stored in
pgsql_servers_ssl_params.

Comment thread lib/Admin_Handler.cpp
Comment on lines +3453 to +3464
GloAdmin->pgsql_servers_wrlock();
resultset = PgHGM->get_current_pgsql_table("pgsql_servers_ssl_params");
GloAdmin->pgsql_servers_wrunlock();

if (resultset == nullptr) {
resultset = PgHGM->dump_table_pgsql("pgsql_servers_ssl_params");
}

if (resultset) {
sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot);
delete resultset;
run_query=false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Don't delete the current-table resultset here.

PgHGM->get_current_pgsql_table() looks like the PgSQL twin of the MySQL path a few lines above, and that path only deletes the dump_table_*() fallback. Unconditionally freeing resultset here can tear down the shared runtime snapshot on the first cluster query and make later reads hit UAF/double-free.

💡 Mirror the existing ownership pattern
 	if (sess->session_type == PROXYSQL_SESSION_ADMIN) {
 		if (!strncasecmp(CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS, query_no_space, strlen(CLUSTER_QUERY_PGSQL_SERVERS_SSL_PARAMS))) {
+			bool owns_resultset = false;
 			GloAdmin->pgsql_servers_wrlock();
 			resultset = PgHGM->get_current_pgsql_table("pgsql_servers_ssl_params");
 			GloAdmin->pgsql_servers_wrunlock();
 
 			if (resultset == nullptr) {
 				resultset = PgHGM->dump_table_pgsql("pgsql_servers_ssl_params");
+				owns_resultset = true;
 			}
 
 			if (resultset) {
 				sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot);
-				delete resultset;
+				if (owns_resultset) {
+					delete resultset;
+				}
 				run_query=false;
 				goto __run_query;
 			}
 		}
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
GloAdmin->pgsql_servers_wrlock();
resultset = PgHGM->get_current_pgsql_table("pgsql_servers_ssl_params");
GloAdmin->pgsql_servers_wrunlock();
if (resultset == nullptr) {
resultset = PgHGM->dump_table_pgsql("pgsql_servers_ssl_params");
}
if (resultset) {
sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot);
delete resultset;
run_query=false;
bool owns_resultset = false;
GloAdmin->pgsql_servers_wrlock();
resultset = PgHGM->get_current_pgsql_table("pgsql_servers_ssl_params");
GloAdmin->pgsql_servers_wrunlock();
if (resultset == nullptr) {
resultset = PgHGM->dump_table_pgsql("pgsql_servers_ssl_params");
owns_resultset = true;
}
if (resultset) {
sess->SQLite3_to_MySQL(resultset, error, affected_rows, &sess->client_myds->myprot);
if (owns_resultset) {
delete resultset;
}
run_query=false;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/Admin_Handler.cpp` around lines 3453 - 3464, The code is deleting
resultset unconditionally which frees a shared "current table" snapshot returned
by PgHGM->get_current_pgsql_table(); change the ownership handling to only
delete the fallback dump returned by PgHGM->dump_table_pgsql() while leaving the
resultset returned by get_current_pgsql_table() intact. Specifically, when
calling PgHGM->get_current_pgsql_table("pgsql_servers_ssl_params") keep that
pointer alive (do not delete), but if you had to call
PgHGM->dump_table_pgsql("pgsql_servers_ssl_params") as a fallback, delete that
dump after sess->SQLite3_to_MySQL(...) as the MySQL-path does; update the logic
around resultset, sess->SQLite3_to_MySQL(...), and delete resultset so only the
dump_table_pgsql() result is freed and run_query handling remains correct.

parse_tls_version() silently discarded partially-specified ranges like
"TLSv1.2-" or "-TLSv1.3", leaving both min and max empty. This meant
the user's intent (e.g. "at least TLSv1.2") was lost without any
indication. Now one-sided ranges set the specified bound and leave the
other side to libpq defaults. A bare "-" logs a proxy_warning.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
include/Servers_SslParams.h (2)

24-41: Consider passing strings by const reference to avoid copies.

Constructors take string parameters by value, causing an extra copy when callers pass lvalues. Using const string& (or string_view in C++17) avoids this overhead.

♻️ Suggested change for one constructor (apply similarly to others)
-	Servers_SslParams(string _h, int _p, string _u,
-		string ca, string cert, string key, string capath,
-		string crl, string crlpath, string cipher, string tls,
-		string c) {
+	Servers_SslParams(const string& _h, int _p, const string& _u,
+		const string& ca, const string& cert, const string& key, const string& capath,
+		const string& crl, const string& crlpath, const string& cipher, const string& tls,
+		const string& c) {

Also applies to: 42-59, 89-100

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/Servers_SslParams.h` around lines 24 - 41, The Servers_SslParams
constructor (the one taking parameters _h, _p, _u, ca, cert, key, capath, crl,
crlpath, cipher, tls, c) takes many std::string parameters by value causing
unnecessary copies; change those string parameters to const std::string& (or
std::string_view if you prefer C++17) and apply the same change to the other
Servers_SslParams overloads/constructors referenced elsewhere so all string
inputs are passed by const reference to avoid copies while keeping assignments
to members (e.g., hostname, ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl,
ssl_crlpath, ssl_cipher, tls_version, comment, MapKey) unchanged.

119-120: Implicit dependency on proxy logging header.

proxy_warning is used here but Servers_SslParams.h doesn't include the header that defines it. Any translation unit including this header must ensure the proxy logging macros are available beforehand.

💡 Consider adding forward declaration or include

Either add an include for the header defining proxy_warning, or add a forward declaration/comment documenting the prerequisite:

 `#include` <string>
+
+// Requires proxy logging macros (proxy_warning) to be available;
+// include "proxysql.h" or equivalent before this header.

Alternatively, move parse_tls_version() out-of-line into a .cpp file.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/Servers_SslParams.h` around lines 119 - 120, The header uses
proxy_warning inside parse_tls_version (and references tls_version, hostname,
port) but does not include the header that defines the proxy logging macros,
creating an implicit dependency; fix by either adding an `#include` for the header
that defines proxy_warning to Servers_SslParams.h, or move parse_tls_version
out-of-line into a .cpp and include the logging header there, or add a clear
comment/forward-declaration documenting that any TU including
Servers_SslParams.h must include the proxy logging header first; update
references in parse_tls_version accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@include/Servers_SslParams.h`:
- Around line 24-41: The Servers_SslParams constructor (the one taking
parameters _h, _p, _u, ca, cert, key, capath, crl, crlpath, cipher, tls, c)
takes many std::string parameters by value causing unnecessary copies; change
those string parameters to const std::string& (or std::string_view if you prefer
C++17) and apply the same change to the other Servers_SslParams
overloads/constructors referenced elsewhere so all string inputs are passed by
const reference to avoid copies while keeping assignments to members (e.g.,
hostname, ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl, ssl_crlpath,
ssl_cipher, tls_version, comment, MapKey) unchanged.
- Around line 119-120: The header uses proxy_warning inside parse_tls_version
(and references tls_version, hostname, port) but does not include the header
that defines the proxy logging macros, creating an implicit dependency; fix by
either adding an `#include` for the header that defines proxy_warning to
Servers_SslParams.h, or move parse_tls_version out-of-line into a .cpp and
include the logging header there, or add a clear comment/forward-declaration
documenting that any TU including Servers_SslParams.h must include the proxy
logging header first; update references in parse_tls_version accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f874b392-a406-46ca-b303-048fe9ef2584

📥 Commits

Reviewing files that changed from the base of the PR and between ca75d56 and 49553cf.

📒 Files selected for processing (3)
  • docs/pgsql_servers_ssl_params.md
  • include/Servers_SslParams.h
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
✅ Files skipped from review due to trivial changes (1)
  • docs/pgsql_servers_ssl_params.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{cpp,h,hpp}: Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)
Member variables must use snake_case
Constants and macros must use UPPER_SNAKE_CASE
C++17 is required; use conditional compilation via #ifdef PROXYSQLGENAI, #ifdef PROXYSQL31, etc. for feature flags
Use pthread mutexes for synchronization and std::atomic<> for counters

Files:

  • include/Servers_SslParams.h
  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
include/**/*.{h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Include guards must follow the pattern #ifndef _CLASS*_H

Files:

  • include/Servers_SslParams.h
**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Use RAII for resource management and jemalloc for memory allocation

Files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
test/tap/tests/unit/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h and link against libproxysql.a via the custom test harness

Files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
🧠 Learnings (6)
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)

Applied to files:

  • include/Servers_SslParams.h
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to **/*.{cpp,h,hpp} : C++17 is required; use conditional compilation via `#ifdef` PROXYSQLGENAI, `#ifdef` PROXYSQL31, etc. for feature flags

Applied to files:

  • include/Servers_SslParams.h
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/unit/**/*.cpp : Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h and link against libproxysql.a via the custom test harness

Applied to files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
📚 Learning: 2026-03-22T14:38:16.093Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T14:38:16.093Z
Learning: Applies to test/tap/tests/{test_*,*-t}.cpp : Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp

Applied to files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
📚 Learning: 2026-04-01T21:27:00.297Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5557
File: test/tap/tests/unit/gtid_set_unit-t.cpp:14-17
Timestamp: 2026-04-01T21:27:00.297Z
Learning: In ProxySQL unit tests under test/tap/tests/unit/, include test_globals.h and test_init.h only for tests that depend on ProxySQL runtime globals/initialization (i.e., tests that exercise components linked against libproxysql.a). For “pure” data-structure/utility tests (e.g., ezoption_parser_unit-t.cpp, gtid_set_unit-t.cpp, gtid_trxid_interval_unit-t.cpp) that do not require runtime globals/initialization, it is correct to omit test_globals.h and test_init.h and instead include only tap.h plus the relevant project header(s).

Applied to files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
📚 Learning: 2026-01-20T09:34:19.124Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:39-48
Timestamp: 2026-01-20T09:34:19.124Z
Learning: In ProxySQL's TAP test suite, resource leaks (e.g., not calling mysql_close() on early return paths) are commonly tolerated because test processes are short-lived and OS frees resources on exit. This pattern applies to all C++ test files under test/tap/tests. When reviewing, recognize this as a project-wide test convention and focus on test correctness and isolation rather than insisting on fixing such leaks in these test files.

Applied to files:

  • test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp
🪛 Clang (14.0.6)
include/Servers_SslParams.h

[error] 4-4: 'string' file not found

(clang-diagnostic-error)

test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp

[error] 7-7: 'tap.h' file not found

(clang-diagnostic-error)

🪛 Cppcheck (2.20.0)
test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp

[error] 149-149: Common realloc mistake

(memleakOnRealloc)


[warning] 86-86: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)


[warning] 31-31: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)


[warning] 138-138: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)

🔇 Additional comments (5)
include/Servers_SslParams.h (1)

63-67: getMapKey() can return a stale key.

The cached MapKey is built with the first delimiter and never invalidated. Subsequent calls with a different delimiter return the originally-cached value. Since identity fields are public and mutable, changes after construction also go unnoticed.

test/tap/tests/unit/pgsql_servers_ssl_params_unit-t.cpp (4)

1-21: LGTM!

The test file correctly includes test_globals.h and test_init.h as required for unit tests that depend on ProxySQL runtime globals. The file naming follows the *-t.cpp pattern, and the structure with section comments is well-organized.


336-337: TAP plan count verified.

The plan(71) correctly matches the total assertion count across all test functions (accounting for conditional ok() and skip() paths).


126-192: Thorough coverage of TLS version parsing edge cases.

Good test coverage for the parse_tls_version() logic including full range, single-token pin, empty input, one-sided ranges (TLSv1.2-, -TLSv1.3), and the malformed bare dash case.


255-330: Well-structured lookup tests with proper cleanup.

The lookup tests correctly verify exact match, username fallback, miss behavior, copy semantics, and cross-host retrieval. Memory management is handled properly with delete calls on returned pointers, and skip() is used appropriately for conditional test paths.

@sonarqubecloud

sonarqubecloud Bot commented Apr 9, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
Image 1 Security Hotspot

See analysis details on SonarQube Cloud

@renecannao
renecannao merged commit 7f14bee into v3.0 Apr 9, 2026
5 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants