Fixed check for nondeterministic functions to handle lambdas correctly

This commit is contained in:
Alexander Kazakov 2020-04-13 17:34:11 +03:00
parent 210a829774
commit e05e2c7628
3 changed files with 34 additions and 16 deletions

View File

@ -36,34 +36,44 @@ namespace ErrorCodes
namespace
{
struct FirstNonDeterministicFuncData
/// Helps to detect situations, where non-deterministic functions may be used in mutations of Replicated*MergeTree.
class FirstNonDeterministicFuncMatcher
{
using TypeToVisit = ASTFunction;
public:
struct Data {
const Context & context;
std::optional<String> nondeterministic_function_name;
};
explicit FirstNonDeterministicFuncData(const Context & context_)
: context{context_}
{}
const Context & context;
std::optional<String> nondeterministic_function_name;
void visit(ASTFunction & function, ASTPtr &)
public:
static bool needChildVisit(const ASTPtr & /*node*/, const ASTPtr & child)
{
if (nondeterministic_function_name)
return child != nullptr;
}
static void visit(const ASTPtr & node, Data & data)
{
if (data.nondeterministic_function_name)
return;
const auto func = FunctionFactory::instance().get(function.name, context);
if (!func->isDeterministic())
nondeterministic_function_name = func->getName();
if (const auto * function = typeid_cast<const ASTFunction *>(node.get()))
{
if (function->name != "lambda")
{
const auto func = FunctionFactory::instance().get(function->name, data.context);
if (!func->isDeterministic())
data.nondeterministic_function_name = func->getName();
}
}
}
};
using FirstNonDeterministicFuncFinder =
InDepthNodeVisitor<OneTypeMatcher<FirstNonDeterministicFuncData>, true>;
InDepthNodeVisitor<FirstNonDeterministicFuncMatcher, true>;
std::optional<String> findFirstNonDeterministicFuncName(const MutationCommand & command, const Context & context)
{
FirstNonDeterministicFuncData finder_data(context);
FirstNonDeterministicFuncMatcher::Data finder_data{context};
switch (command.type)
{

View File

@ -43,6 +43,12 @@ ${CLICKHOUSE_CLIENT} --query "ALTER TABLE $R1 DELETE WHERE ignore(rand())" 2>&1
${CLICKHOUSE_CLIENT} --query "ALTER TABLE $R1 UPDATE y = y + rand() % 1 WHERE not ignore()" 2>&1 \
| fgrep -q "must use only deterministic functions" && echo 'OK' || echo 'FAIL'
${CLICKHOUSE_CLIENT} --query "ALTER TABLE $R1 UPDATE y = x + arrayCount(x -> (x + y) % 2, range(y)) WHERE not ignore()" 2>&1 > /dev/null \
&& echo 'OK' || echo 'FAIL'
${CLICKHOUSE_CLIENT} --query "ALTER TABLE $R1 UPDATE y = x + arrayCount(x -> (rand() + x) % 2, range(y)) WHERE not ignore()" 2>&1 \
| fgrep -q "must use only deterministic functions" && echo 'OK' || echo 'FAIL'
# For regular tables we do not enforce deterministic functions
${CLICKHOUSE_CLIENT} --query "ALTER TABLE $T1 DELETE WHERE rand() = 0" 2>&1 > /dev/null \