Skip to content

Commit d45cf75

Browse files
committed
MDEV-40551 Copy/Paste friendly output format for MariaDB Command Line Client
Copy/paste friendly output was only reachable by starting the client with --silent --skip-column-names, which cannot be done from a running interactive session. Add \S, a statement terminator which prints the result of one statement in the tab separated format without column names. com_silent() sets output_plain, opt_silent and column_names around com_go(), then restores them, the same way com_ego() handles vertical. output_plain selects print_tab_data() ahead of the vertical and table branches, so \S gives the same output whether the session was started plainly or with --table, --vertical or --silent. --html and --xml still win, matching \G.
1 parent f3b7fad commit d45cf75

5 files changed

Lines changed: 143 additions & 2 deletions

File tree

‎client/mysql.cc‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ enum ss_comment_type { SSC_NONE= 0, SSC_CONDITIONAL, SSC_HINT };
243243
static MYSQL mysql; /* The connection */
244244
static my_bool ignore_errors=0,wait_flag=0,quick=0,
245245
connected=0,opt_raw_data=0,unbuffered=0,output_tables=0,
246+
output_plain=0,
246247
opt_rehash=1,skip_updates=0,safe_updates=0,one_database=0,
247248
opt_compress=0, using_opt_local_infile=0,
248249
vertical=0, line_numbers=1, column_names=1,opt_html=0,
@@ -324,7 +325,7 @@ extern "C" my_bool get_one_option(int optid, const struct my_option *opt,
324325
const char *argument);
325326
static int com_quit(String *str,char*),
326327
com_go(String *str,char*), com_ego(String *str,char*),
327-
com_print(String *str,char*),
328+
com_silent(String *str,char*), com_print(String *str,char*),
328329
com_help(String *str,char*), com_clear(String *str,char*),
329330
com_connect(String *str,char*), com_status(String *str,char*),
330331
com_use(String *str,char*), com_source(String *str, char*),
@@ -414,6 +415,8 @@ static COMMANDS commands[] = {
414415
{ "rehash", '#', com_rehash, 0, "Rebuild completion hash." },
415416
{ "sandbox", '-', com_sandbox, 0,
416417
"Disallow commands that access the file system (except \\P without an argument and \\e)." },
418+
{ "silent", 'S', com_silent, 0,
419+
"Send command to MariaDB server, display result without column names or borders."},
417420
{ "source", '.', com_source, 1,
418421
"Execute an SQL script file. Takes a file name as an argument."},
419422
{ "status", 's', com_status, 0, "Get status information from the server."},
@@ -3675,7 +3678,7 @@ static int com_go(String *buffer, char *)
36753678
#ifdef HAVE_READLINE
36763679
if (status.add_to_history)
36773680
{
3678-
const char *delim= vertical ? "\\G" : delimiter;
3681+
const char *delim= output_plain ? "\\S" : vertical ? "\\G" : delimiter;
36793682
buffer->append(delim, strlen(delim));
36803683
/* Append final command onto history */
36813684
fix_history(buffer);
@@ -3739,6 +3742,8 @@ static int com_go(String *buffer, char *)
37393742
print_table_data_html(result);
37403743
else if (opt_xml)
37413744
print_table_data_xml(result);
3745+
else if (output_plain)
3746+
print_tab_data(result);
37423747
else if (vertical || (auto_vertical_output &&
37433748
(terminal_width < get_result_width(result))))
37443749
print_table_data_vertically(result);
@@ -3879,6 +3884,24 @@ com_ego(String *buffer,char *line)
38793884
}
38803885

38813886

3887+
static int
3888+
com_silent(String *buffer,char *line)
3889+
{
3890+
int result;
3891+
uint old_opt_silent=opt_silent;
3892+
bool old_output_plain=output_plain;
3893+
bool old_column_names=column_names;
3894+
opt_silent=1;
3895+
output_plain=1;
3896+
column_names=0;
3897+
result=com_go(buffer,line);
3898+
opt_silent=old_opt_silent;
3899+
output_plain=old_output_plain;
3900+
column_names=old_column_names;
3901+
return result;
3902+
}
3903+
3904+
38823905
static const char *fieldtype2str(enum enum_field_types type)
38833906
{
38843907
switch (type) {

‎mysql-test/main/mysql-interactive.result‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,36 @@ Query OK, 0 rows affected
133133
MariaDB [test]> exit
134134
Bye
135135
# End of 11.8 tests
136+
#
137+
# MDEV-40551 Copy/Paste friendly output format for MariaDB Command Line Client
138+
#
139+
select 1 as a,
140+
2 as b\S
141+
^P
142+
select 3 as c;
143+
exit
144+
Welcome to the MariaDB monitor. Commands end with ; or \g.
145+
Your MariaDB connection id is X
146+
Server version: Y
147+
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
148+
149+
Help others discover MariaDB. Star it on GitHub: https://github.com/MariaDB/server
150+
151+
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
152+
153+
MariaDB [test]> select 1 as a,
154+
-> 2 as b\S
155+
1 2
156+
MariaDB [test]> select 1 as a, 2 as b\S
157+
1 2
158+
MariaDB [test]> select 3 as c;
159+
+---+
160+
| c |
161+
+---+
162+
| 3 |
163+
+---+
164+
1 row in set
165+
166+
MariaDB [test]> exit
167+
Bye
168+
# End of 13.1 tests

‎mysql-test/main/mysql-interactive.test‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,24 @@ if ($sys_errno == 127)
9090
remove_file $MYSQL_TMP_DIR/mysql_in;
9191

9292
--echo # End of 11.8 tests
93+
94+
--echo #
95+
--echo # MDEV-40551 Copy/Paste friendly output format for MariaDB Command Line Client
96+
--echo #
97+
# \S prints one statement without column names or borders. A multi line
98+
# statement is put in the history as a single line, and that line has to keep
99+
# the \S terminator. The \020 below is Ctrl-P, which recalls the previous
100+
# history entry.
101+
--exec printf 'select 1 as a,\n2 as b\\S\n\020\nselect 3 as c;\nexit\n' > $MYSQL_TMP_DIR/mysql_in
102+
let TERM=dumb;
103+
replace_regex /id is \d+/id is X/ /Server version: .*/Server version: Y/ / \(\d+\.\d+ sec\)// /MariaDB \[test\]> \r//;
104+
error 0,127;
105+
exec socat -t10 EXEC:"$MYSQL test",pty STDIO < $MYSQL_TMP_DIR/mysql_in;
106+
if ($sys_errno == 127)
107+
{
108+
remove_file $MYSQL_TMP_DIR/mysql_in;
109+
skip no socat;
110+
}
111+
remove_file $MYSQL_TMP_DIR/mysql_in;
112+
113+
--echo # End of 13.1 tests

‎mysql-test/main/mysql.result‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,41 @@ _
5555
Test 'go' command g
5656
a
5757
1
58+
_
59+
Test 'silent' command(no column names) S
60+
a b
61+
1 x
62+
1 x
63+
_
64+
Test 'silent' command(overrides --table) S
65+
1 x
66+
_
67+
Test 'silent' command(overrides --vertical) S
68+
1 x
69+
_
70+
Test 'silent' command(already silent) S
71+
1 x
72+
_
73+
Test 'silent' command(next statement unaffected) S
74+
1
75+
+---+
76+
| a |
77+
+---+
78+
| 1 |
79+
+---+
80+
1
81+
*************************** 1. row ***************************
82+
a: 1
83+
_
84+
Test 'silent' command(G unaffected) S
85+
1
86+
*************************** 1. row ***************************
87+
a: 1
88+
_
89+
Test 'silent' command(statement with a quoted delimiter) S
90+
analyze table t1;
91+
_
92+
Test 'silent' command(empty result and error) S
5893
drop table t1;
5994
create table t1(a int);
6095
lock tables t1 write;

‎mysql-test/main/mysql.test‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,35 @@ select "Test 'go' command(vertical output) \G" as "_";
3030
# Test 'go' command \g
3131
select "Test 'go' command \g" as "_";
3232
--exec $MYSQL test -e "select * from t1\g"
33+
#
34+
# MDEV-40551 Copy/Paste friendly output format for MariaDB Command Line Client
35+
#
36+
# Test 'silent' command \S
37+
select "Test 'silent' command(no column names) \S" as "_";
38+
--exec $MYSQL test -e "select 1 as a, 'x' as b;"
39+
--exec $MYSQL test -e "select 1 as a, 'x' as b\S"
40+
# \S overrides the session output format, whatever it was started with
41+
select "Test 'silent' command(overrides --table) \S" as "_";
42+
--exec $MYSQL test --table -e "select 1 as a, 'x' as b\S"
43+
select "Test 'silent' command(overrides --vertical) \S" as "_";
44+
--exec $MYSQL test --vertical -e "select 1 as a, 'x' as b\S"
45+
select "Test 'silent' command(already silent) \S" as "_";
46+
--exec $MYSQL test -s -s -e "select 1 as a, 'x' as b\S"
47+
# \S applies to its own statement only
48+
select "Test 'silent' command(next statement unaffected) \S" as "_";
49+
--exec $MYSQL test --table -e "select 1 as a\S select 1 as a;"
50+
--exec $MYSQL test --vertical -e "select 1 as a\S select 1 as a;"
51+
# \G after \S is still vertical
52+
select "Test 'silent' command(\G unaffected) \S" as "_";
53+
--exec $MYSQL test --table -e "select 1 as a\S select 1 as a\G"
54+
# The statement from the feature request
55+
select "Test 'silent' command(statement with a quoted delimiter) \S" as "_";
56+
--exec $MYSQL test --table -e "select concat('analyze table ', table_name, ';') from information_schema.tables where table_schema='test'\S"
57+
# \S on a statement that returns no rows, and on one that fails
58+
select "Test 'silent' command(empty result and error) \S" as "_";
59+
--exec $MYSQL test --table -e "select 1 as a from t1 where 1=0\S"
60+
--error 1
61+
--exec $MYSQL test --table -e "select nosuchcolumn from t1\S"
3362
--enable_query_log
3463
drop table t1;
3564

0 commit comments

Comments
 (0)