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 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 {
explicit FirstNonDeterministicFuncData(const Context & context_)
: context{context_}
{}
const Context & context; const Context & context;
std::optional<String> nondeterministic_function_name; 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; return;
const auto func = FunctionFactory::instance().get(function.name, context); 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()) if (!func->isDeterministic())
nondeterministic_function_name = func->getName(); data.nondeterministic_function_name = func->getName();
}
}
} }
}; };
using FirstNonDeterministicFuncFinder = using FirstNonDeterministicFuncFinder =
InDepthNodeVisitor<OneTypeMatcher<FirstNonDeterministicFuncData>, true>; InDepthNodeVisitor<FirstNonDeterministicFuncMatcher, true>;
std::optional<String> findFirstNonDeterministicFuncName(const MutationCommand & command, const Context & context) std::optional<String> findFirstNonDeterministicFuncName(const MutationCommand & command, const Context & context)
{ {
FirstNonDeterministicFuncData finder_data(context); FirstNonDeterministicFuncMatcher::Data finder_data{context};
switch (command.type) 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 \ ${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' | 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 # For regular tables we do not enforce deterministic functions
${CLICKHOUSE_CLIENT} --query "ALTER TABLE $T1 DELETE WHERE rand() = 0" 2>&1 > /dev/null \ ${CLICKHOUSE_CLIENT} --query "ALTER TABLE $T1 DELETE WHERE rand() = 0" 2>&1 > /dev/null \