Skip to content

Commit 7d5cc04

Browse files
authored
feat(cli): add sql_delimiter set (#649)
* feat(cli): add sql_delimiter set * feat(cli): add sql_delimiter set
1 parent 61950a8 commit 7d5cc04

File tree

6 files changed

+53
-17
lines changed

6 files changed

+53
-17
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ prompt = ":) "
165165
| `expand` | Expand table format display, default auto, could be on/off/auto. |
166166
| `time` | Whether to show the time elapsed when executing queries. |
167167
| `multi_line` | Whether to allow multi-line input. |
168-
| `quote_string` | Whether to quote string values in table output format. |
168+
| `quote_string` | Whether to quote string values in table output format, default false. |
169+
| `sql_delimiter` | SQL delimiter, default `;`. |
169170

170171
## Commands in REPL
171172

cli/src/config.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub struct SettingsConfig {
4242
pub show_stats: Option<bool>,
4343
pub expand: Option<String>,
4444
pub quote_string: Option<bool>,
45+
pub sql_delimiter: Option<char>,
4546
pub max_display_rows: Option<usize>,
4647
pub max_col_width: Option<usize>,
4748
pub max_width: Option<usize>,
@@ -101,6 +102,7 @@ pub struct Settings {
101102
pub multi_line: bool,
102103
/// Whether to quote string values in table output format.
103104
pub quote_string: bool,
105+
pub sql_delimiter: char,
104106

105107
pub bind_address: String,
106108
pub bind_port: u16,
@@ -157,6 +159,7 @@ impl Settings {
157159
.map(|expand| expand.as_str().into())
158160
.unwrap_or_else(|| self.expand);
159161
self.quote_string = cfg.quote_string.unwrap_or(self.quote_string);
162+
self.sql_delimiter = cfg.sql_delimiter.unwrap_or(self.sql_delimiter);
160163
self.max_width = cfg.max_width.unwrap_or(self.max_width);
161164
self.max_col_width = cfg.max_col_width.unwrap_or(self.max_col_width);
162165
self.max_display_rows = cfg.max_display_rows.unwrap_or(self.max_display_rows);
@@ -197,6 +200,12 @@ impl Settings {
197200
"max_width" => self.max_width = cmd_value.parse()?,
198201
"max_col_width" => self.max_col_width = cmd_value.parse()?,
199202
"quote_string" => self.quote_string = cmd_value.parse()?,
203+
"sql_delimiter" => {
204+
if cmd_value.len() != 1 {
205+
return Err(anyhow!("SQL delimiter must be a single character"));
206+
}
207+
self.sql_delimiter = cmd_value.chars().next().unwrap()
208+
}
200209
_ => return Err(anyhow!("Unknown command: {}", cmd_name)),
201210
}
202211
Ok(())
@@ -261,6 +270,7 @@ impl Default for Settings {
261270
no_auto_complete: false,
262271
output_format: OutputFormat::Table,
263272
quote_style: OutputQuoteStyle::Necessary,
273+
sql_delimiter: ';',
264274
expand: ExpandMode::Auto,
265275
show_progress: false,
266276
max_display_rows: 1000,
@@ -269,7 +279,7 @@ impl Default for Settings {
269279
show_stats: false,
270280
time: None,
271281
multi_line: true,
272-
quote_string: true,
282+
quote_string: false,
273283
auto_open_browser: false,
274284
bind_address: "127.0.0.1".to_string(),
275285
bind_port: 0,

cli/src/session.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ impl Session {
484484
}
485485
self.query.push_str(line);
486486
let mut err = String::new();
487+
let delimiter = self.settings.sql_delimiter;
487488

488489
'Parser: loop {
489490
let mut is_valid = true;
@@ -493,7 +494,7 @@ impl Session {
493494
match token {
494495
Ok(token) => {
495496
// SQL end with `;` or `\G` in repl
496-
let is_end_query = matches!(token.kind, TokenKind::SemiColon);
497+
let is_end_query = token.text() == delimiter.to_string();
497498
let is_slash_g = self.is_repl
498499
&& (previous_token_backslash
499500
&& token.kind == TokenKind::Ident
@@ -503,8 +504,8 @@ impl Session {
503504
if is_end_query || is_slash_g {
504505
// push to current and continue the tokenizer
505506
let (sql, remain) = self.query.split_at(token.span.end as usize);
506-
if is_valid && !sql.is_empty() && sql.trim() != ";" {
507-
queries.push(sql.to_string());
507+
if is_valid && !sql.is_empty() && sql.trim() != delimiter.to_string() {
508+
queries.push(sql.trim_end_matches(delimiter).to_string());
508509
}
509510
self.query = remain.to_string();
510511
continue 'Parser;
@@ -532,15 +533,17 @@ impl Session {
532533
pub async fn handle_query(
533534
&mut self,
534535
is_repl: bool,
535-
query: &str,
536+
raw_query: &str,
536537
) -> Result<Option<ServerStats>> {
537-
let mut query = query.trim_end_matches(';').trim();
538+
let mut query = raw_query
539+
.trim_end_matches(self.settings.sql_delimiter)
540+
.trim();
538541
let mut expand = None;
539542
self.interrupted.store(false, Ordering::SeqCst);
540543

541544
if is_repl {
542545
if query.starts_with('!') {
543-
return self.handle_commands(query).await;
546+
return self.handle_commands(raw_query).await;
544547
}
545548
if query == "exit" || query == "quit" {
546549
return Ok(None);
@@ -601,12 +604,20 @@ impl Session {
601604
other => {
602605
if other.starts_with("!set") {
603606
let query = query[4..].split_whitespace().collect::<Vec<_>>();
604-
if query.len() != 2 {
607+
if query.len() == 3 {
608+
if query[1] != "=" {
609+
return Err(anyhow!(
610+
"Control command error, must be syntax of `!set cmd_name = cmd_value`."
611+
));
612+
}
613+
self.settings.inject_ctrl_cmd(query[0], query[2])?;
614+
} else if query.len() == 2 {
615+
self.settings.inject_ctrl_cmd(query[0], query[1])?;
616+
} else {
605617
return Err(anyhow!(
606-
"Control command error, must be syntax of `.cmd_name cmd_value`."
618+
"Control command error, must be syntax of `!set cmd_name = cmd_value` or `!set cmd_name cmd_value`."
607619
));
608620
}
609-
self.settings.inject_ctrl_cmd(query[0], query[1])?;
610621
} else if other.starts_with("!source") {
611622
let query = query[7..].trim();
612623
let path = Path::new(query);

cli/test.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ DATABEND_HOST=${DATABEND_HOST:-localhost}
2323
DATABEND_PORT=${DATABEND_PORT:-8000}
2424

2525
TEST_HANDLER=$1
26+
FILTER=$2
2627

2728
cargo build --bin bendsql
2829

@@ -44,6 +45,10 @@ esac
4445
export BENDSQL="${CARGO_TARGET_DIR}/debug/bendsql"
4546

4647
for tf in cli/tests/*.{sql,sh}; do
48+
if [[ -n "$FILTER" && ! $tf =~ $FILTER ]]; then
49+
continue
50+
fi
51+
4752
[[ -e "$tf" ]] || continue
4853
echo " Running test -- ${tf}"
4954
if [[ $tf == *.sh ]]; then
@@ -59,6 +64,11 @@ rm -f cli/tests/*.output
5964

6065
for tf in cli/tests/"$TEST_HANDLER"/*.{sql,sh}; do
6166
[[ -e "$tf" ]] || continue
67+
68+
if [[ -n "$FILTER" && ! $tf =~ $FILTER ]]; then
69+
continue
70+
fi
71+
6272
echo " Running test -- ${tf}"
6373
if [[ $tf == *.sh ]]; then
6474
suite=$(basename "${tf}" | sed -e 's#.sh##')

cli/tests/00-base.result

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Parser 'CREATE TABLE 🐳🍞(🐳🐳 INTEGER, 🍞🍞 INTEGER);' failed
2222
with error 'unable to recognize the rest tokens'
2323
Parser 'explain select * from c where b in ('x');' failed
2424
with error 'unable to recognize the rest tokens'
25+
aa
26+
"def add(a, b):
27+
a + b"
2528
3.00 3.00 0.0000000170141183460469231731687303715884105727000 -0.0000000170141183460469231731687303715884105727000
2629
Asia/Shanghai
2730
3

cli/tests/00-base.sql

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ CREATE TABLE 🐳🍞(🐳🐳 INTEGER, 🍞🍞 INTEGER);
3636
explain select * from c where b in'x');
3737

3838
-- enable it after we support code string in databend
39-
-- select $$aa$$;
40-
-- select $$
41-
-- def add(a, b):
42-
-- a + b
43-
-- $$;
39+
select $$aa$$;
40+
select $$
41+
def add(a, b):
42+
a + b
43+
$$;
4444

45-
/* ignore this block /* /*
45+
/* ignore this block
4646
select 'in comment block';
4747
*/
4848

@@ -68,3 +68,4 @@ select 'bye';
6868
drop table test;
6969
drop table test_decimal;
7070
drop table test_nested;
71+

0 commit comments

Comments
 (0)