mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-28 02:21:59 +00:00
Backport #71541 to 24.9: Avoid crash when using a UDF in a constraint
This commit is contained in:
parent
5bfc84f951
commit
51e5d0e3c2
@ -24,73 +24,17 @@ namespace ErrorCodes
|
|||||||
|
|
||||||
void UserDefinedSQLFunctionVisitor::visit(ASTPtr & ast)
|
void UserDefinedSQLFunctionVisitor::visit(ASTPtr & ast)
|
||||||
{
|
{
|
||||||
if (!ast)
|
chassert(ast);
|
||||||
{
|
|
||||||
chassert(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// FIXME: this helper should use updatePointerToChild(), but
|
if (const auto * function = ast->template as<ASTFunction>())
|
||||||
/// forEachPointerToChild() is not implemented for ASTColumnDeclaration
|
|
||||||
/// (and also some members should be adjusted for this).
|
|
||||||
const auto visit_child_with_shared_ptr = [&](ASTPtr & child)
|
|
||||||
{
|
|
||||||
if (!child)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto * old_value = child.get();
|
|
||||||
visit(child);
|
|
||||||
|
|
||||||
// child did not change
|
|
||||||
if (old_value == child.get())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// child changed, we need to modify it in the list of children of the parent also
|
|
||||||
for (auto & current_child : ast->children)
|
|
||||||
{
|
|
||||||
if (current_child.get() == old_value)
|
|
||||||
current_child = child;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (auto * col_decl = ast->as<ASTColumnDeclaration>())
|
|
||||||
{
|
|
||||||
visit_child_with_shared_ptr(col_decl->default_expression);
|
|
||||||
visit_child_with_shared_ptr(col_decl->ttl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto * storage = ast->as<ASTStorage>())
|
|
||||||
{
|
|
||||||
const auto visit_child = [&](IAST * & child)
|
|
||||||
{
|
|
||||||
if (!child)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (const auto * function = child->template as<ASTFunction>())
|
|
||||||
{
|
{
|
||||||
std::unordered_set<std::string> udf_in_replace_process;
|
std::unordered_set<std::string> udf_in_replace_process;
|
||||||
auto replace_result = tryToReplaceFunction(*function, udf_in_replace_process);
|
auto replace_result = tryToReplaceFunction(*function, udf_in_replace_process);
|
||||||
if (replace_result)
|
if (replace_result)
|
||||||
ast->setOrReplace(child, replace_result);
|
ast = replace_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(child);
|
for (auto & child : ast->children)
|
||||||
};
|
|
||||||
|
|
||||||
visit_child(storage->partition_by);
|
|
||||||
visit_child(storage->primary_key);
|
|
||||||
visit_child(storage->order_by);
|
|
||||||
visit_child(storage->sample_by);
|
|
||||||
visit_child(storage->ttl_table);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto * alter = ast->as<ASTAlterCommand>())
|
|
||||||
{
|
|
||||||
/// It is OK to use updatePointerToChild() because ASTAlterCommand implements forEachPointerToChild()
|
|
||||||
const auto visit_child_update_parent = [&](ASTPtr & child)
|
|
||||||
{
|
{
|
||||||
if (!child)
|
if (!child)
|
||||||
return;
|
return;
|
||||||
@ -103,24 +47,7 @@ void UserDefinedSQLFunctionVisitor::visit(ASTPtr & ast)
|
|||||||
/// We have to replace them if the child was replaced.
|
/// We have to replace them if the child was replaced.
|
||||||
if (new_ptr != old_ptr)
|
if (new_ptr != old_ptr)
|
||||||
ast->updatePointerToChild(old_ptr, new_ptr);
|
ast->updatePointerToChild(old_ptr, new_ptr);
|
||||||
};
|
|
||||||
|
|
||||||
for (auto & children : alter->children)
|
|
||||||
visit_child_update_parent(children);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto * function = ast->template as<ASTFunction>())
|
|
||||||
{
|
|
||||||
std::unordered_set<std::string> udf_in_replace_process;
|
|
||||||
auto replace_result = tryToReplaceFunction(*function, udf_in_replace_process);
|
|
||||||
if (replace_result)
|
|
||||||
ast = replace_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto & child : ast->children)
|
|
||||||
visit(child);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserDefinedSQLFunctionVisitor::visit(IAST * ast)
|
void UserDefinedSQLFunctionVisitor::visit(IAST * ast)
|
||||||
|
@ -128,4 +128,14 @@ void ASTColumnDeclaration::formatImpl(const FormatSettings & format_settings, Fo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTColumnDeclaration::forEachPointerToChild(std::function<void(void **)> f)
|
||||||
|
{
|
||||||
|
f(reinterpret_cast<void **>(&default_expression));
|
||||||
|
f(reinterpret_cast<void **>(&comment));
|
||||||
|
f(reinterpret_cast<void **>(&codec));
|
||||||
|
f(reinterpret_cast<void **>(&statistics_desc));
|
||||||
|
f(reinterpret_cast<void **>(&ttl));
|
||||||
|
f(reinterpret_cast<void **>(&collation));
|
||||||
|
f(reinterpret_cast<void **>(&settings));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,9 @@ public:
|
|||||||
|
|
||||||
ASTPtr clone() const override;
|
ASTPtr clone() const override;
|
||||||
void formatImpl(const FormatSettings & format_settings, FormatState & state, FormatStateStacked frame) const override;
|
void formatImpl(const FormatSettings & format_settings, FormatState & state, FormatStateStacked frame) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void forEachPointerToChild(std::function<void(void **)> f) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
CREATE TABLE default.t0\n(\n `c0` Int32,\n CONSTRAINT c1 CHECK c0 > 5\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192
|
||||||
|
10
|
17
tests/queries/0_stateless/03262_udf_in_constraint.sh
Executable file
17
tests/queries/0_stateless/03262_udf_in_constraint.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
# shellcheck source=../shell_config.sh
|
||||||
|
. "$CUR_DIR"/../shell_config.sh
|
||||||
|
|
||||||
|
$CLICKHOUSE_CLIENT -q "
|
||||||
|
CREATE FUNCTION ${CLICKHOUSE_DATABASE}_function AS (x) -> x > 5;
|
||||||
|
CREATE TABLE t0 (c0 Int, CONSTRAINT c1 CHECK ${CLICKHOUSE_DATABASE}_function(c0)) ENGINE = MergeTree() ORDER BY tuple();
|
||||||
|
SHOW CREATE TABLE t0;
|
||||||
|
INSERT INTO t0(c0) VALUES (10);
|
||||||
|
INSERT INTO t0(c0) VALUES (3); -- {serverError VIOLATED_CONSTRAINT}
|
||||||
|
SELECT * FROM t0;
|
||||||
|
|
||||||
|
DROP TABLE t0;
|
||||||
|
DROP FUNCTION ${CLICKHOUSE_DATABASE}_function;
|
||||||
|
"
|
Loading…
Reference in New Issue
Block a user