replace settings limit and offset with corresponding expression nodes

This commit is contained in:
Yakov Olkhovskiy 2023-02-21 22:36:02 +00:00
parent ce2b044532
commit cf493d1dfb
6 changed files with 107 additions and 17 deletions

View File

@ -233,22 +233,43 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q
auto select_settings = select_query_typed.settings();
SettingsChanges settings_changes;
if (is_subquery)
/// We are going to remove settings LIMIT and OFFSET and
/// further replace them with corresponding expression nodes
UInt64 limit = 0;
UInt64 offset = 0;
/// remove global settings limit and offset
if (const Settings & settings_ref = updated_context->getSettingsRef(); settings_ref.limit || settings_ref.offset)
{
if (const Settings & settings_ref = updated_context->getSettingsRef(); settings_ref.limit || settings_ref.offset)
{
Settings settings = updated_context->getSettings();
settings.limit = 0;
settings.offset = 0;
updated_context->setSettings(settings);
}
Settings settings = updated_context->getSettings();
limit = settings.limit;
offset = settings.offset;
settings.limit = 0;
settings.offset = 0;
updated_context->setSettings(settings);
}
if (select_settings)
{
auto & set_query = select_settings->as<ASTSetQuery &>();
updated_context->applySettingsChanges(set_query.changes);
settings_changes = set_query.changes;
/// remove expression settings limit and offset
if (auto * limit_field = set_query.changes.tryGet("limit"))
{
limit = limit_field->safeGet<UInt64>();
set_query.changes.removeSetting("limit");
}
if (auto * offset_field = set_query.changes.tryGet("offset"))
{
offset = offset_field->safeGet<UInt64>();
set_query.changes.removeSetting("offset");
}
if (!set_query.changes.empty())
{
updated_context->applySettingsChanges(set_query.changes);
settings_changes = set_query.changes;
}
}
auto current_query_tree = std::make_shared<QueryNode>(std::move(updated_context), std::move(settings_changes));
@ -334,12 +355,32 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q
if (select_limit_by)
current_query_tree->getLimitByNode() = buildExpressionList(select_limit_by, current_context);
/// combine limit expression with limit setting
auto select_limit = select_query_typed.limitLength();
if (select_limit)
if (select_limit && limit)
{
auto function_node = std::make_shared<FunctionNode>("least");
function_node->getArguments().getNodes().push_back(buildExpression(select_limit, current_context));
function_node->getArguments().getNodes().push_back(std::make_shared<ConstantNode>(limit));
current_query_tree->getLimit() = function_node;
}
else if (limit)
current_query_tree->getLimit() = std::make_shared<ConstantNode>(limit);
else if (select_limit)
current_query_tree->getLimit() = buildExpression(select_limit, current_context);
/// combine offset expression with offset setting
auto select_offset = select_query_typed.limitOffset();
if (select_offset)
if (select_offset && offset)
{
auto function_node = std::make_shared<FunctionNode>("plus");
function_node->getArguments().getNodes().push_back(buildExpression(select_offset, current_context));
function_node->getArguments().getNodes().push_back(std::make_shared<ConstantNode>(offset));
current_query_tree->getOffset() = function_node;
}
else if (offset)
current_query_tree->getOffset() = std::make_shared<ConstantNode>(offset);
else if (select_offset)
current_query_tree->getOffset() = buildExpression(select_offset, current_context);
return current_query_tree;

View File

@ -46,4 +46,29 @@ Field * SettingsChanges::tryGet(std::string_view name)
return &change->value;
}
bool SettingsChanges::insertSetting(std::string_view name, const Field & value)
{
if (std::find_if(begin(), end(), [&name](const SettingChange & change) { return change.name == name; }) != end())
return false;
emplace_back(name, value);
return true;
}
void SettingsChanges::setSetting(std::string_view name, const Field & value)
{
if (auto * v = tryGet(name))
*v = value;
else
insertSetting(name, value);
}
bool SettingsChanges::removeSetting(std::string_view name)
{
auto it = std::find_if(begin(), end(), [&name](const SettingChange & change) { return change.name == name; });
if (it == end())
return false;
erase(it);
return true;
}
}

View File

@ -28,6 +28,13 @@ public:
bool tryGet(std::string_view name, Field & out_value) const;
const Field * tryGet(std::string_view name) const;
Field * tryGet(std::string_view name);
/// inserts element if doesn't exists and returns true, else just returns false
bool insertSetting(std::string_view name, const Field & value);
/// sets element to value, inserts if doesn't exist
void setSetting(std::string_view name, const Field & value);
/// if element exists - removes it and returns true, else returns false
bool removeSetting(std::string_view name);
};
}

View File

@ -216,17 +216,12 @@ public:
limit_length = query_node.getLimit()->as<ConstantNode &>().getValue().safeGet<UInt64>();
}
if (settings.limit)
limit_length = limit_length ? std::min(limit_length, settings.limit.value) : settings.limit;
if (query_node.hasOffset())
{
/// Constness of offset is validated during query analysis stage
limit_offset = query_node.getOffset()->as<ConstantNode &>().getValue().safeGet<UInt64>();
}
limit_offset += settings.offset;
/// Partial sort can be done if there is LIMIT, but no DISTINCT, LIMIT WITH TIES, LIMIT BY, ARRAY JOIN
if (limit_length != 0 &&
!query_node.isDistinct() &&

View File

@ -52,3 +52,19 @@ SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5);
5
SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5;
10
SET limit = 4;
SET offset = 1;
SELECT * FROM numbers(10);
1
2
3
4
SELECT * FROM numbers(10) LIMIT 3 OFFSET 2;
3
4
5
SELECT * FROM numbers(10) LIMIT 5 OFFSET 2;
3
4
5
6

View File

@ -21,4 +21,10 @@ SELECT count(*) FROM (SELECT * FROM numbers(10)) SETTINGS limit=5;
SELECT count(*) FROM view(SELECT * FROM numbers(10));
SELECT count(*) FROM view(SELECT * FROM numbers(10) SETTINGS limit=5);
SELECT count(*) FROM view(SELECT * FROM numbers(10)) SETTINGS limit=5;
SET limit = 4;
SET offset = 1;
SELECT * FROM numbers(10);
SELECT * FROM numbers(10) LIMIT 3 OFFSET 2;
SELECT * FROM numbers(10) LIMIT 5 OFFSET 2;
-- { echoOff }