mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 08:40:50 +00:00
PREWHERE can be used now by user without row filtering.
This commit is contained in:
parent
d992e408d8
commit
4d93577791
@ -1,7 +1,5 @@
|
||||
#include <Access/EnabledRowPolicies.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTExpressionList.h>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
#include <Parsers/makeASTForLogicalFunction.h>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
@ -35,19 +33,17 @@ ASTPtr EnabledRowPolicies::getCondition(const String & database, const String &
|
||||
|
||||
ASTPtr EnabledRowPolicies::getCondition(const String & database, const String & table_name, ConditionType type, const ASTPtr & extra_condition) const
|
||||
{
|
||||
ASTPtr main_condition = getCondition(database, table_name, type);
|
||||
if (!main_condition)
|
||||
return extra_condition;
|
||||
if (!extra_condition)
|
||||
return main_condition;
|
||||
auto function = std::make_shared<ASTFunction>();
|
||||
auto exp_list = std::make_shared<ASTExpressionList>();
|
||||
function->name = "and";
|
||||
function->arguments = exp_list;
|
||||
function->children.push_back(exp_list);
|
||||
exp_list->children.push_back(main_condition);
|
||||
exp_list->children.push_back(extra_condition);
|
||||
return function;
|
||||
ASTPtr condition = getCondition(database, table_name, type);
|
||||
if (condition && extra_condition)
|
||||
condition = makeASTForLogicalAnd({condition, extra_condition});
|
||||
else if (!condition)
|
||||
condition = extra_condition;
|
||||
|
||||
bool value;
|
||||
if (tryGetLiteralBool(condition.get(), value) && value)
|
||||
condition = nullptr; /// The condition is always true, no need to check it.
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,97 +1,19 @@
|
||||
#include <Access/RowPolicyCache.h>
|
||||
#include <Access/EnabledRowPolicies.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ExpressionListParsers.h>
|
||||
#include <Parsers/parseQuery.h>
|
||||
#include <Parsers/makeASTForLogicalFunction.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/quoteString.h>
|
||||
#include <ext/range.h>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace
|
||||
{
|
||||
bool tryGetLiteralBool(const IAST & ast, bool & value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (const ASTLiteral * literal = ast.as<ASTLiteral>())
|
||||
{
|
||||
value = !literal->value.isNull() && applyVisitor(FieldVisitorConvertToNumber<bool>(), literal->value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ASTPtr applyFunctionAND(ASTs arguments)
|
||||
{
|
||||
bool const_arguments = true;
|
||||
boost::range::remove_erase_if(arguments, [&](const ASTPtr & argument) -> bool
|
||||
{
|
||||
bool b;
|
||||
if (!tryGetLiteralBool(*argument, b))
|
||||
return false;
|
||||
const_arguments &= b;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!const_arguments)
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(0)});
|
||||
if (arguments.empty())
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(1)});
|
||||
if (arguments.size() == 1)
|
||||
return arguments[0];
|
||||
|
||||
auto function = std::make_shared<ASTFunction>();
|
||||
auto exp_list = std::make_shared<ASTExpressionList>();
|
||||
function->name = "and";
|
||||
function->arguments = exp_list;
|
||||
function->children.push_back(exp_list);
|
||||
exp_list->children = std::move(arguments);
|
||||
return function;
|
||||
}
|
||||
|
||||
|
||||
ASTPtr applyFunctionOR(ASTs arguments)
|
||||
{
|
||||
bool const_arguments = false;
|
||||
boost::range::remove_erase_if(arguments, [&](const ASTPtr & argument) -> bool
|
||||
{
|
||||
bool b;
|
||||
if (!tryGetLiteralBool(*argument, b))
|
||||
return false;
|
||||
const_arguments |= b;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (const_arguments)
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(1)});
|
||||
if (arguments.empty())
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(0)});
|
||||
if (arguments.size() == 1)
|
||||
return arguments[0];
|
||||
|
||||
auto function = std::make_shared<ASTFunction>();
|
||||
auto exp_list = std::make_shared<ASTExpressionList>();
|
||||
function->name = "or";
|
||||
function->arguments = exp_list;
|
||||
function->children.push_back(exp_list);
|
||||
exp_list->children = std::move(arguments);
|
||||
return function;
|
||||
}
|
||||
|
||||
|
||||
using ConditionType = RowPolicy::ConditionType;
|
||||
constexpr size_t MAX_CONDITION_TYPE = RowPolicy::MAX_CONDITION_TYPE;
|
||||
|
||||
@ -111,10 +33,16 @@ namespace
|
||||
ASTPtr getResult() &&
|
||||
{
|
||||
/// Process permissive conditions.
|
||||
restrictions.push_back(applyFunctionOR(std::move(permissions)));
|
||||
restrictions.push_back(makeASTForLogicalOr(std::move(permissions)));
|
||||
|
||||
/// Process restrictive conditions.
|
||||
return applyFunctionAND(std::move(restrictions));
|
||||
auto condition = makeASTForLogicalAnd(std::move(restrictions));
|
||||
|
||||
bool value;
|
||||
if (tryGetLiteralBool(condition.get(), value) && value)
|
||||
condition = nullptr; /// The condition is always true, no need to check it.
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
private:
|
||||
|
103
src/Parsers/makeASTForLogicalFunction.cpp
Normal file
103
src/Parsers/makeASTForLogicalFunction.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include <Parsers/makeASTForLogicalFunction.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTExpressionList.h>
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
ASTPtr makeASTForLogicalNot(ASTPtr argument)
|
||||
{
|
||||
bool b;
|
||||
if (tryGetLiteralBool(argument.get(), b))
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(!b)});
|
||||
|
||||
auto function = std::make_shared<ASTFunction>();
|
||||
auto exp_list = std::make_shared<ASTExpressionList>();
|
||||
function->name = "not";
|
||||
function->arguments = exp_list;
|
||||
function->children.push_back(exp_list);
|
||||
exp_list->children.push_back(argument);
|
||||
return function;
|
||||
}
|
||||
|
||||
|
||||
ASTPtr makeASTForLogicalAnd(ASTs && arguments)
|
||||
{
|
||||
bool partial_result = true;
|
||||
boost::range::remove_erase_if(arguments, [&](const ASTPtr & argument) -> bool
|
||||
{
|
||||
bool b;
|
||||
if (!tryGetLiteralBool(argument.get(), b))
|
||||
return false;
|
||||
partial_result &= b;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!partial_result)
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(0)});
|
||||
if (arguments.empty())
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(1)});
|
||||
if (arguments.size() == 1)
|
||||
return arguments[0];
|
||||
|
||||
auto function = std::make_shared<ASTFunction>();
|
||||
auto exp_list = std::make_shared<ASTExpressionList>();
|
||||
function->name = "and";
|
||||
function->arguments = exp_list;
|
||||
function->children.push_back(exp_list);
|
||||
exp_list->children = std::move(arguments);
|
||||
return function;
|
||||
}
|
||||
|
||||
|
||||
ASTPtr makeASTForLogicalOr(ASTs && arguments)
|
||||
{
|
||||
bool partial_result = false;
|
||||
boost::range::remove_erase_if(arguments, [&](const ASTPtr & argument) -> bool
|
||||
{
|
||||
bool b;
|
||||
if (!tryGetLiteralBool(argument.get(), b))
|
||||
return false;
|
||||
partial_result |= b;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (partial_result)
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(1)});
|
||||
if (arguments.empty())
|
||||
return std::make_shared<ASTLiteral>(Field{UInt8(0)});
|
||||
if (arguments.size() == 1)
|
||||
return arguments[0];
|
||||
|
||||
auto function = std::make_shared<ASTFunction>();
|
||||
auto exp_list = std::make_shared<ASTExpressionList>();
|
||||
function->name = "or";
|
||||
function->arguments = exp_list;
|
||||
function->children.push_back(exp_list);
|
||||
exp_list->children = std::move(arguments);
|
||||
return function;
|
||||
}
|
||||
|
||||
|
||||
bool tryGetLiteralBool(const IAST * ast, bool & value)
|
||||
{
|
||||
if (!ast)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
if (const ASTLiteral * literal = ast->as<ASTLiteral>())
|
||||
{
|
||||
value = !literal->value.isNull() && applyVisitor(FieldVisitorConvertToNumber<bool>(), literal->value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
19
src/Parsers/makeASTForLogicalFunction.h
Normal file
19
src/Parsers/makeASTForLogicalFunction.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
/// Makes an AST calculating NOT argument.
|
||||
ASTPtr makeASTForLogicalNot(ASTPtr argument);
|
||||
|
||||
/// Makes an AST calculating argument1 AND argument2 AND ... AND argumentN.
|
||||
ASTPtr makeASTForLogicalAnd(ASTs && arguments);
|
||||
|
||||
/// Makes an AST calculating argument1 OR argument2 OR ... OR argumentN.
|
||||
ASTPtr makeASTForLogicalOr(ASTs && arguments);
|
||||
|
||||
/// Tries to extract a literal bool from AST.
|
||||
bool tryGetLiteralBool(const IAST * ast, bool & value);
|
||||
}
|
@ -113,6 +113,9 @@ def test_prewhere_not_supported():
|
||||
assert expected_error in instance.query_and_get_error("SELECT * FROM mydb.filtered_table2 PREWHERE 1")
|
||||
assert expected_error in instance.query_and_get_error("SELECT * FROM mydb.filtered_table3 PREWHERE 1")
|
||||
|
||||
# However PREWHERE should still work for user without filtering.
|
||||
assert instance.query("SELECT * FROM mydb.filtered_table1 PREWHERE 1", user="another") == "0\t0\n0\t1\n1\t0\n1\t1\n"
|
||||
|
||||
|
||||
def test_single_table_name():
|
||||
copy_policy_xml('tag_with_table_name.xml')
|
||||
|
Loading…
Reference in New Issue
Block a user