Merge branch 'master' into async-loader-integration

This commit is contained in:
Sergei Trifonov 2023-08-04 19:13:04 +02:00 committed by GitHub
commit 2c47bb2a22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 176 additions and 1 deletions

View File

@ -34,7 +34,13 @@ The binary you just downloaded can run all sorts of ClickHouse tools and utiliti
A common use of `clickhouse-local` is to run ad-hoc queries on files: where you don't have to insert the data into a table. `clickhouse-local` can stream the data from a file into a temporary table and execute your SQL.
If the file is sitting on the same machine as `clickhouse-local`, use the `file` table engine. The following `reviews.tsv` file contains a sampling of Amazon product reviews:
If the file is sitting on the same machine as `clickhouse-local`, you can simple specify the file to load. The following `reviews.tsv` file contains a sampling of Amazon product reviews:
```bash
./clickhouse local -q "SELECT * FROM 'reviews.tsv'"
```
This command is a shortcut of:
```bash
./clickhouse local -q "SELECT * FROM file('reviews.tsv')"

View File

@ -35,6 +35,18 @@ LocalConnection::LocalConnection(ContextPtr context_, bool send_progress_, bool
LocalConnection::~LocalConnection()
{
/// Last query may not have been finished or cancelled due to exception on client side.
if (state && !state->is_finished && !state->is_cancelled)
{
try
{
LocalConnection::sendCancel();
}
catch (...)
{
/// Just ignore any exception.
}
}
state.reset();
}
@ -73,6 +85,10 @@ void LocalConnection::sendQuery(
bool,
std::function<void(const Progress &)> process_progress_callback)
{
/// Last query may not have been finished or cancelled due to exception on client side.
if (state && !state->is_finished && !state->is_cancelled)
sendCancel();
/// Suggestion comes without client_info.
if (client_info)
query_context = session.makeQueryContext(*client_info);
@ -204,6 +220,10 @@ void LocalConnection::sendCancel()
state->is_cancelled = true;
if (state->executor)
state->executor->cancel();
if (state->pushing_executor)
state->pushing_executor->cancel();
if (state->pushing_async_executor)
state->pushing_async_executor->cancel();
}
bool LocalConnection::pullBlock(Block & block)

View File

@ -243,6 +243,38 @@ bool ParserIdentifier::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
}
bool ParserTableAsStringLiteralIdentifier::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
if (pos->type != TokenType::StringLiteral)
return false;
ReadBufferFromMemory in(pos->begin, pos->size());
String s;
if (!tryReadQuotedStringInto(s, in))
{
expected.add(pos, "string literal");
return false;
}
if (in.count() != pos->size())
{
expected.add(pos, "string literal");
return false;
}
if (s.empty())
{
expected.add(pos, "non-empty string literal");
return false;
}
node = std::make_shared<ASTTableIdentifier>(s);
++pos;
return true;
}
bool ParserCompoundIdentifier::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
ASTPtr id_list;

View File

@ -34,6 +34,19 @@ protected:
};
/** An identifier for tables written as string literal, for example, 'mytable.avro'
*/
class ParserTableAsStringLiteralIdentifier : public IParserBase
{
public:
explicit ParserTableAsStringLiteralIdentifier() {}
protected:
const char * getName() const override { return "string literal table identifier"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
/** An identifier, possibly containing a dot, for example, x_yz123 or `something special` or Hits.EventTime,
* possibly with UUID clause like `db name`.`table name` UUID 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
*/

View File

@ -24,6 +24,8 @@ bool ParserTableExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
if (!ParserWithOptionalAlias(std::make_unique<ParserSubquery>(), allow_alias_without_as_keyword).parse(pos, res->subquery, expected)
&& !ParserWithOptionalAlias(std::make_unique<ParserFunction>(false, true), allow_alias_without_as_keyword).parse(pos, res->table_function, expected)
&& !ParserWithOptionalAlias(std::make_unique<ParserCompoundIdentifier>(true, true), allow_alias_without_as_keyword)
.parse(pos, res->database_and_table_name, expected)
&& !ParserWithOptionalAlias(std::make_unique<ParserTableAsStringLiteralIdentifier>(), allow_alias_without_as_keyword)
.parse(pos, res->database_and_table_name, expected))
return false;

View File

@ -0,0 +1,27 @@
Test 1: check double quotes
1 abc 123 abacaba
2 def 456 bacabaa
3 story 78912 acabaab
4 history 21321321 cabaaba
Test 1a: check double quotes no parsing overflow
1
Test 1b: check double quotes empty
1
Test 2: check back quotes
1 abc 123 abacaba
2 def 456 bacabaa
3 story 78912 acabaab
4 history 21321321 cabaaba
Test 2a: check back quotes no parsing overflow
1
Test 2b: check back quotes empty
1
Test 3: check literal
1 abc 123 abacaba
2 def 456 bacabaa
3 story 78912 acabaab
4 history 21321321 cabaaba
Test 3a: check literal no parsing overflow
1
Test 3b: check literal empty
1

View File

@ -0,0 +1,56 @@
#!/usr/bin/env bash
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CURDIR"/../shell_config.sh
dir=${CLICKHOUSE_TEST_UNIQUE_NAME}
[[ -d $dir ]] && rm -rd $dir
mkdir $dir
# Create temporary csv file for tests
echo '"id","str","int","text"' > $dir/tmp.csv
echo '1,"abc",123,"abacaba"' >> $dir/tmp.csv
echo '2,"def",456,"bacabaa"' >> $dir/tmp.csv
echo '3,"story",78912,"acabaab"' >> $dir/tmp.csv
echo '4,"history",21321321,"cabaaba"' >> $dir/tmp.csv
#################
echo "Test 1: check double quotes"
$CLICKHOUSE_LOCAL -q "SELECT * FROM \"${dir}/tmp.csv\""
#################
echo "Test 1a: check double quotes no parsing overflow"
$CLICKHOUSE_LOCAL -q "SELECT * FROM \"${dir}/tmp.csv\"\"bad\"" 2>&1 | grep -c "UNKNOWN_TABLE"
#################
echo "Test 1b: check double quotes empty"
$CLICKHOUSE_LOCAL -q "SELECT * FROM \"\"" 2>&1 | grep -c "SYNTAX_ERROR"
#################
echo "Test 2: check back quotes"
$CLICKHOUSE_LOCAL -q "SELECT * FROM \`${dir}/tmp.csv\`"
#################
echo "Test 2a: check back quotes no parsing overflow"
$CLICKHOUSE_LOCAL -q "SELECT * FROM \`${dir}/tmp.csv\`\`bad\`" 2>&1 | grep -c "UNKNOWN_TABLE"
#################
echo "Test 2b: check back quotes empty"
$CLICKHOUSE_LOCAL -q "SELECT * FROM \`\`" 2>&1 | grep -c "SYNTAX_ERROR"
#################
echo "Test 3: check literal"
$CLICKHOUSE_LOCAL -q "SELECT * FROM '${dir}/tmp.csv'"
#################
echo "Test 3a: check literal no parsing overflow"
$CLICKHOUSE_LOCAL -q "SELECT * FROM '${dir}/tmp.csv''bad'" 2>&1 | grep -c "SYNTAX_ERROR"
#################
echo "Test 3b: check literal empty"
$CLICKHOUSE_LOCAL -q "SELECT * FROM ''" 2>&1 | grep -c "SYNTAX_ERROR"
# Remove temporary dir with files
rm -rd $dir

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CUR_DIR"/../shell_config.sh
echo "create table test (x UInt64) engine=Memory;
insert into test from infile 'data'; -- {clientError BAD_ARGUMENTS}" | $CLICKHOUSE_LOCAL -nm
echo "create table test (x UInt64) engine=Memory;
insert into test from infile 'data';" | $CLICKHOUSE_LOCAL -nm --ignore-error
echo "create table test (x UInt64) engine=Memory;
insert into test from infile 'data'; -- {clientError BAD_ARGUMENTS}
select 1" | $CLICKHOUSE_LOCAL -nm