Skip to content

feat: add Galera wsrep variables and MariaDB SET STATEMENT ... FOR support#5708

Merged
renecannao merged 16 commits into
v3.0from
issue-5686-galera-vars
May 5, 2026
Merged

feat: add Galera wsrep variables and MariaDB SET STATEMENT ... FOR support#5708
renecannao merged 16 commits into
v3.0from
issue-5686-galera-vars

Conversation

@renecannao

@renecannao renecannao commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #5686

This PR addresses the two feature requests from issue #5686 as separate, independent commits:

  1. Add wsrep_trx_fragment_size and wsrep_trx_fragment_unit as tracked session variables — ProxySQL now intercepts SET statements for these two Galera variables, tracks them per-session, and synchronizes them to backend connections, following the same pattern as the existing wsrep_sync_wait support.

  2. Support MariaDB SET STATEMENT ... FOR passthrough — ProxySQL now recognizes MariaDB's SET STATEMENT var=val [, ...] FOR statement syntax and forwards it to the backend without locking the hostgroup. Previously, this syntax was unrecognized, triggering unable_to_parse_set_statement() which locked the session to a single hostgroup, causing error 9006 on subsequent queries targeting different hostgroups.


Changes

Commit 1: a5714d56f — wsrep variable tracking

Core changes (follows the wsrep_sync_wait pattern exactly):

File Change
include/proxysql_structs.h Add SQL_WSREP_TRX_FRAGMENT_SIZE and SQL_WSREP_TRX_FRAGMENT_UNIT to mysql_variable_name enum; add two entries to mysql_tracked_variables[] metadata array
lib/MySQL_Session.cpp Add wsrep_trx_fragment_size to mysql_variables_numeric set; add wsrep_trx_fragment_unit to mysql_variables_strings set

No other code changes needed — the existing variable tracking infrastructure handles regex matching, SET parsing, hash tracking, backend synchronization, pool return, and var_absent handling automatically based on the enum/metadata registration.

  • wsrep_trx_fragment_size: numeric variable (quote=false, is_number=true, default "0")
  • wsrep_trx_fragment_unit: string variable (quote=true, is_number=false, default ""). No client-side validation of allowed values (BYTES/ROWS/STATEMENTS) — the backend handles validation, consistent with how wsrep_osu_method handles TOI/RSU.

Test changes:

File Change
test/tap/tests/test_filtered_set_statements-t.cpp Add 2 entries to filtered_set_queries
test/tap/tests/set_testing-t.csv Add 4 new CSV test rows
test/tap/tests/generate_set_session_csv.cpp Add variable definitions for random test generation
test/tap/tests/set_testing.h Add to possible_unknown_variables
test/tap/tests/set_testing-240.h Add to possible_unknown_variables

Commit 2: 0c832e5ce + c4666ae8f — SET STATEMENT ... FOR passthrough

Core change — 5-line detection in lib/MySQL_Session.cpp inserted before the SET parser (after query cleanup, before match_regexes check):

// detect MariaDB SET STATEMENT ... FOR syntax
// pass through to backend without hostgroup locking
if (strncasecmp(nq.c_str(), (char *)"SET STATEMENT ", 14) == 0 && strcasestr(nq.c_str(), (char *)" FOR ")) {
    return false;
}

This returns false (forward to backend) with *lock_hostgroup unchanged (default false), so the session remains free to route to any hostgroup for subsequent queries.

New TAP testtest/tap/tests/test_set_statement_for-t.cpp:

  • Detects MariaDB at runtime, skips on non-MariaDB backends
  • 5 tests: basic execution, result correctness, multi-variable, no hostgroup lock persistence, case-insensitive matching
  • Registered in groups.json (legacy-g2, mysql84-g2, mysql90-g2, mysql95-g2)

How it works

wsrep variable tracking (automatic infrastructure)

When a client sends SET wsrep_trx_fragment_size=1000:

  1. The SET parser matches the variable name via variables_regexp (auto-generated from mysql_tracked_variables[])
  2. The value is hashed and stored on the client-side connection via client_set_value()
  3. An OK packet is returned to the client immediately (no backend traffic)
  4. When a subsequent query needs a backend connection, handler_again___verify_multiple_variables() compares client/server hashes and sends SET wsrep_trx_fragment_size=1000 to the backend if they differ
  5. On pool return, variable state is preserved; on next reuse, only changed variables are re-synchronized

SET STATEMENT ... FOR (passthrough)

When a client sends SET STATEMENT max_statement_time=60 FOR SELECT 1:

  1. ProxySQL detects the SET STATEMENT ... FOR pattern before the SET parser
  2. The entire query is forwarded to the backend as-is (MariaDB handles the temporary variable scoping natively)
  3. No hostgroup lock is set — subsequent queries can route to any hostgroup
  4. No variable tracking is needed since SET STATEMENT variables are temporary (scoped to the single statement)

Test plan

  • Build: make clean && make — verify compilation (enum ordering assertion in MySQL_Variables.cpp validates at startup)
  • Existing SET tests pass: make build_tap_tests && WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=mysql84-g2 test/infra/control/run-tests-isolated.bash
  • New test on MariaDB: make build_tap_tests && WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=legacy-g2 test/infra/control/run-tests-isolated.bash
  • Manual: SET wsrep_trx_fragment_size=1000; SELECT @@wsrep_trx_fragment_size; on a Galera cluster
  • Manual: SET STATEMENT max_statement_time=60 FOR SELECT 1; followed by SELECT 1; against a different hostgroup — no error 9006

Summary by CodeRabbit

  • New Features

    • Allow MariaDB "SET STATEMENT ... FOR" statements to pass through to the backend without triggering hostgroup locking.
    • Recognize and apply two additional Galera/wsrep session variables: wsrep_trx_fragment_size and wsrep_trx_fragment_unit.
  • Tests

    • Added integration and unit test coverage for SET STATEMENT passthrough and the new wsrep variables; test generators and harness updated accordingly.

renecannao added 3 commits May 1, 2026 18:22
… variable tracking

Add support for two additional Galera wsrep session-level variables
that can be set by clients through ProxySQL:

- wsrep_trx_fragment_size (numeric): controls transaction fragmentation size
- wsrep_trx_fragment_unit (string): controls fragmentation unit (BYTES/ROWS/STATEMENTS)

These follow the same tracking pattern as the existing wsrep_sync_wait
variable. ProxySQL intercepts SET statements for these variables,
tracks them per-session, and synchronizes them to backend connections
when needed.

Changes:
- Add SQL_WSREP_TRX_FRAGMENT_SIZE and SQL_WSREP_TRX_FRAGMENT_UNIT
  to mysql_variable_name enum in proxysql_structs.h
- Add metadata entries in mysql_tracked_variables[] array
- Add to classification sets (mysql_variables_numeric and
  mysql_variables_strings) in MySQL_Session.cpp
- Update test infrastructure: filtered_set_statements test,
  set_testing-t.csv, generate_set_session_csv.cpp, and
  possible_unknown_variables in set_testing headers

Ref: sub-issue 1 of #5686
ProxySQL now recognizes MariaDB's SET STATEMENT ... FOR syntax and
forwards it to the backend without locking the hostgroup.

Previously, this syntax was unrecognized and triggered
unable_to_parse_set_statement(), which locked the session to a single
hostgroup. This caused error 9006 on subsequent queries targeting
different hostgroups.

The implementation is a minimal passthrough: ProxySQL detects the
"SET STATEMENT <vars> FOR <query>" pattern, forwards the query as-is
to the backend, and does not lock the hostgroup. Variable tracking is
not needed since SET STATEMENT variables are temporary (scoped to the
single statement execution).

Changes:
- Add SET STATEMENT ... FOR detection in MySQL_Session.cpp before the
  SET parser, returning false without lock_hostgroup
- Add new TAP test (test_set_statement_for-t.cpp) that verifies:
  - Basic SET STATEMENT ... FOR succeeds
  - Multi-variable SET STATEMENT ... FOR succeeds
  - No hostgroup lock persists after execution
  - Case-insensitive matching works
- Register test in groups.json (legacy-g2, mysql84-g2, etc.)

Ref: sub-issue 2 of #5686
Rewrite test_set_statement_for-t.cpp with:
- Clear diag() output explaining what each test does and why
- Explicit description of the bug being tested (hostgroup lock)
- Verify the query returns the correct result, not just succeeds
- 5 tests: basic, result correctness, multi-variable, no-lock,
  case-insensitive
@coderabbitai

coderabbitai Bot commented May 1, 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 two wsrep session variables to ProxySQL's tracked variables and allowlists, updates session parsing to bypass hostgroup locking for MariaDB SET STATEMENT ... FOR queries, and extends tests and test data to cover the new variables and passthrough behavior.

Changes

wsrep variable tracking + SET STATEMENT passthrough

Layer / File(s) Summary
Data Shape
include/proxysql_structs.h
Adds SQL_WSREP_TRX_FRAGMENT_SIZE and SQL_WSREP_TRX_FRAGMENT_UNIT to mysql_variable_name and corresponding mysql_tracked_variables[] entries (wsrep_trx_fragment_size default "0", wsrep_trx_fragment_unit default "").
Core Implementation
lib/MySQL_Session.cpp
Adds wsrep_trx_fragment_size to the numeric allowlist and wsrep_trx_fragment_unit to the string allowlist. Detects MariaDB SET STATEMENT ... FOR form and returns early to bypass hostgroup-locking/variable-parsing so the statement is forwarded unchanged.
Wiring / Integration
test/tap/groups/groups.json
Registers new integration test group key test_set_statement_for-t into the test matrix.
Tests / Test Data
test/tap/tests/generate_set_session_csv.cpp, test/tap/tests/set_testing.h, test/tap/tests/set_testing-240.h, test/tap/tests/test_filtered_set_statements-t.cpp
Extends variable pools, possible_unknown_variables, filtered query lists, and CSV generator to include wsrep_trx_fragment_size and wsrep_trx_fragment_unit.
New Integration Test
test/tap/tests/test_set_statement_for-t.cpp
Adds TAP test that detects MariaDB backends and verifies SET STATEMENT ... FOR passthrough for single and multiple variables, case-insensitive variants, and that no hostgroup lock persists for subsequent queries.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Proxy as ProxySQL
    participant DB as MariaDB

    Client->>Proxy: SET STATEMENT max_statement_time=60 FOR SELECT 1
    Proxy->>Proxy: Detect "SET STATEMENT ... FOR"
    Proxy->>Proxy: Skip hostgroup lock & variable parsing
    Proxy->>DB: Forward query unchanged
    DB-->>Proxy: Result
    Proxy-->>Client: Result

    Client->>Proxy: SELECT 1
    Proxy->>Proxy: Normal processing (no lock)
    Proxy->>DB: Forward to appropriate hostgroup
    DB-->>Proxy: Result
    Proxy-->>Client: Result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I found two wsrep names to store,
Size and unit hopped through the door.
SET STATEMENT skips the chain and race,
Forwards cleanly, leaves no trace.
A happy rabbit twitches its nose.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.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 Title accurately summarizes the two main changes: adding Galera wsrep variable support and MariaDB SET STATEMENT ... FOR passthrough.
Linked Issues check ✅ Passed All objectives from issue #5686 are implemented: wsrep_trx_fragment_size and wsrep_trx_fragment_unit tracking added, SET STATEMENT ... FOR passthrough enabled to prevent hostgroup locking.
Out of Scope Changes check ✅ Passed All changes directly support the two objectives: wsrep variable tracking, SET STATEMENT passthrough, and corresponding test infrastructure updates with no unrelated modifications.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-5686-galera-vars

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.

@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 support for MariaDB's SET STATEMENT ... FOR syntax, ensuring these queries are passed to the backend without hostgroup locking. Additionally, it adds tracking and comprehensive testing for the wsrep_trx_fragment_size and wsrep_trx_fragment_unit variables. The review feedback suggests removing redundant C-style casts on string literals for better C++ idiomaticity and correcting a typo in a date tag within the new test file.

Comment thread lib/MySQL_Session.cpp
}
// detect MariaDB SET STATEMENT ... FOR syntax
// pass through to backend without hostgroup locking
if (strncasecmp(nq.c_str(), (char *)"SET STATEMENT ", 14) == 0 && strcasestr(nq.c_str(), (char *)" FOR ")) {

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 C-style casts (char *) on string literals are unnecessary and not idiomatic C++. String literals are already const char*, which is the type expected by strncasecmp and strcasestr. Removing these casts will make the code cleaner and more correct according to modern C++ standards.

if (strncasecmp(nq.c_str(), "SET STATEMENT ", 14) == 0 && strcasestr(nq.c_str(), " FOR ")) {

*
* All tests are skipped on non-MariaDB backends.
*
* @date 2026-05-01

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 date in the @date tag is set to the future (2026). This appears to be a typo and should be corrected to the current date of creation.

@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: 3

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

Inline comments:
In `@lib/MySQL_Session.cpp`:
- Around line 7463-7467: The current check in MySQL_Session.cpp uses exact-space
string checks on nq (the normalized query) which misses variants with
tabs/newlines or multiple spaces; update the detection logic in the block that
checks nq (the strncasecmp(... "SET STATEMENT ", 14) and strcasestr(... " FOR
")) to match whitespace more flexibly—either normalize consecutive whitespace in
nq to single spaces before testing or use a regex that matches "SET" \s+
"STATEMENT" and a later \s+ "FOR" (case-insensitive); ensure the function that
returns false for these matches (the SET STATEMENT ... FOR passthrough branch)
still executes when any whitespace variant is present.

In `@test/tap/tests/test_set_statement_for-t.cpp`:
- Around line 131-143: The current test uses mysql_query(proxysql, "SELECT 1 AS
no_lock_test") which can succeed even if the session is still pinned, so replace
the simple SELECT with a query that is guaranteed to route to a different
hostgroup (or assert the session's routing directly) to prove the hostgroup lock
was cleared; update the test around unable_to_parse_set_statement() to run a
cross-hostgroup query (one that requires the alternate hostgroup) or call the
session routing-check helper in the test harness instead of SELECT 1, and keep
using mysql_query(proxysql, ...) and the existing ok()/diag() checks to validate
success.
🪄 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: 47cdaf8e-f7f5-4f34-bd98-400b06267c73

📥 Commits

Reviewing files that changed from the base of the PR and between 849fad9 and c4666ae.

⛔ Files ignored due to path filters (1)
  • test/tap/tests/set_testing-t.csv is excluded by !**/*.csv
📒 Files selected for processing (8)
  • include/proxysql_structs.h
  • lib/MySQL_Session.cpp
  • test/tap/groups/groups.json
  • test/tap/tests/generate_set_session_csv.cpp
  • test/tap/tests/set_testing-240.h
  • test/tap/tests/set_testing.h
  • test/tap/tests/test_filtered_set_statements-t.cpp
  • test/tap/tests/test_set_statement_for-t.cpp
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • test/tap/tests/generate_set_session_csv.cpp
  • test/tap/tests/set_testing.h
  • test/tap/tests/set_testing-240.h
  • test/tap/tests/test_filtered_set_statements-t.cpp
  • test/tap/tests/test_set_statement_for-t.cpp
  • include/proxysql_structs.h
  • lib/MySQL_Session.cpp
test/tap/groups/groups.json

📄 CodeRabbit inference engine (CLAUDE.md)

Register new test files in test/tap/groups/groups.json for test discovery via pattern rules in test/tap/tests/Makefile

Files:

  • test/tap/groups/groups.json
test/tap/tests/*-t.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • test/tap/tests/test_filtered_set_statements-t.cpp
  • test/tap/tests/test_set_statement_for-t.cpp
include/**/*.{h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Use #ifndef __CLASS_*_H include guards in header files

Files:

  • include/proxysql_structs.h
lib/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

One class per file typically in lib/ directory

Files:

  • lib/MySQL_Session.cpp
🧠 Learnings (9)
📓 Common learnings
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.
📚 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/generate_set_session_csv.cpp
  • test/tap/tests/set_testing.h
  • test/tap/tests/set_testing-240.h
  • test/tap/groups/groups.json
  • test/tap/tests/test_filtered_set_statements-t.cpp
  • test/tap/tests/test_set_statement_for-t.cpp
  • lib/MySQL_Session.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/generate_set_session_csv.cpp
  • test/tap/tests/test_filtered_set_statements-t.cpp
  • test/tap/tests/test_set_statement_for-t.cpp
📚 Learning: 2026-04-17T16:31:58.196Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-17T16:31:58.196Z
Learning: Applies to test/tap/tests/unit/**/*.cpp : Unit tests 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/set_testing.h
  • test/tap/tests/set_testing-240.h
  • test/tap/tests/test_set_statement_for-t.cpp
📚 Learning: 2026-04-17T16:31:58.196Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-17T16:31:58.196Z
Learning: Applies to test/tap/groups/groups.json : Register new test files in `test/tap/groups/groups.json` for test discovery via pattern rules in `test/tap/tests/Makefile`

Applied to files:

  • test/tap/groups/groups.json
📚 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/test_filtered_set_statements-t.cpp
  • lib/MySQL_Session.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/test_set_statement_for-t.cpp
📚 Learning: 2026-04-17T16:31:58.196Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-17T16:31:58.196Z
Learning: Applies to **/*.{cpp,h,hpp} : C++17 is required; use conditional compilation via `#ifdef PROXYSQLGENAI`, `#ifdef PROXYSQL31`, etc. for feature-gated code

Applied to files:

  • test/tap/tests/test_set_statement_for-t.cpp
📚 Learning: 2026-04-17T16:31:58.196Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-17T16:31:58.196Z
Learning: Applies to test/tap/tests/*-t.cpp : Test files should follow naming pattern `test_*.cpp` or `*-t.cpp` in `test/tap/tests/`

Applied to files:

  • test/tap/tests/test_set_statement_for-t.cpp
🔇 Additional comments (7)
test/tap/tests/set_testing.h (1)

24-25: Looks good.

These new wsrep variables are wired into the unknown-variable fallback path as expected, so the harness stays consistent with the backend tracking changes.

test/tap/groups/groups.json (1)

401-401: Looks good.

The new TAP test is registered in the discovery matrix, so it will be picked up by the standard test harness.

test/tap/tests/generate_set_session_csv.cpp (1)

306-309: Looks good.

The generator now covers both wsrep session variables with the expected numeric/string shapes, which keeps the generated SET corpus aligned with the new metadata.

test/tap/tests/set_testing-240.h (1)

24-25: Looks good.

This keeps the 240 harness in sync with the main set-testing helper, so the new wsrep variables will be handled consistently in comparisons.

test/tap/tests/test_filtered_set_statements-t.cpp (1)

44-45: Looks good.

The filtered SET-statement coverage now includes both wsrep variables, and the test plan still scales correctly with the expanded matrix.

lib/MySQL_Session.cpp (1)

133-135: wsrep tracked-variable classification looks correct.

This correctly wires wsrep_trx_fragment_size into numeric handling and wsrep_trx_fragment_unit into string handling for existing session-variable tracking/sync paths.

Also applies to: 145-146

include/proxysql_structs.h (1)

253-254: Enum/table additions stay in sync.

The new wsrep entries are inserted in matching order in both the enum and mysql_tracked_variables[], so the lookup table remains consistent with the index mapping.

Also applies to: 1855-1856

Comment thread lib/MySQL_Session.cpp
Comment thread test/tap/tests/test_set_statement_for-t.cpp
Comment on lines +131 to +143
// Test 3: No hostgroup lock persists after SET STATEMENT
diag("Test 3: Execute a plain SELECT after SET STATEMENT");
diag(" Prior to the fix, unable_to_parse_set_statement() would lock the");
diag(" hostgroup, causing subsequent queries to fail with error 9006.");
{
int rc = mysql_query(proxysql, "SELECT 1 AS no_lock_test");
ok(rc == 0, "Plain SELECT after SET STATEMENT should succeed (no hostgroup lock)");
if (rc != 0) {
diag(" ERROR: %s (this indicates the hostgroup is still locked)", mysql_error(proxysql));
} else {
MYSQL_RES* res = mysql_store_result(proxysql);
mysql_free_result(res);
}

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 | ⚡ Quick win

Strengthen the post-SET STATEMENT lock check.

A plain SELECT 1 on the same session can still succeed even if the session remains pinned to the same hostgroup, so this does not actually prove the lock was cleared. Use a query that must route to a different hostgroup, or assert the routing state directly, to make the regression check meaningful.

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

In `@test/tap/tests/test_set_statement_for-t.cpp` around lines 131 - 143, The
current test uses mysql_query(proxysql, "SELECT 1 AS no_lock_test") which can
succeed even if the session is still pinned, so replace the simple SELECT with a
query that is guaranteed to route to a different hostgroup (or assert the
session's routing directly) to prove the hostgroup lock was cleared; update the
test around unable_to_parse_set_statement() to run a cross-hostgroup query (one
that requires the alternate hostgroup) or call the session routing-check helper
in the test harness instead of SELECT 1, and keep using mysql_query(proxysql,
...) and the existing ok()/diag() checks to validate success.

Address review feedback: detect_mariadb() now returns three states
(1=MariaDB, 0=not MariaDB, -1=error) so that connection failures
cause the test to fail rather than silently skip.

@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

🤖 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/test_set_statement_for-t.cpp`:
- Around line 106-120: The test currently calls mysql_query(proxysql, "SET
STATEMENT...") and only emits the second ok() inside the rc==0 branch, causing
TAP plan(5) to mismatch when rc!=0; modify the failure branch (where rc != 0) to
call skip(1, "SET STATEMENT failed: %s", mysql_error(proxysql)) so the test
still emits the expected number of TAP results, keep the diagnostic diag(" 
ERROR: %s", mysql_error(proxysql)) and do not remove the existing ok() calls in
the success path (the block using mysql_store_result, mysql_fetch_row,
mysql_num_rows and the ok comparing row[0] to "1").
- Around line 89-101: The test calls plan(5) before establishing the ProxySQL
connection so if mysql_real_connect(proxysql, ...) fails the TAP output has a
plan but no ok() results; move the connection setup (the MYSQL* proxysql =
mysql_init(NULL); and the mysql_real_connect(...) block) to occur before
plan(5), or alternatively replace the early return -1 with a bail_out(...) call;
update the code around plan(), proxysql, and mysql_real_connect to ensure plan()
is only emitted after a successful connection (or use bail_out on failure).
🪄 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: 86d475ca-913a-46b7-9fa6-e85d83cf7a02

📥 Commits

Reviewing files that changed from the base of the PR and between c4666ae and b1ace3f.

📒 Files selected for processing (1)
  • test/tap/tests/test_set_statement_for-t.cpp
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • test/tap/tests/test_set_statement_for-t.cpp
test/tap/tests/*-t.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • test/tap/tests/test_set_statement_for-t.cpp
🧠 Learnings (8)
📓 Common learnings
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.
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-17T16:31:58.196Z
Learning: Use feature flags `PROXYSQL31=1` for v3.1.x Innovative tier and `PROXYSQLGENAI=1` for v4.0.x AI/MCP tier; PROXYSQLGENAI implies both PROXYSQL31 and PROXYSQLFFTO/PROXYSQLTSDB
📚 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/test_set_statement_for-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/test_set_statement_for-t.cpp
📚 Learning: 2026-04-17T16:31:58.196Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-17T16:31:58.196Z
Learning: Applies to test/tap/tests/unit/**/*.cpp : Unit tests 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/test_set_statement_for-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/test_set_statement_for-t.cpp
📚 Learning: 2026-04-17T16:31:58.196Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-17T16:31:58.196Z
Learning: Applies to **/*.{cpp,h,hpp} : C++17 is required; use conditional compilation via `#ifdef PROXYSQLGENAI`, `#ifdef PROXYSQL31`, etc. for feature-gated code

Applied to files:

  • test/tap/tests/test_set_statement_for-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/test_set_statement_for-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/test_set_statement_for-t.cpp
🔇 Additional comments (1)
test/tap/tests/test_set_statement_for-t.cpp (1)

141-154: Weak lock-check assertion (carries over from previous review).

SELECT 1 AS no_lock_test succeeds regardless of which hostgroup the session is pinned to, so it cannot distinguish "lock was cleared" from "lock remains on the same hostgroup." A cross-hostgroup query or a direct inspection of session routing state would make this regression check meaningful.

Comment on lines +89 to +101
plan(5);

diag("=== Test: MariaDB SET STATEMENT ... FOR passthrough ===");
diag("Issue #5686: ProxySQL should forward SET STATEMENT ... FOR");
diag("to the backend without locking the hostgroup.");
diag("");

// Connect to ProxySQL
MYSQL* proxysql = mysql_init(NULL);
if (!mysql_real_connect(proxysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql));
return -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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

plan(5) is emitted before the ProxySQL connection is established.

If mysql_real_connect fails at line 98, plan(5) has already been output but zero ok() calls follow. The TAP harness will report 0 tests run against a plan of 5. Either establish the connection before calling plan(), or call bail_out() instead of return -1 on connection failure.

🐛 Proposed fix (establish connection before plan)
+	// Connect to ProxySQL
+	MYSQL* proxysql = mysql_init(NULL);
+	if (!mysql_real_connect(proxysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql));
+		return -1;
+	}
+
 	plan(5);
 
 	diag("=== Test: MariaDB SET STATEMENT ... FOR passthrough ===");
 	...
-
-	// Connect to ProxySQL
-	MYSQL* proxysql = mysql_init(NULL);
-	if (!mysql_real_connect(proxysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql));
-		return -1;
-	}
📝 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
plan(5);
diag("=== Test: MariaDB SET STATEMENT ... FOR passthrough ===");
diag("Issue #5686: ProxySQL should forward SET STATEMENT ... FOR");
diag("to the backend without locking the hostgroup.");
diag("");
// Connect to ProxySQL
MYSQL* proxysql = mysql_init(NULL);
if (!mysql_real_connect(proxysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql));
return -1;
}
// Connect to ProxySQL
MYSQL* proxysql = mysql_init(NULL);
if (!mysql_real_connect(proxysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql));
return -1;
}
plan(5);
diag("=== Test: MariaDB SET STATEMENT ... FOR passthrough ===");
diag("Issue `#5686`: ProxySQL should forward SET STATEMENT ... FOR");
diag("to the backend without locking the hostgroup.");
diag("");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/test_set_statement_for-t.cpp` around lines 89 - 101, The test
calls plan(5) before establishing the ProxySQL connection so if
mysql_real_connect(proxysql, ...) fails the TAP output has a plan but no ok()
results; move the connection setup (the MYSQL* proxysql = mysql_init(NULL); and
the mysql_real_connect(...) block) to occur before plan(5), or alternatively
replace the early return -1 with a bail_out(...) call; update the code around
plan(), proxysql, and mysql_real_connect to ensure plan() is only emitted after
a successful connection (or use bail_out on failure).

Comment on lines +106 to +120
{
int rc = mysql_query(proxysql, "SET STATEMENT max_statement_time=60 FOR SELECT 1 AS val");
ok(rc == 0, "SET STATEMENT max_statement_time=60 FOR SELECT 1 should succeed");
if (rc != 0) {
diag(" ERROR: %s", mysql_error(proxysql));
} else {
MYSQL_RES* res = mysql_store_result(proxysql);
MYSQL_ROW row = mysql_fetch_row(res);
int rows = mysql_num_rows(res);
diag(" Result: rows=%d, val=%s", rows, row ? row[0] : "NULL");
ok(rows == 1 && row && strcmp(row[0], "1") == 0,
"SET STATEMENT ... FOR should return the result from the inner SELECT");
mysql_free_result(res);
}
}

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 | ⚡ Quick win

TAP count mismatch when Test 1 fails: plan(5) but only 4 ok() calls are emitted.

The second assertion (line 116) is inside the else branch that only runs when rc == 0. If the SET STATEMENT query fails, only 4 ok() calls are made against plan(5), which the TAP harness will report as a bad test count — potentially masking the real failure.

Use skip(1, ...) in the failure path to keep the emitted count at exactly 5.

🐛 Proposed fix
 		int rc = mysql_query(proxysql, "SET STATEMENT max_statement_time=60 FOR SELECT 1 AS val");
 		ok(rc == 0, "SET STATEMENT max_statement_time=60 FOR SELECT 1 should succeed");
 		if (rc != 0) {
 			diag("  ERROR: %s", mysql_error(proxysql));
+			skip(1, "Skipping result check because query failed");
 		} else {
 			MYSQL_RES* res = mysql_store_result(proxysql);
 			MYSQL_ROW row = mysql_fetch_row(res);
 			int rows = mysql_num_rows(res);
 			diag("  Result: rows=%d, val=%s", rows, row ? row[0] : "NULL");
 			ok(rows == 1 && row && strcmp(row[0], "1") == 0,
 				"SET STATEMENT ... FOR should return the result from the inner SELECT");
 			mysql_free_result(res);
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tap/tests/test_set_statement_for-t.cpp` around lines 106 - 120, The test
currently calls mysql_query(proxysql, "SET STATEMENT...") and only emits the
second ok() inside the rc==0 branch, causing TAP plan(5) to mismatch when rc!=0;
modify the failure branch (where rc != 0) to call skip(1, "SET STATEMENT failed:
%s", mysql_error(proxysql)) so the test still emits the expected number of TAP
results, keep the diagnostic diag("  ERROR: %s", mysql_error(proxysql)) and do
not remove the existing ok() calls in the success path (the block using
mysql_store_result, mysql_fetch_row, mysql_num_rows and the ok comparing row[0]
to "1").

renecannao added 6 commits May 2, 2026 03:56
Resolve groups.json conflict: keep test_set_statement_for-t from PR
and set_parser_algorithm=3-g1 additions from v3.0.
…ossible_unknown_variables

The set_testing tests generate multi-variable SET statements that mix
Galera/Group-Replication-only variables (wsrep_trx_fragment_size,
wsrep_trx_fragment_unit, group_replication_consistency) with standard
MySQL variables. When sent to a non-Galera/non-GR backend, the entire
SET fails because MySQL rejects the unknown variable.

Previously only wsrep_sync_wait had an exception: if MySQL doesnt have
it but ProxySQL correctly tracked the value, the test passes. Extend
this exception to all variables in possible_unknown_variables for
set_testing-t, set_testing-multi-t, and set_testing-240-t.
@renecannao
renecannao force-pushed the issue-5686-galera-vars branch from 5bd04b1 to e212998 Compare May 5, 2026 02:39
- Guard with is_cluster in set_testing-t and set_testing-multi-t
  (same pattern as wsrep_sync_wait)
- Set mix=false in generate_set_session_csv so they only appear
  in single-variable SETs (avoids corrupting connection state
  when backend rejects them)
- Restore CSV entries that were incorrectly removed
@renecannao
renecannao force-pushed the issue-5686-galera-vars branch from e212998 to 51b279c Compare May 5, 2026 03:09
renecannao added 5 commits May 5, 2026 03:48
…on backend

When ProxySQL tries to SET a tracked variable on a backend that has
the variable but rejects the value (error 1231: Variable can't be set
to the value), it now marks the variable as absent on that connection
and continues instead of destroying the connection.

This matches existing handling for errors 1193 (unknown variable),
1064 (syntax error), and 1651 (query cache disabled).

Fixes set_testing failures on MariaDB 10.11 with wsrep_provider=none,
where wsrep_trx_fragment_size exists but all SET attempts fail with
error 1231.
- CI base image can be pulled from GHCR instead of built locally
- Build commands should use debug mode: make debug + build_tap_test_debug
set_testing-240-t was missing the is_cluster detection and wsrep variable
guards that set_testing-t and set_testing-multi-t already had. This caused
failures on MariaDB 10.11 backends with wsrep_provider=none where
wsrep_trx_fragment_size exists but can't be set.
…n backend

ProxySQL now gracefully handles error 1210 (Incorrect arguments to SET)
in addition to the previously handled 1231 (Variable can't be set to the
value). Both errors occur when a tracked variable is SET on a backend
that has the variable but rejects the value (e.g. wsrep_trx_fragment_size
on MariaDB 10.11 with wsrep_provider=none).

Instead of destroying the backend connection, ProxySQL marks the variable
as absent on that connection and continues.

Also fix test comparison logic: when the backend returns UNKNOWNVAR for
a variable (backend doesn't have it) but ProxySQL's tracked value matches
the expected CSV value, count it as a pass. This prevents false failures
when test connections are routed to heterogeneous backends.
@sonarqubecloud

sonarqubecloud Bot commented May 5, 2026

Copy link
Copy Markdown

tabacco pushed a commit to tabacco/proxysql that referenced this pull request May 26, 2026
PR sysown#5708 added detection for MariaDB's `SET STATEMENT … FOR …` syntax
to keep ProxySQL from invoking `unable_to_parse_set_statement()` and
locking the session to a single hostgroup. The detection at
`lib/MySQL_Session.cpp` was:

    if (strncasecmp(nq.c_str(), "SET STATEMENT ", 14) == 0
        && strcasestr(nq.c_str(),  " FOR ")) {
        return false;
    }

`strcasestr(nq, " FOR ")` is a literal-substring search requiring a
space BOTH before and after the FOR keyword. A customer report (see
PR sysown#5708 thread) reproduced the same error 9006 as before the fix by
typing the statement across multiple lines at the mysql client
prompt — the character after FOR is then a newline, not a space, so
the detection misses, the code falls through to the regular SET
parser, the parser doesn't know SET STATEMENT, and the hostgroup is
locked to the user's default. The next non-default-hostgroup query
fails with 9006.

Verified with a standalone strcasestr probe:

  q1 (customer multi-line):  strcasestr(" FOR ") matches ? NO
  q2 (existing TAP single-line):                            YES

The fix uses `dig` (the digest text) for the detection instead of
`nq` (the raw query). `dig` is whitespace-normalised by the digest
builder, so " FOR " always has a space on both sides regardless of
how the client formatted the query. This is consistent with the
prefix check 35 lines above, which already uses `dig` for keyword
detection.

== Test coverage ==

`test/tap/tests/test_set_statement_for-t.cpp` previously had `plan(5)`
and self-skipped on non-MariaDB backends via `skip_all()`. It was
also registered ONLY in MySQL-family TAP groups
(`legacy-g2`, `mysql84-g2`, etc.). The net effect was that the test
self-skipped on every CI run since it was added — never actually
executing an assertion in CI. The customer's bug regressed entirely
unnoticed.

This commit:

1. Removes the runtime MariaDB-detection helper and the `skip_all`
   call. A misregistered test should fail loudly, not silently skip;
   correct registration is enforced through the groups.json layer
   instead.
2. Moves the groups.json registration from the MySQL-only groups to
   `mariadb10-galera-g2`, which actually provides a MariaDB backend.
3. Adds four new test cases (assertions 6–13) covering the customer
   whitespace shapes that strcasestr (" FOR ") missed: newline,
   tab, CRLF, and multiple spaces between FOR and the inner
   statement. Each case verifies (a) the SET STATEMENT succeeds, and
   (b) a follow-up plain SELECT succeeds (i.e. no hostgroup lock
   persists — the customer's actual failure mode).

Verified locally on TAP group mariadb10-galera-g2 against MariaDB
10.11.9: 13/13 ok, RC=0.

A separate framework-cleanup follow-up should remove `skip_all()`
from `test/tap/tap/tap.{h,cpp}` entirely and convert the other four
callers (`test_mysqlx_e2e_*`, `test_mysqlx_route_drop_inflight-t`,
`test_mysqlx_sigterm_inflight-t`) to either fail loudly or move to
appropriately-gated TAP groups.
tabacco pushed a commit to tabacco/proxysql that referenced this pull request May 26, 2026
…ions

Stage 2 follow-up to the PR sysown#5708 reproduction debug. The framework
helper test/tap/tap/tap.{h,cpp}::skip_all() prints "1..0 # skip ..."
and exit(0), which the harness reports as "ignored" — zero assertions
emitted, zero failures recorded, no notice that a test never ran.

While investigating the customer regression on PR sysown#5708 we discovered
that test_set_statement_for-t had been silently skipping in CI since
the day it was added: it self-skipped on non-MariaDB backends, but was
registered only in MySQL-family TAP groups, so every run skipped.
PR sysown#5794 fixes that one test. The principled fix is to remove the
mechanism that lets a test silently disappear.

This commit converts the remaining four skip_all() callers and deletes
the framework function:

  - test_mysqlx_e2e_routing-t       BAIL_OUT if MYSQLX_E2E_PROXYSQL_PORT
                                    is not set. The group env file
                                    test/tap/groups/mysqlx-e2e/env.sh
                                    sets it; missing at runtime means
                                    the harness did not source it.
  - test_mysqlx_e2e_handshake-t     BAIL_OUT if MYSQLX_E2E_HOST is not
                                    set (same env file, same rationale).
  - test_mysqlx_route_drop_inflight-t  BAIL_OUT if the X-Protocol
                                    listener is not reachable. The
                                    mysqlx-soak-g1 harness is supposed
                                    to start ProxySQL with the mysqlx
                                    plugin and provision the route; a
                                    missing listener is a setup bug.
  - test_mysqlx_sigterm_inflight-t  Deleted. The binary was a stub
                                    whose body was a TODO; the real
                                    sigterm scenario is implemented in
                                    test/scripts/mysqlx/behavioral_validation.py
                                    --scenario sigterm. With skip_all
                                    gone the stub had no remaining
                                    purpose. Also dropped from
                                    groups.json and the Makefile.

After this commit, the test/tap codebase has zero call sites of
skip_all(). The framework declaration and definition are deleted from
tap.h and tap.cpp; the doc references at the bottom of tap.cpp are
updated; a comment explains the rationale and points at BAIL_OUT() as
the replacement.

Verified locally: full TAP debug build succeeds, no undefined-reference
errors, lint_groups_json + check_groups --source both green.

Depends on PR sysown#5794 (which removed the fifth caller in
test_set_statement_for-t.cpp). This PR is based on that branch; merging
in order keeps each merge a clean compile.
@renecannao
renecannao deleted the issue-5686-galera-vars branch June 10, 2026 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide some more wsrep session variables support

1 participant