Skip to content

Commit ad19325

Browse files
authoredMar 24, 2025··
Merge pull request #4872 from sysown/v3.0_issue_4867
Fixed mirror_hostgroup and mirror_flagOUT swapping issue in MySQL and PostgreSQL query rules - v3.0
2 parents 8f51df7 + c95afaf commit ad19325

6 files changed

+1054
-10
lines changed
 

‎include/MySQL_Query_Processor.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ class MySQL_Query_Processor : public Query_Processor<MySQL_Query_Processor> {
5454
static MySQL_Query_Processor_Rule_t* new_query_rule(int rule_id, bool active, const char* username, const char* schemaname, int flagIN, const char* client_addr,
5555
const char* proxy_addr, int proxy_port, const char* digest, const char* match_digest, const char* match_pattern, bool negate_match_pattern,
5656
const char* re_modifiers, int flagOUT, const char* replace_pattern, int destination_hostgroup, int cache_ttl, int cache_empty_result,
57-
int cache_timeout, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_hostgroup,
58-
int mirror_flagOUT, const char* error_msg, const char* OK_msg, int sticky_conn, int multiplex, int gtid_from_hostgroup, int log,
57+
int cache_timeout, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_flagOUT,
58+
int mirror_hostgroup, const char* error_msg, const char* OK_msg, int sticky_conn, int multiplex, int gtid_from_hostgroup, int log,
5959
bool apply, const char* attributes, const char* comment);
6060

6161
private:

‎include/PgSQL_Query_Processor.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ class PgSQL_Query_Processor : public Query_Processor<PgSQL_Query_Processor> {
3131
static PgSQL_Query_Processor_Rule_t* new_query_rule(int rule_id, bool active, const char* username, const char* schemaname, int flagIN, const char* client_addr,
3232
const char* proxy_addr, int proxy_port, const char* digest, const char* match_digest, const char* match_pattern, bool negate_match_pattern,
3333
const char* re_modifiers, int flagOUT, const char* replace_pattern, int destination_hostgroup, int cache_ttl, int cache_empty_result,
34-
int cache_timeout, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_hostgroup,
35-
int mirror_flagOUT, const char* error_msg, const char* OK_msg, int sticky_conn, int multiplex, int log,
34+
int cache_timeout, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_flagOUT,
35+
int mirror_hostgroup, const char* error_msg, const char* OK_msg, int sticky_conn, int multiplex, int log,
3636
bool apply, const char* attributes, const char* comment);
3737

3838
private:

‎lib/MySQL_Query_Processor.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -680,8 +680,8 @@ MySQL_Query_Processor_Output* MySQL_Query_Processor::process_query(MySQL_Session
680680
MySQL_Query_Processor_Rule_t* MySQL_Query_Processor::new_query_rule(int rule_id, bool active, const char* username, const char* schemaname, int flagIN, const char* client_addr,
681681
const char* proxy_addr, int proxy_port, const char* digest, const char* match_digest, const char* match_pattern, bool negate_match_pattern,
682682
const char* re_modifiers, int flagOUT, const char* replace_pattern, int destination_hostgroup, int cache_ttl, int cache_empty_result,
683-
int cache_timeout, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_hostgroup,
684-
int mirror_flagOUT, const char* error_msg, const char* OK_msg, int sticky_conn, int multiplex, int gtid_from_hostgroup, int log,
683+
int cache_timeout, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_flagOUT,
684+
int mirror_hostgroup, const char* error_msg, const char* OK_msg, int sticky_conn, int multiplex, int gtid_from_hostgroup, int log,
685685
bool apply, const char* attributes, const char* comment) {
686686

687687
MySQL_Query_Processor_Rule_t* newQR = (MySQL_Query_Processor_Rule_t*)malloc(sizeof(MySQL_Query_Processor_Rule_t));
@@ -941,7 +941,7 @@ MySQL_Query_Processor_Rule_t* MySQL_Query_Processor::new_query_rule(const MySQL_
941941

942942
SQLite3_result* MySQL_Query_Processor::get_current_query_rules() {
943943
proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Dumping current query rules, using Global version %d\n", version);
944-
SQLite3_result* result = new SQLite3_result(35);
944+
SQLite3_result* result = new SQLite3_result(36);
945945
MySQL_Query_Processor_Rule_t* qr1;
946946
rdlock();
947947
result->add_column_definition(SQLITE_TEXT, "rule_id");

‎lib/PgSQL_Query_Processor.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ PgSQL_Query_Processor_Output* PgSQL_Query_Processor::process_query(PgSQL_Session
317317
PgSQL_Query_Processor_Rule_t* PgSQL_Query_Processor::new_query_rule(int rule_id, bool active, const char* username, const char* schemaname, int flagIN, const char* client_addr,
318318
const char* proxy_addr, int proxy_port, const char* digest, const char* match_digest, const char* match_pattern, bool negate_match_pattern,
319319
const char* re_modifiers, int flagOUT, const char* replace_pattern, int destination_hostgroup, int cache_ttl, int cache_empty_result,
320-
int cache_timeout, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_hostgroup,
321-
int mirror_flagOUT, const char* error_msg, const char* OK_msg, int sticky_conn, int multiplex, int log,
320+
int cache_timeout, int reconnect, int timeout, int retries, int delay, int next_query_flagIN, int mirror_flagOUT,
321+
int mirror_hostgroup, const char* error_msg, const char* OK_msg, int sticky_conn, int multiplex, int log,
322322
bool apply, const char* attributes, const char* comment) {
323323

324324
PgSQL_Query_Processor_Rule_t* newQR = (PgSQL_Query_Processor_Rule_t*)malloc(sizeof(PgSQL_Query_Processor_Rule_t));
@@ -576,7 +576,7 @@ PgSQL_Query_Processor_Rule_t* PgSQL_Query_Processor::new_query_rule(const PgSQL_
576576

577577
SQLite3_result* PgSQL_Query_Processor::get_current_query_rules() {
578578
proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Dumping current query rules, using Global version %d\n", version);
579-
SQLite3_result* result = new SQLite3_result(34);
579+
SQLite3_result* result = new SQLite3_result(35);
580580
PgSQL_Query_Processor_Rule_t* qr1;
581581
rdlock();
582582
result->add_column_definition(SQLITE_TEXT, "rule_id");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,470 @@
1+
/**
2+
* @file mysql-reg_test_4867_query_rules-t-t.cpp
3+
* @brief This TAP test ensures that the main.mysql_query_rules table is correctly synchronized with both runtime_mysql_query_rules
4+
* and disk_mysql_query_rules, while also verifying that values are not swapped between columns.
5+
*/
6+
7+
#include <unistd.h>
8+
#include <string>
9+
#include <sstream>
10+
#include <chrono>
11+
#include <thread>
12+
#include "libpq-fe.h"
13+
#include "command_line.h"
14+
#include "tap.h"
15+
#include "utils.h"
16+
17+
CommandLine cl;
18+
19+
using MySQLConnPtr = std::unique_ptr<MYSQL, decltype(&mysql_close)>;
20+
21+
typedef struct {
22+
int rule_id;
23+
int active;
24+
char* username;
25+
char* schemaname;
26+
int flagIN;
27+
char* client_addr;
28+
char* proxy_addr;
29+
int proxy_port;
30+
unsigned int digest;
31+
char* match_digest;
32+
char* match_pattern;
33+
int negate_match_pattern;
34+
const char* re_modifiers;
35+
int flagOUT;
36+
char* replace_pattern;
37+
int destination_hostgroup;
38+
int cache_ttl;
39+
int cache_empty_result;
40+
int cache_timeout;
41+
int reconnect;
42+
unsigned int timeout;
43+
int retries;
44+
unsigned int delay;
45+
unsigned int next_query_flagIN;
46+
unsigned int mirror_flagOUT;
47+
unsigned int mirror_hostgroup;
48+
char* error_msg;
49+
char* OK_msg;
50+
int sticky_conn;
51+
int multiplex;
52+
int gtid_from_hostgroup;
53+
int log;
54+
int apply;
55+
char* attributes;
56+
char* comment;
57+
} RuleData;
58+
59+
// Unique value generator with offsets
60+
typedef struct {
61+
int base;
62+
int offset;
63+
} ValueGenerator;
64+
65+
// Compare two strings considering NULL
66+
bool compare_str(const char* a, const char* b) {
67+
if (a == NULL && b == NULL) return true;
68+
if (a == NULL || b == NULL) return false;
69+
return strcmp(a, b) == 0;
70+
}
71+
72+
int next_val(ValueGenerator* vg) {
73+
return vg->base + (vg->offset++);
74+
}
75+
76+
char* unique_str(ValueGenerator* vg, const char* field) {
77+
char* str = (char*)malloc(32);
78+
sprintf(str, "%s_%d", field, next_val(vg));
79+
return str;
80+
}
81+
82+
char* unique_ip(ValueGenerator* vg) {
83+
char* ip = (char*)malloc(16);
84+
int octet = vg->base + vg->offset++;
85+
sprintf(ip, "%d.%d.%d.%d",
86+
octet % 256, (octet + 1) % 256, (octet + 2) % 256, (octet + 3) % 256);
87+
return ip;
88+
}
89+
90+
char* unique_json(ValueGenerator* vg) {
91+
char* json = (char*)malloc(50);
92+
sprintf(json, "{\"%s\":%d}", "unique_key", next_val(vg));
93+
return json;
94+
}
95+
96+
char* pvsprintf(const char* fmt, va_list args) {
97+
va_list args_copy;
98+
int len;
99+
size_t size;
100+
char* buffer;
101+
102+
// Create a copy of args to determine the length
103+
va_copy(args_copy, args);
104+
len = vsnprintf(NULL, 0, fmt, args_copy);
105+
va_end(args_copy);
106+
107+
if (len < 0) {
108+
return NULL; // Formatting error occurred
109+
}
110+
111+
size = len + 1; // +1 for the null terminator
112+
buffer = (char*)malloc(size);
113+
if (buffer == NULL) {
114+
return NULL; // Memory allocation failed
115+
}
116+
117+
// Now format the string into the allocated buffer
118+
len = vsnprintf(buffer, size, fmt, args);
119+
if (len < 0) {
120+
free(buffer);
121+
return NULL; // Formatting error occurred
122+
}
123+
124+
return buffer;
125+
}
126+
127+
char* psprintf(const char* fmt, ...) {
128+
va_list args;
129+
char* result;
130+
131+
va_start(args, fmt);
132+
result = pvsprintf(fmt, args);
133+
va_end(args);
134+
135+
return result;
136+
}
137+
138+
char* escape_str(MYSQL* mysql, const char* str) {
139+
if (!str) return strdup("NULL");
140+
char* escaped = (char*)malloc(2 * strlen(str) + 1);
141+
mysql_real_escape_string(mysql, escaped, str, strlen(str));
142+
char* result = (char*)malloc(strlen(escaped) + 3);
143+
sprintf(result, "'%s'", escaped);
144+
free(escaped);
145+
return result;
146+
}
147+
148+
// Build INSERT query for a rule
149+
char* build_insert_query(MYSQL* mysql, RuleData* rule) {
150+
char* query = NULL;
151+
char* esc_username = escape_str(mysql, rule->username);
152+
char* esc_schemaname = escape_str(mysql, rule->schemaname);
153+
char* esc_client_addr = escape_str(mysql, rule->client_addr);
154+
char* esc_proxy_addr = escape_str(mysql, rule->proxy_addr);
155+
char* esc_proxy_port = (rule->proxy_port != -1) ? psprintf("%d", rule->proxy_port) : strdup("NULL");
156+
char* esc_match_digest = escape_str(mysql, rule->match_digest);
157+
char* esc_match_pattern = escape_str(mysql, rule->match_pattern);
158+
char* esc_replace_pattern = escape_str(mysql, rule->replace_pattern);
159+
char* esc_destination_hostgroup = (rule->destination_hostgroup != -1) ? psprintf("%d", rule->destination_hostgroup) : strdup("NULL");
160+
char* esc_cache_ttl = (rule->cache_ttl != -1) ? psprintf("%d", rule->cache_ttl) : strdup("NULL");
161+
char* esc_cache_empty_result = (rule->cache_empty_result != -1) ? psprintf("%d", rule->cache_empty_result) : strdup("NULL");
162+
char* esc_cache_timeout = (rule->cache_timeout != -1) ? psprintf("%d", rule->cache_timeout) : strdup("NULL");
163+
char* esc_reconnect = (rule->reconnect != -1) ? psprintf("%d", rule->reconnect) : strdup("NULL");
164+
char* esc_flagOUT = (rule->flagOUT != -1) ? psprintf("%d", rule->flagOUT) : strdup("NULL");
165+
char* esc_error_msg = escape_str(mysql, rule->error_msg);
166+
char* esc_OK_msg = escape_str(mysql, rule->OK_msg);
167+
char* esc_attributes = escape_str(mysql, rule->attributes);
168+
char* esc_comment = escape_str(mysql, rule->comment);
169+
170+
query = psprintf(
171+
"INSERT INTO mysql_query_rules ("
172+
"active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, "
173+
"digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, "
174+
"destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, "
175+
"next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, OK_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment"
176+
") VALUES ("
177+
"%d, %s, %s, %d, %s, %s, %s, "
178+
"%u, %s, %s, %d, '%s', %s, %s, "
179+
"%s, %s, %s, %s, %s, %u, %d, %u, "
180+
"%u, %u, %u, %s, %s, %d, %d, %d, %d, %d, %s, %s"
181+
")",
182+
rule->active, esc_username, esc_schemaname, rule->flagIN, esc_client_addr, esc_proxy_addr, esc_proxy_port,
183+
rule->digest, esc_match_digest, esc_match_pattern, rule->negate_match_pattern, rule->re_modifiers, esc_flagOUT, esc_replace_pattern,
184+
esc_destination_hostgroup, esc_cache_ttl, esc_cache_empty_result, esc_cache_timeout, esc_reconnect, rule->timeout, rule->retries, rule->delay,
185+
rule->next_query_flagIN, rule->mirror_flagOUT, rule->mirror_hostgroup, esc_error_msg, esc_OK_msg, rule->sticky_conn, rule->multiplex, rule->gtid_from_hostgroup, rule->log, rule->apply, esc_attributes, esc_comment
186+
);
187+
188+
// Free all allocated strings
189+
free(esc_username);
190+
free(esc_schemaname);
191+
free(esc_client_addr);
192+
free(esc_proxy_addr);
193+
free(esc_proxy_port);
194+
free(esc_match_digest);
195+
free(esc_match_pattern);
196+
free(esc_replace_pattern);
197+
free(esc_destination_hostgroup);
198+
free(esc_cache_ttl);
199+
free(esc_cache_empty_result);
200+
free(esc_cache_timeout);
201+
free(esc_reconnect);
202+
free(esc_flagOUT);
203+
free(esc_error_msg);
204+
free(esc_OK_msg);
205+
free(esc_attributes);
206+
free(esc_comment);
207+
208+
return query;
209+
}
210+
211+
212+
void generate_rule(RuleData* rule, int base) {
213+
ValueGenerator vg = { base, 0 };
214+
215+
// Generate unique values for each field
216+
rule->active = 1;
217+
rule->username = unique_str(&vg, "user");
218+
rule->schemaname = unique_str(&vg, "schemaname");
219+
rule->flagIN = next_val(&vg);
220+
rule->client_addr = unique_ip(&vg);
221+
rule->proxy_addr = unique_ip(&vg);
222+
rule->proxy_port = next_val(&vg) % 65536;
223+
rule->digest = next_val(&vg);
224+
rule->match_digest = unique_str(&vg, "match_dig");
225+
rule->match_pattern = unique_str(&vg, "pattern");
226+
rule->negate_match_pattern = next_val(&vg) % 2;
227+
rule->re_modifiers = "CASELESS"; // Keep simple for demo
228+
rule->flagOUT = next_val(&vg);
229+
rule->replace_pattern = unique_str(&vg, "replace");
230+
rule->destination_hostgroup = next_val(&vg);
231+
rule->cache_ttl = next_val(&vg);
232+
rule->cache_empty_result = next_val(&vg) % 2;
233+
rule->cache_timeout = next_val(&vg);
234+
rule->reconnect = next_val(&vg) % 2;
235+
rule->timeout = next_val(&vg);
236+
rule->retries = next_val(&vg) % 1001;
237+
rule->delay = next_val(&vg);
238+
rule->next_query_flagIN = next_val(&vg);
239+
rule->mirror_flagOUT = next_val(&vg);
240+
rule->mirror_hostgroup = next_val(&vg);
241+
rule->error_msg = unique_str(&vg, "err");
242+
rule->OK_msg = unique_str(&vg, "ok");
243+
rule->sticky_conn = next_val(&vg) % 2;
244+
rule->multiplex = next_val(&vg) % 3;
245+
rule->gtid_from_hostgroup = next_val(&vg);
246+
rule->log = next_val(&vg) % 2;
247+
rule->apply = next_val(&vg) % 2;
248+
rule->attributes = unique_json(&vg);
249+
rule->comment = unique_str(&vg, "comment");
250+
}
251+
252+
bool check_result(MYSQL_RES* res, RuleData* expected, bool runtime_table) {
253+
MYSQL_ROW row = mysql_fetch_row(res);
254+
unsigned long* lengths = mysql_fetch_lengths(res);
255+
bool match = true;
256+
257+
int field_idx = 1; // excluding rule_id
258+
#define COMPARE_INT(expected_val, col) \
259+
if (row[field_idx] == NULL) { \
260+
if (expected_val != -1) { \
261+
diag("Expected %s to be %d, got NULL", #col, expected_val); \
262+
match = false; \
263+
} \
264+
} else { \
265+
int val = atoi(row[field_idx]); \
266+
if (val != expected_val) { \
267+
diag("Expected %s to be %d, got %d", #col, expected_val, val); \
268+
match = false; \
269+
} \
270+
} \
271+
field_idx++;
272+
273+
#define COMPARE_STR(expected_str, col) \
274+
if (row[field_idx] == NULL) { \
275+
if (expected_str != NULL) { \
276+
diag("Expected %s to be '%s', got NULL", #col, expected_str); \
277+
match = false; \
278+
} \
279+
} else { \
280+
if (strcmp(row[field_idx], expected_str ? expected_str : "") != 0) { \
281+
diag("Expected %s to be '%s', got '%s'", #col, expected_str, row[field_idx]); \
282+
match = false; \
283+
} \
284+
} \
285+
field_idx++;
286+
287+
COMPARE_INT(expected->active, active);
288+
COMPARE_STR(expected->username, username);
289+
COMPARE_STR(expected->schemaname, schemaname);
290+
COMPARE_INT(expected->flagIN, flagIN);
291+
COMPARE_STR(expected->client_addr, client_addr);
292+
COMPARE_STR(expected->proxy_addr, proxy_addr);
293+
COMPARE_INT(expected->proxy_port, proxy_port);
294+
295+
296+
if (runtime_table == true) {
297+
298+
// converting digest to hex string
299+
char hex_string[20];
300+
sprintf(hex_string, "0x%016X", expected->digest);
301+
302+
if (strcmp(row[field_idx], hex_string ? hex_string : "") != 0) {
303+
diag("Expected digest to be '%s', got '%s'", hex_string, row[field_idx]);
304+
match = false;
305+
}
306+
field_idx++;
307+
}
308+
else {
309+
COMPARE_INT(expected->digest, digest);
310+
}
311+
312+
313+
COMPARE_STR(expected->match_digest, match_digest);
314+
COMPARE_STR(expected->match_pattern, match_pattern);
315+
COMPARE_INT(expected->negate_match_pattern, negate_match_pattern);
316+
COMPARE_STR(expected->re_modifiers, re_modifiers);
317+
COMPARE_INT(expected->flagOUT, flagOUT);
318+
COMPARE_STR(expected->replace_pattern, replace_pattern);
319+
COMPARE_INT(expected->destination_hostgroup, destination_hostgroup);
320+
COMPARE_INT(expected->cache_ttl, cache_ttl);
321+
COMPARE_INT(expected->cache_empty_result, cache_empty_result);
322+
COMPARE_INT(expected->cache_timeout, cache_timeout);
323+
COMPARE_INT(expected->reconnect, reconnect);
324+
COMPARE_INT(expected->timeout, timeout);
325+
COMPARE_INT(expected->retries, retries);
326+
COMPARE_INT(expected->delay, delay);
327+
COMPARE_INT(expected->next_query_flagIN, next_query_flagIN);
328+
COMPARE_INT(expected->mirror_flagOUT, mirror_flagOUT);
329+
COMPARE_INT(expected->mirror_hostgroup, mirror_hostgroup);
330+
COMPARE_STR(expected->error_msg, error_msg);
331+
COMPARE_STR(expected->OK_msg, OK_msg);
332+
COMPARE_INT(expected->sticky_conn, sticky_conn);
333+
COMPARE_INT(expected->multiplex, multiplex);
334+
COMPARE_INT(expected->gtid_from_hostgroup, gtid_from_hostgroup);
335+
COMPARE_INT(expected->log, log);
336+
COMPARE_INT(expected->apply, apply);
337+
COMPARE_STR(expected->attributes, attributes);
338+
COMPARE_STR(expected->comment, comment);
339+
340+
return match;
341+
}
342+
343+
#define MYSQL_QUERY_ON_ERR_CLEANUP(mysql, query) \
344+
do { \
345+
if (mysql_query(mysql, query)) { \
346+
fprintf(stderr, "File %s, line %d, Error: %s (%s)\n", __FILE__, __LINE__, mysql_error(mysql), query); \
347+
goto cleanup; \
348+
} \
349+
} while(0)
350+
351+
int main() {
352+
int num_tests = 3;
353+
plan(num_tests * 2);
354+
355+
if (cl.getEnv())
356+
return exit_status();
357+
358+
MySQLConnPtr conn(mysql_init(NULL), mysql_close);
359+
MYSQL* proxysql_admin = conn.get();
360+
361+
// Initialize connections
362+
if (!proxysql_admin) {
363+
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
364+
return -1;
365+
}
366+
367+
if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
368+
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
369+
return -1;
370+
}
371+
372+
srand(time(NULL));
373+
RuleData* rules = (RuleData*)calloc(num_tests, sizeof(RuleData));
374+
int* rule_ids = (int*)malloc(num_tests * sizeof(int));
375+
376+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "DELETE FROM mysql_query_rules");
377+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "LOAD MYSQL QUERY RULES TO RUNTIME");
378+
379+
// Insert test rules
380+
for (int i = 0; i < num_tests; i++) {
381+
generate_rule(&rules[i], (i + 1) * 1000); // Unique base per rule
382+
char* query = build_insert_query(proxysql_admin, &rules[i]);
383+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, query);
384+
free(query);
385+
386+
// Get last insert ID
387+
MYSQL_RES* res = mysql_store_result(proxysql_admin);
388+
if (!res && mysql_field_count(proxysql_admin) == 0) {
389+
mysql_free_result(res);
390+
//rule_ids[i] = mysql_insert_id(proxysql_admin); // not supported in admin
391+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "SELECT last_insert_rowid()");
392+
MYSQL_ROW row;
393+
res = mysql_store_result(proxysql_admin);
394+
while ((row = mysql_fetch_row(res))) {
395+
rule_ids[i] = atoll(row[0]);
396+
}
397+
mysql_free_result(res);
398+
} else {
399+
diag("Failed to get rule_id for rule %d", i);
400+
if (res) mysql_free_result(res);
401+
continue;
402+
}
403+
}
404+
405+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "LOAD MYSQL QUERY RULES TO RUNTIME");
406+
407+
diag(">>>> Checking runtime_mysql_query_rules table...");
408+
// Check rules in runtime table
409+
for (int i = 0; i < num_tests; i++) {
410+
char query[256];
411+
sprintf(query, "SELECT * FROM runtime_mysql_query_rules WHERE rule_id = %d", rule_ids[i]);
412+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, query);
413+
MYSQL_RES* res = mysql_store_result(proxysql_admin);
414+
if (!res || mysql_num_rows(res) == 0) {
415+
fprintf(stderr, "Rule %d not found", rule_ids[i]);
416+
if (res) mysql_free_result(res);
417+
continue;
418+
}
419+
420+
ok(check_result(res, &rules[i], true), "Rule should match (%d)", rule_ids[i]);
421+
mysql_free_result(res);
422+
}
423+
424+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "DROP TABLE IF EXISTS mysql_query_rules_4867");
425+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "CREATE TABLE mysql_query_rules_4867 AS SELECT * FROM disk.mysql_query_rules");
426+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "SAVE MYSQL QUERY RULES TO DISK");
427+
428+
diag(">>>> Checking disk.mysql_query_rules table...");
429+
// Check rules in runtime table
430+
for (int i = 0; i < num_tests; i++) {
431+
char query[256];
432+
sprintf(query, "SELECT * FROM disk.mysql_query_rules WHERE rule_id = %d", rule_ids[i]);
433+
434+
if (mysql_query(proxysql_admin, query)) {
435+
fprintf(stderr, "File %s, line %d, Error: %s (%s)\n", __FILE__, __LINE__, mysql_error(proxysql_admin), query);
436+
goto restore_mysql_query_rules;
437+
}
438+
MYSQL_RES* res = mysql_store_result(proxysql_admin);
439+
if (!res || mysql_num_rows(res) == 0) {
440+
fprintf(stderr, "Rule %d not found", rule_ids[i]);
441+
if (res) mysql_free_result(res);
442+
continue;
443+
}
444+
ok(check_result(res, &rules[i], false), "Rule should match (%d)", rule_ids[i]);
445+
mysql_free_result(res);
446+
}
447+
448+
restore_mysql_query_rules:
449+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "DELETE FROM disk.mysql_query_rules");
450+
MYSQL_QUERY_ON_ERR_CLEANUP(proxysql_admin, "INSERT INTO disk.mysql_query_rules SELECT * FROM mysql_query_rules_4867");
451+
452+
cleanup:
453+
for (int i = 0; i < num_tests; i++) {
454+
free(rules[i].username);
455+
free(rules[i].schemaname);
456+
free(rules[i].client_addr);
457+
free(rules[i].proxy_addr);
458+
free(rules[i].match_digest);
459+
free(rules[i].match_pattern);
460+
free(rules[i].replace_pattern);
461+
free(rules[i].error_msg);
462+
free(rules[i].OK_msg);
463+
free(rules[i].attributes);
464+
free(rules[i].comment);
465+
}
466+
free(rules);
467+
free(rule_ids);
468+
469+
return exit_status();
470+
}

‎test/tap/tests/pgsql-reg_test_4867_query_rules-t.cpp

+574
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.