mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-23 08:02:02 +00:00
Fix parsing of SETTINGS clause of the INSERT ... SELECT ... SETTINGS query
Before this patch the following query ignores the settings for INSERT: insert into test_parallel_insert select * from numbers_mt(65535*2) settings max_insert_threads=10 And the reason is that SETTINGS was parsed by the SELECT parser. Fix this by push down the SETTINGS from the SELECT to INSERT. Also note that since INSERT parser does not use ParserQueryWithOutput the following works: insert into test_parallel_insert select * from numbers_mt(65535*2) format Null settings max_insert_threads=10
This commit is contained in:
parent
36dc23668d
commit
3f67e320dd
64
src/Parsers/InsertQuerySettingsPushDownVisitor.cpp
Normal file
64
src/Parsers/InsertQuerySettingsPushDownVisitor.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <Common/SettingsChanges.h>
|
||||
#include <Parsers/InsertQuerySettingsPushDownVisitor.h>
|
||||
#include <Parsers/ASTSelectWithUnionQuery.h>
|
||||
#include <Parsers/ASTSelectQuery.h>
|
||||
#include <Parsers/ASTSetQuery.h>
|
||||
#include <Parsers/ASTSubquery.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
bool InsertQuerySettingsPushDownMatcher::needChildVisit(ASTPtr & node, const ASTPtr & child)
|
||||
{
|
||||
if (node->as<ASTSelectWithUnionQuery>())
|
||||
return true;
|
||||
if (node->as<ASTSubquery>())
|
||||
return true;
|
||||
if (child->as<ASTSelectQuery>())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void InsertQuerySettingsPushDownMatcher::visit(ASTPtr & ast, Data & data)
|
||||
{
|
||||
if (auto * select_query = ast->as<ASTSelectQuery>())
|
||||
visit(*select_query, ast, data);
|
||||
}
|
||||
|
||||
void InsertQuerySettingsPushDownMatcher::visit(ASTSelectQuery & select_query, ASTPtr &, Data & data)
|
||||
{
|
||||
ASTPtr select_settings_ast = select_query.settings();
|
||||
if (!select_settings_ast)
|
||||
return;
|
||||
|
||||
auto & insert_settings_ast = data.insert_settings_ast;
|
||||
|
||||
if (!insert_settings_ast)
|
||||
{
|
||||
insert_settings_ast = select_settings_ast->clone();
|
||||
return;
|
||||
}
|
||||
|
||||
SettingsChanges & select_settings = select_settings_ast->as<ASTSetQuery &>().changes;
|
||||
SettingsChanges & insert_settings = insert_settings_ast->as<ASTSetQuery &>().changes;
|
||||
|
||||
for (auto & setting : select_settings)
|
||||
{
|
||||
auto it = std::find_if(insert_settings.begin(), insert_settings.end(), [&](auto & select_setting)
|
||||
{
|
||||
return select_setting.name == setting.name;
|
||||
});
|
||||
if (it == insert_settings.end())
|
||||
insert_settings.push_back(setting);
|
||||
else
|
||||
{
|
||||
/// Do not ovewrite setting that was passed for INSERT
|
||||
/// by settings that was passed for SELECT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
37
src/Parsers/InsertQuerySettingsPushDownVisitor.h
Normal file
37
src/Parsers/InsertQuerySettingsPushDownVisitor.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Interpreters/InDepthNodeVisitor.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class ASTSelectQuery;
|
||||
struct SettingChange;
|
||||
class SettingsChanges;
|
||||
|
||||
/// Pushdown SETTINGS clause to the INSERT from the SELECT query:
|
||||
/// (since SETTINGS after SELECT will be parsed by the SELECT parser.)
|
||||
///
|
||||
/// NOTE: INSERT ... SELECT ... FORMAT Null SETTINGS max_insert_threads=10 works even w/o push down,
|
||||
/// since ParserInsertQuery does not ParserInsertQuery.
|
||||
class InsertQuerySettingsPushDownMatcher
|
||||
{
|
||||
public:
|
||||
using Visitor = InDepthNodeVisitor<InsertQuerySettingsPushDownMatcher, true>;
|
||||
|
||||
struct Data
|
||||
{
|
||||
ASTPtr & insert_settings_ast;
|
||||
};
|
||||
|
||||
static bool needChildVisit(ASTPtr & node, const ASTPtr & child);
|
||||
static void visit(ASTPtr & ast, Data & data);
|
||||
|
||||
private:
|
||||
static void visit(ASTSelectQuery &, ASTPtr &, Data &);
|
||||
};
|
||||
|
||||
using InsertQuerySettingsPushDownVisitor = InsertQuerySettingsPushDownMatcher::Visitor;
|
||||
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
#include <Parsers/ParserWatchQuery.h>
|
||||
#include <Parsers/ParserInsertQuery.h>
|
||||
#include <Parsers/ParserSetQuery.h>
|
||||
#include <Parsers/InsertQuerySettingsPushDownVisitor.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
|
||||
@ -127,6 +128,14 @@ bool ParserInsertQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (select)
|
||||
{
|
||||
/// Copy SETTINGS from the INSERT ... SELECT ... SETTINGS
|
||||
InsertQuerySettingsPushDownVisitor::Data visitor_data{settings_ast};
|
||||
InsertQuerySettingsPushDownVisitor(visitor_data).visit(select);
|
||||
}
|
||||
|
||||
|
||||
if (format)
|
||||
{
|
||||
Pos last_token = pos;
|
||||
|
@ -67,6 +67,7 @@ SRCS(
|
||||
ExpressionListParsers.cpp
|
||||
IAST.cpp
|
||||
IParserBase.cpp
|
||||
InsertQuerySettingsPushDownVisitor.cpp
|
||||
Lexer.cpp
|
||||
MySQL/ASTAlterCommand.cpp
|
||||
MySQL/ASTAlterQuery.cpp
|
||||
|
8
tests/queries/0_stateless/01593_insert_settings.sql
Normal file
8
tests/queries/0_stateless/01593_insert_settings.sql
Normal file
@ -0,0 +1,8 @@
|
||||
drop table if exists data_01593;
|
||||
create table data_01593 (key Int) engine=MergeTree() order by key partition by key;
|
||||
|
||||
insert into data_01593 select * from numbers_mt(10);
|
||||
-- TOO_MANY_PARTS error
|
||||
insert into data_01593 select * from numbers_mt(10) settings max_partitions_per_insert_block=1; -- { serverError 252 }
|
||||
-- settings for INSERT is prefered
|
||||
insert into data_01593 select * from numbers_mt(10) settings max_partitions_per_insert_block=1 settings max_partitions_per_insert_block=100;
|
Loading…
Reference in New Issue
Block a user