Commit a296c526 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub Committed by Sergei Golubchik

MDEV-26713 UTF8 support on Windows, mysql_upgrade_service preparation

- Tolerate situation, when datadir for service seems invalid/non-existing
prior to upgrade. It could be that my.ini contains legacy ANSI characters
for the data directory. Those can't be read correctly by
mysql_upgrade_service, which uses a different ANSI codepage(UTF8)
.
- schedule upgrade_config_file at later stage, because once we
convert it to UTF-8 (followup patch), this will render config file uselss
with the older version of mariadbd.exe

- Refactor upgrade_conf_file.cc, prepare for UTF-8 conversion.
parent a4fc41b6
......@@ -374,13 +374,17 @@ static void change_service_config()
Write datadir to my.ini, after converting backslashes to
unix style slashes.
*/
strcpy_s(buf, MAX_PATH, service_properties.datadir);
for(i= 0; buf[i]; i++)
if (service_properties.datadir[0])
{
if (buf[i] == '\\')
buf[i]= '/';
strcpy_s(buf, MAX_PATH, service_properties.datadir);
for (i= 0; buf[i]; i++)
{
if (buf[i] == '\\')
buf[i]= '/';
}
WritePrivateProfileString("mysqld", "datadir", buf,
service_properties.inifile);
}
WritePrivateProfileString("mysqld", "datadir",buf, service_properties.inifile);
/*
Remove basedir from defaults file, otherwise the service wont come up in
......@@ -465,13 +469,8 @@ int main(int argc, char **argv)
}
}
old_mysqld_exe_exists = (GetFileAttributes(service_properties.mysqld_exe) != INVALID_FILE_ATTRIBUTES);
log("Phase %d/%d: Fixing server config file%s", ++phase, max_phases, my_ini_exists ? "" : "(skipped)");
snprintf(my_ini_bck, sizeof(my_ini_bck), "%s.BCK", service_properties.inifile);
CopyFile(service_properties.inifile, my_ini_bck, FALSE);
upgrade_config_file(service_properties.inifile);
old_mysqld_exe_exists= (GetFileAttributes(service_properties.mysqld_exe) !=
INVALID_FILE_ATTRIBUTES);
bool do_start_stop_server = old_mysqld_exe_exists && initial_service_state != SERVICE_RUNNING;
log("Phase %d/%d: Start and stop server in the old version, to avoid crash recovery %s", ++phase, max_phases,
......@@ -526,6 +525,14 @@ int main(int argc, char **argv)
start_duration_ms += 500;
}
}
log("Phase %d/%d: Fixing server config file%s", ++phase, max_phases,
my_ini_exists ? "" : "(skipped)");
snprintf(my_ini_bck, sizeof(my_ini_bck), "%s.BCK",
service_properties.inifile);
CopyFile(service_properties.inifile, my_ini_bck, FALSE);
upgrade_config_file(service_properties.inifile);
/*
Start mysqld.exe as non-service skipping privileges (so we do not
care about the password). But disable networking and enable pipe
......
......@@ -158,51 +158,103 @@ static int cmp_strings(const void* a, const void *b)
return strcmp((const char *)a, *(const char **)b);
}
/**
Convert file from a previous version, by removing
*/
int upgrade_config_file(const char *myini_path)
#define MY_INI_SECTION_SIZE 32 * 1024 + 3
int fix_section(const char *myini_path, const char *section_name,
bool is_server)
{
#define MY_INI_SECTION_SIZE 32*1024 +3
if (!is_server)
return 0;
static char section_data[MY_INI_SECTION_SIZE];
for (const char *section_name : { "mysqld","server","mariadb" })
DWORD size= GetPrivateProfileSection(section_name, section_data,
MY_INI_SECTION_SIZE, myini_path);
if (size == MY_INI_SECTION_SIZE - 2)
{
DWORD size = GetPrivateProfileSection(section_name, section_data, MY_INI_SECTION_SIZE, myini_path);
if (size == MY_INI_SECTION_SIZE - 2)
{
return -1;
}
return -1;
}
for (char *keyval = section_data; *keyval; keyval += strlen(keyval) + 1)
for (char *keyval= section_data; *keyval; keyval += strlen(keyval)+1)
{
char varname[256];
char *value;
char *key_end= strchr(keyval, '=');
if (!key_end)
key_end= keyval + strlen(keyval);
if (key_end - keyval > sizeof(varname))
continue;
value= key_end + 1;
// Check if variable should be removed from config.
// First, copy and normalize (convert dash to underscore) to variable
// names
for (char *p= keyval, *q= varname;; p++, q++)
{
char varname[256];
char *key_end = strchr(keyval, '=');
if (!key_end)
key_end = keyval+ strlen(keyval);
if (key_end - keyval > sizeof(varname))
continue;
// copy and normalize (convert dash to underscore) to variable names
for (char *p = keyval, *q = varname;; p++,q++)
if (p == key_end)
{
if (p == key_end)
{
*q = 0;
break;
}
*q = (*p == '-') ? '_' : *p;
*q= 0;
break;
}
const char *v = (const char *)bsearch(varname, removed_variables, sizeof(removed_variables) / sizeof(removed_variables[0]),
sizeof(char *), cmp_strings);
*q= (*p == '-') ? '_' : *p;
}
const char *v= (const char *) bsearch(varname, removed_variables, sizeof(removed_variables) / sizeof(removed_variables[0]),
sizeof(char *), cmp_strings);
if (v)
{
fprintf(stdout, "Removing variable '%s' from config file\n", varname);
// delete variable
*key_end = 0;
WritePrivateProfileString(section_name, keyval, 0, myini_path);
}
if (v)
{
fprintf(stdout, "Removing variable '%s' from config file\n", varname);
// delete variable
*key_end= 0;
WritePrivateProfileString(section_name, keyval, 0, myini_path);
}
}
return 0;
}
static bool is_mariadb_section(const char *name, bool *is_server)
{
if (strncmp(name, "mysql", 5)
&& strncmp(name, "mariadb", 7)
&& strcmp(name, "client")
&& strcmp(name, "client-server")
&& strcmp(name, "server"))
{
return false;
}
for (const char *section_name : {"mysqld", "server", "mariadb"})
if (*is_server= !strcmp(section_name, name))
break;
return *is_server;
}
/**
Convert file from a previous version, by removing obsolete variables
Also, fix values to be UTF8, if MariaDB is running in utf8 mode
*/
int upgrade_config_file(const char *myini_path)
{
static char all_sections[MY_INI_SECTION_SIZE];
int sz= GetPrivateProfileSectionNamesA(all_sections, MY_INI_SECTION_SIZE,
myini_path);
if (!sz)
return 0;
if (sz > MY_INI_SECTION_SIZE - 2)
{
fprintf(stderr, "Too many sections in config file\n");
return -1;
}
for (char *section= all_sections; *section; section+= strlen(section) + 1)
{
bool is_server_section;
if (is_mariadb_section(section, &is_server_section))
fix_section(myini_path, section, is_server_section);
}
return 0;
}
......@@ -134,6 +134,20 @@ static void get_datadir_from_ini(const char *ini, char *service_name, char *data
}
static int fix_and_check_datadir(mysqld_service_properties *props)
{
normalize_path(props->datadir, MAX_PATH);
/* Check if datadir really exists */
if (GetFileAttributes(props->datadir) != INVALID_FILE_ATTRIBUTES)
return 0;
/*
It is possible, that datadir contains some unconvertable character.
We just pretend not to know what's the data directory
*/
props->datadir[0]= 0;
return 0;
}
/*
Retrieve some properties from windows mysqld service binary path.
We're interested in ini file location and datadir, and also in version of
......@@ -284,16 +298,9 @@ int get_mysql_service_properties(const wchar_t *bin_path,
}
}
if (props->datadir[0])
{
normalize_path(props->datadir, MAX_PATH);
/* Check if datadir really exists */
if (GetFileAttributes(props->datadir) == INVALID_FILE_ATTRIBUTES)
goto end;
}
else
if (props->datadir[0] == 0 || fix_and_check_datadir(props))
{
/* There is no datadir in ini file, bail out.*/
/* There is no datadir in ini file, or non-existing dir, bail out.*/
goto end;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment