Skip to content

Commit 99e5ae3

Browse files
vaintroubvuvova
authored andcommitted
MDEV-27090 Windows client - ReadConsoleA does not work correctly with UTF8 codepage
Corresponding Windows bug microsoft/terminal#4551 Use ReadConsoleW instead and convert to console's input codepage, to workaround. Also, disable VT sequences in the console output, as we do not knows what type of data comes with SELECT, we do not want VT escapes there. Remove my_cgets()
1 parent 9e9b211 commit 99e5ae3

File tree

4 files changed

+95
-264
lines changed

4 files changed

+95
-264
lines changed

client/mysql.cc

Lines changed: 95 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,7 @@ extern "C" {
8888
#endif /* defined(HAVE_CURSES_H) && defined(HAVE_TERM_H) */
8989

9090
#undef bcmp // Fix problem with new readline
91-
#if defined(_WIN32)
92-
#include <conio.h>
93-
#else
91+
#if !defined(_WIN32)
9492
# ifdef __APPLE__
9593
# include <editline/readline.h>
9694
# else
@@ -104,6 +102,98 @@ extern "C" {
104102
#endif
105103
}
106104

105+
static CHARSET_INFO *charset_info= &my_charset_latin1;
106+
107+
#if defined(_WIN32)
108+
/*
109+
Set console mode for the whole duration of the client session.
110+
111+
We need for input
112+
- line input (i.e read lines from console)
113+
- echo typed characters
114+
- "cooked" mode, i.e we do not want to handle all keystrokes,
115+
like DEL etc ourselves, yet. We might want handle keystrokes
116+
in the future, to implement tab completion, and better
117+
(multiline) history.
118+
119+
Disable VT escapes for the output.We do not know what kind of escapes SELECT would return.
120+
*/
121+
struct Console_mode
122+
{
123+
HANDLE in= GetStdHandle(STD_INPUT_HANDLE);
124+
HANDLE out= GetStdHandle(STD_OUTPUT_HANDLE);
125+
DWORD mode_in=0;
126+
DWORD mode_out=0;
127+
128+
enum {STDIN_CHANGED = 1, STDOUT_CHANGED = 2};
129+
int changes=0;
130+
131+
Console_mode()
132+
{
133+
if (in && in != INVALID_HANDLE_VALUE && GetConsoleMode(in, &mode_in))
134+
{
135+
SetConsoleMode(in, ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT);
136+
changes |= STDIN_CHANGED;
137+
}
138+
139+
if (out && out != INVALID_HANDLE_VALUE && GetConsoleMode(out, &mode_out))
140+
{
141+
#ifdef ENABLE_VIRTUAL_TERMINAL_INPUT
142+
SetConsoleMode(out, mode_out & ~ENABLE_VIRTUAL_TERMINAL_INPUT);
143+
changes |= STDOUT_CHANGED;
144+
#endif
145+
}
146+
}
147+
148+
~Console_mode()
149+
{
150+
if (changes & STDIN_CHANGED)
151+
SetConsoleMode(in, mode_in);
152+
153+
if(changes & STDOUT_CHANGED)
154+
SetConsoleMode(out, mode_out);
155+
}
156+
};
157+
158+
static Console_mode my_conmode;
159+
160+
#define MAX_CGETS_LINE_LEN 65535
161+
/** Read line from console, chomp EOL*/
162+
static char *win_readline()
163+
{
164+
static wchar_t wstrbuf[MAX_CGETS_LINE_LEN];
165+
static char strbuf[MAX_CGETS_LINE_LEN * 4];
166+
167+
DWORD nchars= 0;
168+
uint len= 0;
169+
SetLastError(0);
170+
if (!ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), wstrbuf, MAX_CGETS_LINE_LEN-1,
171+
&nchars, NULL))
172+
goto err;
173+
if (nchars == 0 && GetLastError() == ERROR_OPERATION_ABORTED)
174+
goto err;
175+
176+
for (;nchars > 0; nchars--)
177+
{
178+
if (wstrbuf[nchars - 1] != '\n' && wstrbuf[nchars - 1] != '\r')
179+
break;
180+
}
181+
182+
if (nchars > 0)
183+
{
184+
uint errors;
185+
len= my_convert(strbuf, sizeof(strbuf), charset_info,
186+
(const char *) wstrbuf, nchars * sizeof(wchar_t),
187+
&my_charset_utf16le_bin, &errors);
188+
}
189+
strbuf[len]= 0;
190+
return strbuf;
191+
err:
192+
return NULL;
193+
}
194+
#endif
195+
196+
107197
#ifdef HAVE_VIDATTR
108198
static int have_curses= 0;
109199
static void my_vidattr(chtype attrs)
@@ -208,7 +298,6 @@ unsigned short terminal_width= 80;
208298

209299
static uint opt_protocol=0;
210300
static const char *opt_protocol_type= "";
211-
static CHARSET_INFO *charset_info= &my_charset_latin1;
212301

213302
static uint protocol_to_force= MYSQL_PROTOCOL_DEFAULT;
214303

@@ -2033,11 +2122,6 @@ static int get_options(int argc, char **argv)
20332122

20342123
static int read_and_execute(bool interactive)
20352124
{
2036-
#if defined(_WIN32)
2037-
String tmpbuf;
2038-
String buffer;
2039-
#endif
2040-
20412125
char *line= NULL;
20422126
char in_string=0;
20432127
ulong line_number=0;
@@ -2115,26 +2199,7 @@ static int read_and_execute(bool interactive)
21152199

21162200
#if defined(_WIN32)
21172201
tee_fputs(prompt, stdout);
2118-
if (!tmpbuf.is_alloced())
2119-
tmpbuf.alloc(65535);
2120-
tmpbuf.length(0);
2121-
buffer.length(0);
2122-
size_t clen;
2123-
do
2124-
{
2125-
line= my_cgets((char*)tmpbuf.ptr(), tmpbuf.alloced_length()-1, &clen);
2126-
buffer.append(line, clen);
2127-
/*
2128-
if we got buffer fully filled than there is a chance that
2129-
something else is still in console input buffer
2130-
*/
2131-
} while (tmpbuf.alloced_length() <= clen);
2132-
/*
2133-
An empty line is returned from my_cgets when there's error reading :
2134-
Ctrl-c for example
2135-
*/
2136-
if (line)
2137-
line= buffer.c_ptr();
2202+
line= win_readline();
21382203
#else
21392204
if (opt_outfile)
21402205
fputs(prompt, OUTFILE);
@@ -2201,10 +2266,7 @@ static int read_and_execute(bool interactive)
22012266
}
22022267
}
22032268

2204-
#if defined(_WIN32)
2205-
buffer.free();
2206-
tmpbuf.free();
2207-
#else
2269+
#if !defined(_WIN32)
22082270
if (interactive)
22092271
/*
22102272
free the last entered line.

include/my_sys.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,13 +1097,6 @@ extern void thd_increment_bytes_sent(void *thd, size_t length);
10971097
extern void thd_increment_bytes_received(void *thd, size_t length);
10981098
extern void thd_increment_net_big_packet_count(void *thd, size_t length);
10991099

1100-
#ifdef _WIN32
1101-
1102-
/* implemented in my_conio.c */
1103-
char* my_cgets(char *string, size_t clen, size_t* plen);
1104-
1105-
#endif
1106-
11071100
#include <mysql/psi/psi.h>
11081101

11091102
#ifdef HAVE_PSI_INTERFACE

mysys/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ IF (WIN32)
5454
my_wincond.c
5555
my_winerr.c
5656
my_winfile.c
57-
my_conio.c
5857
my_minidump.cc
5958
my_win_popen.cc)
6059
ENDIF()

0 commit comments

Comments
 (0)