Description:
When using MySQL Connector/C 6.1.2 (mysql_get_client_version() returns 60102) in a multi‑threaded program, calling mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "/absolute/path/to/mysql.cnf") to specify an option file sometimes works and sometimes is completely ignored – the behavior is non‑deterministic. With version 5.5.68 (50568) the same code always applies the option file correctly.
Observed behavior
Option file mysql.cnf content:
[client]
default-character-set=utf8
init-command="set names utf8"
Expected result: After connection, character_set_client and collation_connection should be utf8.
Actual result: Randomly, these variables remain at the default latin1 (e.g., query SHOW VARIABLES LIKE 'character_set_client' returns latin1).
mysql_options() always returns 0 (success), even when the option file is ignored.
Root cause analysis
The problem occurs only in multi‑threaded environments; a simple single‑threaded test does not reproduce it. Historical information indicates that Connector/C 6.1.0 introduced login‑file support (.mylogin.cnf) and used a global variable is_login_file to track whether a login file is being used. In versions 6.1.0 through 6.1.11, this variable is global, so concurrent threads interfere with each other: one thread modifying is_login_file can cause another thread’s option‑file parsing to be skipped, thus ignoring the ordinary option file set by MYSQL_READ_DEFAULT_FILE.
Version 5.5.68 does not have the login‑file feature and therefore lacks this global variable, making its behavior stable.
How to repeat:
Write a multi‑threaded C/C++ program, for example:
\\\\\\\\\\\\\\\\\\\\
#include <mysql.h>
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 10
#define HOST "localhost"
#define USER "root"
#define PASS "password"
#define DB "test"
void *thread_func(void *arg) {
MYSQL *mysql = mysql_init(NULL);
mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "/absolute/path/to/mysql.cnf");
if (!mysql_real_connect(mysql, HOST, USER, PASS, DB, 0, NULL, 0)) {
printf("Connect failed\n");
} else {
// Check character set
mysql_query(mysql, "SHOW VARIABLES LIKE 'character_set_client'");
MYSQL_RES *res = mysql_store_result(mysql);
MYSQL_ROW row = mysql_fetch_row(res);
printf("Thread %ld: character_set_client = %s\n", pthread_self(), row[1]);
mysql_free_result(res);
mysql_close(mysql);
}
return NULL;
}
int main() {
pthread_t threads[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++) {
pthread_create(&threads[i], NULL, thread_func, NULL);
}
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
\\\\\\\\\\\\\\\\\\\\
Compile and run the program repeatedly with Connector/C 6.1.2. Observe that some threads output latin1 (failure) and some output utf8 (success).
Run the same program with Connector/C 5.5.68 – all threads output utf8.
Suggested fix:
Change the is_login_file variable, used to indicate whether a login file is active, from a global variable to thread‑local storage to avoid race conditions in multi‑threaded environments. This fix has already been implemented in later releases (e.g., Connector/C 8.0 series). It is recommended to backport the fix to the 6.1 series, or to clearly document that users should upgrade to an unaffected version.
Description: When using MySQL Connector/C 6.1.2 (mysql_get_client_version() returns 60102) in a multi‑threaded program, calling mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "/absolute/path/to/mysql.cnf") to specify an option file sometimes works and sometimes is completely ignored – the behavior is non‑deterministic. With version 5.5.68 (50568) the same code always applies the option file correctly. Observed behavior Option file mysql.cnf content: [client] default-character-set=utf8 init-command="set names utf8" Expected result: After connection, character_set_client and collation_connection should be utf8. Actual result: Randomly, these variables remain at the default latin1 (e.g., query SHOW VARIABLES LIKE 'character_set_client' returns latin1). mysql_options() always returns 0 (success), even when the option file is ignored. Root cause analysis The problem occurs only in multi‑threaded environments; a simple single‑threaded test does not reproduce it. Historical information indicates that Connector/C 6.1.0 introduced login‑file support (.mylogin.cnf) and used a global variable is_login_file to track whether a login file is being used. In versions 6.1.0 through 6.1.11, this variable is global, so concurrent threads interfere with each other: one thread modifying is_login_file can cause another thread’s option‑file parsing to be skipped, thus ignoring the ordinary option file set by MYSQL_READ_DEFAULT_FILE. Version 5.5.68 does not have the login‑file feature and therefore lacks this global variable, making its behavior stable. How to repeat: Write a multi‑threaded C/C++ program, for example: \\\\\\\\\\\\\\\\\\\\ #include <mysql.h> #include <pthread.h> #include <stdio.h> #define NUM_THREADS 10 #define HOST "localhost" #define USER "root" #define PASS "password" #define DB "test" void *thread_func(void *arg) { MYSQL *mysql = mysql_init(NULL); mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "/absolute/path/to/mysql.cnf"); if (!mysql_real_connect(mysql, HOST, USER, PASS, DB, 0, NULL, 0)) { printf("Connect failed\n"); } else { // Check character set mysql_query(mysql, "SHOW VARIABLES LIKE 'character_set_client'"); MYSQL_RES *res = mysql_store_result(mysql); MYSQL_ROW row = mysql_fetch_row(res); printf("Thread %ld: character_set_client = %s\n", pthread_self(), row[1]); mysql_free_result(res); mysql_close(mysql); } return NULL; } int main() { pthread_t threads[NUM_THREADS]; for (int i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], NULL, thread_func, NULL); } for (int i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } return 0; } \\\\\\\\\\\\\\\\\\\\ Compile and run the program repeatedly with Connector/C 6.1.2. Observe that some threads output latin1 (failure) and some output utf8 (success). Run the same program with Connector/C 5.5.68 – all threads output utf8. Suggested fix: Change the is_login_file variable, used to indicate whether a login file is active, from a global variable to thread‑local storage to avoid race conditions in multi‑threaded environments. This fix has already been implemented in later releases (e.g., Connector/C 8.0 series). It is recommended to backport the fix to the 6.1 series, or to clearly document that users should upgrade to an unaffected version.