diff --git a/libmariadb/ma_default.c b/libmariadb/ma_default.c index 064d1c03..17670e8d 100644 --- a/libmariadb/ma_default.c +++ b/libmariadb/ma_default.c @@ -39,6 +39,12 @@ static const char *ini_exts[]= {"cnf", 0}; char **configuration_dirs= NULL; #define MAX_CONFIG_DIRS 6 +my_bool _mariadb_read_options(MYSQL *mysql, + const char *config_dir, + const char *config_file, + const char *group, + unsigned int recursion); + static int add_cfg_dir(char **cfg_dirs, const char *directory) { int i; @@ -139,7 +145,8 @@ static my_bool is_group(char *ptr, const char **groups) static my_bool _mariadb_read_options_from_file(MYSQL *mysql, const char *config_file, - const char *group) + const char *group, + unsigned int recursion) { uint line=0; my_bool read_values= 0, found_group= 0, is_escaped= 0, is_quoted= 0; @@ -175,6 +182,23 @@ static my_bool _mariadb_read_options_from_file(MYSQL *mysql, is_quoted= !is_quoted; continue; } + /* CONC- 327: !includedir and !include */ + if (*ptr == '!') + { + char *val; + ptr++; + if (!(val= strchr(ptr, ' '))) + continue; + *val++= 0; + end= strchr(val, 0); + for ( ; isspace(end[-1]) ; end--) ; /* Remove end space */ + *end= 0; + if (!strcmp(ptr, "includedir")) + _mariadb_read_options(mysql, (const char *)val, NULL, group, recursion + 1); + else if (!strcmp(ptr, "include")) + _mariadb_read_options(mysql, NULL, (const char *)val, group, recursion + 1); + continue; + } if (*ptr == '#' || *ptr == ';' || !*ptr) continue; is_escaped= (*ptr == '\\'); @@ -286,19 +310,37 @@ err: my_bool _mariadb_read_options(MYSQL *mysql, + const char *config_dir, const char *config_file, - const char *group) + const char *group, + unsigned int recursion) { int i= 0, exts, errors= 0; char filename[FN_REFLEN + 1]; + unsigned int recursion_stop= 64; #ifndef _WIN32 char *env; #endif - if (config_file) - return _mariadb_read_options_from_file(mysql, config_file, group); + if (recursion >= recursion_stop) + return 1; + + if (config_file && config_file[0]) + return _mariadb_read_options_from_file(mysql, config_file, group, recursion); + + if (config_dir && config_dir[0]) + { + for (exts= 0; ini_exts[exts]; exts++) + { + snprintf(filename, FN_REFLEN, + "%s%cmy.%s", config_dir, FN_LIBCHAR, ini_exts[exts]); + if (!access(filename, R_OK)) + errors+= _mariadb_read_options_from_file(mysql, filename, group, recursion); + } + return errors; + } for (i=0; i < MAX_CONFIG_DIRS && configuration_dirs[i]; i++) { @@ -307,7 +349,7 @@ my_bool _mariadb_read_options(MYSQL *mysql, snprintf(filename, FN_REFLEN, "%s%cmy.%s", configuration_dirs[i], FN_LIBCHAR, ini_exts[exts]); if (!access(filename, R_OK)) - errors+= _mariadb_read_options_from_file(mysql, filename, group); + errors+= _mariadb_read_options_from_file(mysql, filename, group, recursion); } } #ifndef _WIN32 @@ -319,7 +361,7 @@ my_bool _mariadb_read_options(MYSQL *mysql, snprintf(filename, FN_REFLEN, "%s%c.my.%s", env, FN_LIBCHAR, ini_exts[exts]); if (!access(filename, R_OK)) - errors+= _mariadb_read_options_from_file(mysql, filename, group); + errors+= _mariadb_read_options_from_file(mysql, filename, group, recursion); } } #endif diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index f5227afb..000e18ef 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -106,8 +106,7 @@ extern int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row); extern int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row); extern int mthd_stmt_read_all_rows(MYSQL_STMT *stmt); extern void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt); -extern my_bool _mariadb_read_options(MYSQL *mysql, const char *config_file, - char *group); +extern my_bool _mariadb_read_options(MYSQL *mysql, const char *dir, const char *config_file, char *group, unsigned int recursion); extern unsigned char *mysql_net_store_length(unsigned char *packet, size_t length); extern void @@ -1210,10 +1209,10 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, /* use default options */ if (mysql->options.my_cnf_file || mysql->options.my_cnf_group) { - _mariadb_read_options(mysql, + _mariadb_read_options(mysql, NULL, (mysql->options.my_cnf_file ? mysql->options.my_cnf_file : NULL), - mysql->options.my_cnf_group); + mysql->options.my_cnf_group, 0); free(mysql->options.my_cnf_file); free(mysql->options.my_cnf_group); mysql->options.my_cnf_file=mysql->options.my_cnf_group=0; diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index 8f1daa92..c24c7254 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1026,6 +1026,9 @@ static int test_reset(MYSQL *mysql) if (mysql_get_server_version(mysql) < 100200) return SKIP; + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "CREATE TABLE t1 (a int)"); check_mysql_rc(rc, mysql); @@ -1415,10 +1418,82 @@ static int test_conc317(MYSQL *unused __attribute__((unused))) mysql_close(mysql); return OK; } + +static int test_conc327(MYSQL *unused __attribute__((unused))) +{ + MYSQL *mysql; + my_bool reconnect = 0; + FILE *fp1= NULL, *fp2= NULL; + const char *env= getenv("MYSQL_TMP_DIR"); + char cnf_file1[FN_REFLEN + 1]; + char cnf_file2[FN_REFLEN + 1]; + + if (travis_test) + return SKIP; + + if (!env) + env= "/tmp"; + + setenv("HOME", env, 1); + + snprintf(cnf_file1, FN_REFLEN, "%s%c.my.cnf", env, FN_LIBCHAR); + snprintf(cnf_file2, FN_REFLEN, "%s%c.my.tmp", env, FN_LIBCHAR); + + FAIL_IF(!access(cnf_file1, R_OK), "access"); + + fp1= fopen(cnf_file1, "w"); + fp2= fopen(cnf_file2, "w"); + FAIL_IF(!fp1 || !fp2, "fopen failed"); + + fprintf(fp1, "!include %s\n", cnf_file2); + + fprintf(fp2, "[client]\ndefault-character-set = latin2\nreconnect= 1\n"); + fclose(fp1); + fclose(fp2); + + mysql= mysql_init(NULL); + mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, ""); + my_test_connect(mysql, hostname, username, password, + schema, 0, socketname, 0); + + remove(cnf_file1); + remove(cnf_file2); + + FAIL_IF(strcmp(mysql_character_set_name(mysql), "latin2"), "expected charset latin2"); + mysql_get_optionv(mysql, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_IF(reconnect != 1, "expected reconnect=1"); + mysql_close(mysql); + + snprintf(cnf_file1, FN_REFLEN, "%s%cmy.cnf", env, FN_LIBCHAR); + fp1= fopen(cnf_file1, "w"); + fp2= fopen(cnf_file2, "w"); + FAIL_IF(!fp1 || !fp2, "fopen failed"); + + fprintf(fp2, "!includedir %s\n", env); + + fprintf(fp1, "[client]\ndefault-character-set = latin2\nreconnect= 1\n"); + fclose(fp1); + fclose(fp2); + mysql= mysql_init(NULL); + mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, cnf_file2); + my_test_connect(mysql, hostname, username, password, + schema, 0, socketname, 0); + + remove(cnf_file1); + remove(cnf_file2); + + FAIL_IF(strcmp(mysql_character_set_name(mysql), "latin2"), "expected charset latin2"); + mysql_get_optionv(mysql, MYSQL_OPT_RECONNECT, &reconnect); + FAIL_IF(reconnect != 1, "expected reconnect=1"); + mysql_close(mysql); + + return OK; +} #endif struct my_tests_st my_tests[] = { #ifndef WIN32 + {"test_conc327", test_conc327, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc317", test_conc317, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, #endif {"test_conc315", test_conc315, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},