Commit 756b00d8 authored by Anushree Prakash B's avatar Anushree Prakash B

Bug#25340722 - PRINT BINARY DATA AS HEX IN THE MYSQL

               CLIENT (CONTRIBUTION)

DESCRIPTION:
============
Binary data should be printed as hex in the mysql client
when the option binary-as-hex is enabled.

ANALYSIS:
=========
The fix deals only with mysql command line client.
It does not change, at all, the data sent to the
applications. Printing binary data as hex also
allows to use the output in the where clause
of the query.

FIX:
====
A new option 'binary-as-hex' is introduced to print the
binary contents as hex in the mysql client. The option
is disabled by default. When the option is enabled, we
convert the binary data to hex before printing the
contents irrespective of whether it is in tabular,
xml or html format.
parent 65ea61fe
...@@ -142,7 +142,7 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0, ...@@ -142,7 +142,7 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0,
default_pager_set= 0, opt_sigint_ignore= 0, default_pager_set= 0, opt_sigint_ignore= 0,
auto_vertical_output= 0, auto_vertical_output= 0,
show_warnings= 0, executing_query= 0, interrupted_query= 0, show_warnings= 0, executing_query= 0, interrupted_query= 0,
ignore_spaces= 0; ignore_spaces= 0, opt_binhex= 0;
static my_bool debug_info_flag, debug_check_flag; static my_bool debug_info_flag, debug_check_flag;
static my_bool column_types_flag; static my_bool column_types_flag;
static my_bool preserve_comments= 0; static my_bool preserve_comments= 0;
...@@ -1392,6 +1392,8 @@ static struct my_option my_long_options[] = ...@@ -1392,6 +1392,8 @@ static struct my_option my_long_options[] =
{"batch", 'B', {"batch", 'B',
"Don't use history file. Disable interactive behavior. (Enables --silent.)", "Don't use history file. Disable interactive behavior. (Enables --silent.)",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"binary-as-hex", 'b', "Print binary data as hex", &opt_binhex, &opt_binhex,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"character-sets-dir", OPT_CHARSETS_DIR, {"character-sets-dir", OPT_CHARSETS_DIR,
"Directory for character set files.", &charsets_dir, "Directory for character set files.", &charsets_dir,
&charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
...@@ -3101,7 +3103,8 @@ com_go(String *buffer,char *line __attribute__((unused))) ...@@ -3101,7 +3103,8 @@ com_go(String *buffer,char *line __attribute__((unused)))
print_table_data_html(result); print_table_data_html(result);
else if (opt_xml) else if (opt_xml)
print_table_data_xml(result); print_table_data_xml(result);
else if (vertical || (auto_vertical_output && (terminal_width < get_result_width(result)))) else if (vertical || (auto_vertical_output &&
(terminal_width < get_result_width(result))))
print_table_data_vertically(result); print_table_data_vertically(result);
else if (opt_silent && verbose <= 2 && !output_tables) else if (opt_silent && verbose <= 2 && !output_tables)
print_tab_data(result); print_tab_data(result);
...@@ -3320,6 +3323,41 @@ print_field_types(MYSQL_RES *result) ...@@ -3320,6 +3323,41 @@ print_field_types(MYSQL_RES *result)
} }
/* Used to determine if we should invoke print_as_hex for this field */
static bool
is_binary_field(MYSQL_FIELD *field)
{
if ((field->charsetnr == 63) &&
(field->type == MYSQL_TYPE_BIT ||
field->type == MYSQL_TYPE_BLOB ||
field->type == MYSQL_TYPE_LONG_BLOB ||
field->type == MYSQL_TYPE_MEDIUM_BLOB ||
field->type == MYSQL_TYPE_TINY_BLOB ||
field->type == MYSQL_TYPE_VAR_STRING ||
field->type == MYSQL_TYPE_STRING ||
field->type == MYSQL_TYPE_VARCHAR ||
field->type == MYSQL_TYPE_GEOMETRY))
return 1;
return 0;
}
/* Print binary value as hex literal (0x ...) */
static void
print_as_hex(FILE *output_file, const char *str, ulong len, ulong total_bytes_to_send)
{
const char *ptr= str, *end= ptr+len;
ulong i;
fprintf(output_file, "0x");
for(; ptr < end; ptr++)
fprintf(output_file, "%02X", *((uchar*)ptr));
for (i= 2*len+2; i < total_bytes_to_send; i++)
tee_putc((int)' ', output_file);
}
static void static void
print_table_data(MYSQL_RES *result) print_table_data(MYSQL_RES *result)
{ {
...@@ -3346,6 +3384,8 @@ print_table_data(MYSQL_RES *result) ...@@ -3346,6 +3384,8 @@ print_table_data(MYSQL_RES *result)
length=max(length,field->max_length); length=max(length,field->max_length);
if (length < 4 && !IS_NOT_NULL(field->flags)) if (length < 4 && !IS_NOT_NULL(field->flags))
length=4; // Room for "NULL" length=4; // Room for "NULL"
if (opt_binhex && is_binary_field(field))
length= 2 + length * 2;
field->max_length=length; field->max_length=length;
separator.fill(separator.length()+length+2,'-'); separator.fill(separator.length()+length+2,'-');
separator.append('+'); separator.append('+');
...@@ -3415,7 +3455,9 @@ print_table_data(MYSQL_RES *result) ...@@ -3415,7 +3455,9 @@ print_table_data(MYSQL_RES *result)
visible_length= charset_info->cset->numcells(charset_info, buffer, buffer + data_length); visible_length= charset_info->cset->numcells(charset_info, buffer, buffer + data_length);
extra_padding= data_length - visible_length; extra_padding= data_length - visible_length;
if (field_max_length > MAX_COLUMN_LENGTH) if (opt_binhex && is_binary_field(field))
print_as_hex(PAGER, cur[off], lengths[off], field_max_length);
else if (field_max_length > MAX_COLUMN_LENGTH)
tee_print_sized_data(buffer, data_length, MAX_COLUMN_LENGTH+extra_padding, FALSE); tee_print_sized_data(buffer, data_length, MAX_COLUMN_LENGTH+extra_padding, FALSE);
else else
{ {
...@@ -3548,11 +3590,15 @@ print_table_data_html(MYSQL_RES *result) ...@@ -3548,11 +3590,15 @@ print_table_data_html(MYSQL_RES *result)
if (interrupted_query) if (interrupted_query)
break; break;
ulong *lengths=mysql_fetch_lengths(result); ulong *lengths=mysql_fetch_lengths(result);
field= mysql_fetch_fields(result);
(void) tee_fputs("<TR>", PAGER); (void) tee_fputs("<TR>", PAGER);
for (uint i=0; i < mysql_num_fields(result); i++) for (uint i=0; i < mysql_num_fields(result); i++)
{ {
(void) tee_fputs("<TD>", PAGER); (void) tee_fputs("<TD>", PAGER);
xmlencode_print(cur[i], lengths[i]); if (opt_binhex && is_binary_field(&field[i]))
print_as_hex(PAGER, cur[i], lengths[i], lengths[i]);
else
xmlencode_print(cur[i], lengths[i]);
(void) tee_fputs("</TD>", PAGER); (void) tee_fputs("</TD>", PAGER);
} }
(void) tee_fputs("</TR>", PAGER); (void) tee_fputs("</TR>", PAGER);
...@@ -3588,7 +3634,10 @@ print_table_data_xml(MYSQL_RES *result) ...@@ -3588,7 +3634,10 @@ print_table_data_xml(MYSQL_RES *result)
if (cur[i]) if (cur[i])
{ {
tee_fprintf(PAGER, "\">"); tee_fprintf(PAGER, "\">");
xmlencode_print(cur[i], lengths[i]); if (opt_binhex && is_binary_field(&fields[i]))
print_as_hex(PAGER, cur[i], lengths[i], lengths[i]);
else
xmlencode_print(cur[i], lengths[i]);
tee_fprintf(PAGER, "</field>\n"); tee_fprintf(PAGER, "</field>\n");
} }
else else
...@@ -3635,23 +3684,28 @@ print_table_data_vertically(MYSQL_RES *result) ...@@ -3635,23 +3684,28 @@ print_table_data_vertically(MYSQL_RES *result)
{ {
unsigned int i; unsigned int i;
const char *p; const char *p;
if (opt_binhex && is_binary_field(field))
fprintf(PAGER, "0x");
for (i= 0, p= cur[off]; i < lengths[off]; i+= 1, p+= 1) for (i= 0, p= cur[off]; i < lengths[off]; i+= 1, p+= 1)
{ {
if (*p == '\0') if (opt_binhex && is_binary_field(field))
tee_putc((int)' ', PAGER); fprintf(PAGER, "%02X", *((uchar*)p));
else else
tee_putc((int)*p, PAGER); {
if (*p == '\0')
tee_putc((int)' ', PAGER);
else
tee_putc((int)*p, PAGER);
}
} }
tee_putc('\n', PAGER); tee_putc('\n', PAGER);
} }
else else
tee_fprintf(PAGER, "NULL\n"); tee_fprintf(PAGER, "NULL\n");
} }
} }
} }
/* print_warnings should be called right after executing a statement */ /* print_warnings should be called right after executing a statement */
static void print_warnings() static void print_warnings()
...@@ -3788,11 +3842,19 @@ print_tab_data(MYSQL_RES *result) ...@@ -3788,11 +3842,19 @@ print_tab_data(MYSQL_RES *result)
while ((cur = mysql_fetch_row(result))) while ((cur = mysql_fetch_row(result)))
{ {
lengths=mysql_fetch_lengths(result); lengths=mysql_fetch_lengths(result);
safe_put_field(cur[0],lengths[0]); field= mysql_fetch_fields(result);
if (opt_binhex && is_binary_field(&field[0]))
print_as_hex(PAGER, cur[0], lengths[0], lengths[0]);
else
safe_put_field(cur[0],lengths[0]);
for (uint off=1 ; off < mysql_num_fields(result); off++) for (uint off=1 ; off < mysql_num_fields(result); off++)
{ {
(void) tee_fputs("\t", PAGER); (void) tee_fputs("\t", PAGER);
safe_put_field(cur[off], lengths[off]); if (opt_binhex && field && is_binary_field(&field[off]))
print_as_hex(PAGER, cur[off], lengths[off], lengths[off]);
else
safe_put_field(cur[off], lengths[off]);
} }
(void) tee_fputs("\n", PAGER); (void) tee_fputs("\n", PAGER);
} }
......
USE test;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (c1 TINYBLOB,
c2 BLOB,
c3 MEDIUMBLOB,
c4 LONGBLOB,
c5 TEXT,
c6 BIT(1),
c7 CHAR,
c8 VARCHAR(10),
c9 GEOMETRY) CHARACTER SET = binary;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` tinyblob,
`c2` blob,
`c3` mediumblob,
`c4` longblob,
`c5` blob,
`c6` bit(1) DEFAULT NULL,
`c7` binary(1) DEFAULT NULL,
`c8` varbinary(10) DEFAULT NULL,
`c9` geometry DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=binary
INSERT INTO t1 VALUES ('tinyblob-text readable', 'blob-text readable',
'mediumblob-text readable', 'longblob-text readable',
'text readable', b'1', 'c', 'variable',
POINT(1, 1));
CREATE TABLE t2(id int, `col1` binary(10),`col2` blob);
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) DEFAULT NULL,
`col1` binary(10) DEFAULT NULL,
`col2` blob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t2 VALUES (1, X'AB1234', X'123ABC'), (2, X'DE1234', X'123DEF');
#Print the table contents when binary-as-hex option is off.
SELECT * FROM t1;
c1 c2 c3 c4 c5 c6 c7 c8 c9
tinyblob-text readable blob-text readable mediumblob-text readable longblob-text readable text readable # c variable #
SELECT * FROM t2;
id col1 col2
1 # #
2 # #
#Print the table contents after turning on the binary-as-hex option
#Print the table contents in tab format
c1 c2 c3 c4 c5 c6 c7 c8 c9
0x74696E79626C6F622D74657874207265616461626C65 0x626C6F622D74657874207265616461626C65 0x6D656469756D626C6F622D74657874207265616461626C65 0x6C6F6E67626C6F622D74657874207265616461626C65 0x74657874207265616461626C65 0x01 0x63 0x7661726961626C65 0x000000000101000000000000000000F03F000000000000F03F
id col1 col2
1 0xAB123400000000000000 0x123ABC
2 0xDE123400000000000000 0x123DEF
#Print the table contents in table format
+------------------------------------------------+----------------------------------------+----------------------------------------------------+------------------------------------------------+------------------------------+------------+------------+--------------------+------------------------------------------------------+
| c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 |
+------------------------------------------------+----------------------------------------+----------------------------------------------------+------------------------------------------------+------------------------------+------------+------------+--------------------+------------------------------------------------------+
| 0x74696E79626C6F622D74657874207265616461626C65 | 0x626C6F622D74657874207265616461626C65 | 0x6D656469756D626C6F622D74657874207265616461626C65 | 0x6C6F6E67626C6F622D74657874207265616461626C65 | 0x74657874207265616461626C65 | 0x01 | 0x63 | 0x7661726961626C65 | 0x000000000101000000000000000000F03F000000000000F03F |
+------------------------------------------------+----------------------------------------+----------------------------------------------------+------------------------------------------------+------------------------------+------------+------------+--------------------+------------------------------------------------------+
+------+------------------------+------------+
| id | col1 | col2 |
+------+------------------------+------------+
| 1 | 0xAB123400000000000000 | 0x123ABC |
+------+------------------------+------------+
#Print the table contents vertically
*************************** 1. row ***************************
c1: 0x74696E79626C6F622D74657874207265616461626C65
c2: 0x626C6F622D74657874207265616461626C65
c3: 0x6D656469756D626C6F622D74657874207265616461626C65
c4: 0x6C6F6E67626C6F622D74657874207265616461626C65
c5: 0x74657874207265616461626C65
c6: 0x01
c7: 0x63
c8: 0x7661726961626C65
c9: 0x000000000101000000000000000000F03F000000000000F03F
#Print the table contents in xml format
<?xml version="1.0"?>
<resultset statement="SELECT * FROM t1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<field name="c1">0x74696E79626C6F622D74657874207265616461626C65</field>
<field name="c2">0x626C6F622D74657874207265616461626C65</field>
<field name="c3">0x6D656469756D626C6F622D74657874207265616461626C65</field>
<field name="c4">0x6C6F6E67626C6F622D74657874207265616461626C65</field>
<field name="c5">0x74657874207265616461626C65</field>
<field name="c6">0x01</field>
<field name="c7">0x63</field>
<field name="c8">0x7661726961626C65</field>
<field name="c9">0x000000000101000000000000000000F03F000000000000F03F</field>
</row>
</resultset>
<?xml version="1.0"?>
<resultset statement="SELECT * FROM t2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<field name="id">1</field>
<field name="col1">0xAB123400000000000000</field>
<field name="col2">0x123ABC</field>
</row>
<row>
<field name="id">2</field>
<field name="col1">0xDE123400000000000000</field>
<field name="col2">0x123DEF</field>
</row>
</resultset>
#Print the table contents in html format
<TABLE BORDER=1><TR><TH>c1</TH><TH>c2</TH><TH>c3</TH><TH>c4</TH><TH>c5</TH><TH>c6</TH><TH>c7</TH><TH>c8</TH><TH>c9</TH></TR><TR><TD>0x74696E79626C6F622D74657874207265616461626C65</TD><TD>0x626C6F622D74657874207265616461626C65</TD><TD>0x6D656469756D626C6F622D74657874207265616461626C65</TD><TD>0x6C6F6E67626C6F622D74657874207265616461626C65</TD><TD>0x74657874207265616461626C65</TD><TD>0x01</TD><TD>0x63</TD><TD>0x7661726961626C65</TD><TD>0x000000000101000000000000000000F03F000000000000F03F</TD></TR></TABLE><TABLE BORDER=1><TR><TH>id</TH><TH>col1</TH><TH>col2</TH></TR><TR><TD>1</TD><TD>0xAB123400000000000000</TD><TD>0x123ABC</TD></TR><TR><TD>2</TD><TD>0xDE123400000000000000</TD><TD>0x123DEF</TD></TR></TABLE>DROP TABLE t1, t2;
# === Purpose ===
# The purpose of this test case is to make
# sure that the binary data in tables is printed
# as hex when the option binary-as-hex is enabled.
#
# === Related bugs and/or worklogs ===
# Bug #25340722 - PRINT BINARY DATA AS HEX IN THE MYSQL
# CLIENT (CONTRIBUTION)
#
# Save the initial number of concurrent sessions
--source include/count_sessions.inc
--source include/not_embedded.inc
USE test;
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
--enable_warnings
CREATE TABLE t1 (c1 TINYBLOB,
c2 BLOB,
c3 MEDIUMBLOB,
c4 LONGBLOB,
c5 TEXT,
c6 BIT(1),
c7 CHAR,
c8 VARCHAR(10),
c9 GEOMETRY) CHARACTER SET = binary;
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES ('tinyblob-text readable', 'blob-text readable',
'mediumblob-text readable', 'longblob-text readable',
'text readable', b'1', 'c', 'variable',
POINT(1, 1));
CREATE TABLE t2(id int, `col1` binary(10),`col2` blob);
SHOW CREATE TABLE t2;
INSERT INTO t2 VALUES (1, X'AB1234', X'123ABC'), (2, X'DE1234', X'123DEF');
--echo #Print the table contents when binary-as-hex option is off.
--replace_column 6 # 9 #
SELECT * FROM t1;
--replace_column 2 # 3 #
SELECT * FROM t2;
--echo #Print the table contents after turning on the binary-as-hex option
--echo
--echo #Print the table contents in tab format
--echo
--exec $MYSQL test --binary-as-hex -e "SELECT * FROM t1; SELECT * FROM t2;"
--echo
--echo #Print the table contents in table format
--echo
--exec $MYSQL test --binary-as-hex --table -e "SELECT * FROM t1; SELECT * FROM t2 WHERE col2=0x123ABC;"
--echo
--echo #Print the table contents vertically
--echo
--exec $MYSQL test --binary-as-hex --vertical -e "SELECT * FROM t1;"
--echo
--echo #Print the table contents in xml format
--echo
--exec $MYSQL test --binary-as-hex --xml -e "SELECT * FROM t1; SELECT * FROM t2;"
--echo
--echo #Print the table contents in html format
--echo
--exec $MYSQL test --binary-as-hex --html -e "SELECT * FROM t1; SELECT * FROM t2;"
#Cleanup
DROP TABLE t1, t2;
# Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc
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