2019-05-17 04:08:03 +00:00
|
|
|
#include <Storages/ConstraintsDescription.h>
|
|
|
|
|
2020-12-10 23:56:57 +00:00
|
|
|
#include <Interpreters/ExpressionAnalyzer.h>
|
|
|
|
#include <Interpreters/TreeRewriter.h>
|
|
|
|
|
2019-05-17 04:08:03 +00:00
|
|
|
#include <Parsers/formatAST.h>
|
|
|
|
#include <Parsers/ParserCreateQuery.h>
|
|
|
|
#include <Parsers/parseQuery.h>
|
|
|
|
#include <Parsers/ASTExpressionList.h>
|
2021-04-03 12:12:45 +00:00
|
|
|
#include <Parsers/ASTFunction.h>
|
2019-05-17 04:08:03 +00:00
|
|
|
|
2020-04-15 20:28:05 +00:00
|
|
|
#include <Core/Defines.h>
|
|
|
|
|
2019-05-17 04:08:03 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
String ConstraintsDescription::toString() const
|
|
|
|
{
|
|
|
|
if (constraints.empty())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
ASTExpressionList list;
|
|
|
|
for (const auto & constraint : constraints)
|
|
|
|
list.children.push_back(constraint);
|
|
|
|
|
|
|
|
return serializeAST(list, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstraintsDescription ConstraintsDescription::parse(const String & str)
|
|
|
|
{
|
|
|
|
if (str.empty())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
ConstraintsDescription res;
|
|
|
|
ParserConstraintDeclarationList parser;
|
2020-04-15 20:28:05 +00:00
|
|
|
ASTPtr list = parseQuery(parser, str, 0, DBMS_DEFAULT_MAX_PARSER_DEPTH);
|
2019-05-17 04:08:03 +00:00
|
|
|
|
|
|
|
for (const auto & constraint : list->children)
|
2020-05-12 11:26:44 +00:00
|
|
|
res.constraints.push_back(constraint);
|
2019-05-17 04:08:03 +00:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2021-01-04 20:55:32 +00:00
|
|
|
ASTs ConstraintsDescription::filterConstraints(ConstraintType selection) const
|
2021-01-03 15:02:00 +00:00
|
|
|
{
|
2021-01-04 20:55:32 +00:00
|
|
|
const auto ast_to_decr_constraint_type = [](ASTConstraintDeclaration::Type constraint_type) -> UInt32
|
|
|
|
{
|
|
|
|
switch (constraint_type)
|
|
|
|
{
|
|
|
|
case ASTConstraintDeclaration::Type::CHECK:
|
|
|
|
return static_cast<UInt32>(ConstraintType::CHECK);
|
|
|
|
case ASTConstraintDeclaration::Type::ASSUME:
|
|
|
|
return static_cast<UInt32>(ConstraintType::ASSUME);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-01-03 15:02:00 +00:00
|
|
|
ASTs res;
|
|
|
|
res.reserve(constraints.size());
|
|
|
|
for (const auto & constraint : constraints)
|
|
|
|
{
|
2021-01-04 20:55:32 +00:00
|
|
|
if ((ast_to_decr_constraint_type(constraint->as<ASTConstraintDeclaration>()->type) & static_cast<UInt32>(selection)) != 0) {
|
2021-01-03 15:02:00 +00:00
|
|
|
res.push_back(constraint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2021-04-03 12:12:45 +00:00
|
|
|
std::vector<std::vector<CNFQuery::AtomicFormula>> ConstraintsDescription::getConstraintData() const
|
|
|
|
{
|
|
|
|
std::vector<std::vector<CNFQuery::AtomicFormula>> constraint_data;
|
|
|
|
for (const auto & constraint : filterConstraints(ConstraintsDescription::ConstraintType::ALWAYS_TRUE))
|
|
|
|
{
|
|
|
|
const auto cnf = TreeCNFConverter::toCNF(constraint->as<ASTConstraintDeclaration>()->expr->ptr())
|
|
|
|
.pullNotOutFunctions(); /// TODO: move prepare stage to ConstraintsDescription
|
|
|
|
for (const auto & group : cnf.getStatements())
|
|
|
|
constraint_data.emplace_back(std::begin(group), std::end(group));
|
|
|
|
}
|
|
|
|
|
|
|
|
return constraint_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<CNFQuery::AtomicFormula> ConstraintsDescription::getAtomicConstraintData() const
|
|
|
|
{
|
|
|
|
std::vector<CNFQuery::AtomicFormula> constraint_data;
|
|
|
|
for (const auto & constraint : filterConstraints(ConstraintsDescription::ConstraintType::ALWAYS_TRUE))
|
|
|
|
{
|
2021-04-10 20:46:53 +00:00
|
|
|
Poco::Logger::get("atomic_formula: initial:").information(constraint->as<ASTConstraintDeclaration>()->expr->ptr()->dumpTree());
|
2021-04-03 12:12:45 +00:00
|
|
|
const auto cnf = TreeCNFConverter::toCNF(constraint->as<ASTConstraintDeclaration>()->expr->ptr())
|
|
|
|
.pullNotOutFunctions();
|
|
|
|
for (const auto & group : cnf.getStatements()) {
|
|
|
|
if (group.size() == 1)
|
|
|
|
constraint_data.push_back(*group.begin());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return constraint_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
ComparisonGraph ConstraintsDescription::getGraph() const
|
|
|
|
{
|
|
|
|
static const std::set<std::string> relations = {
|
|
|
|
"equals", "less", "lessOrEquals", "greaterOrEquals", "greater"};
|
|
|
|
|
|
|
|
std::vector<ASTPtr> constraints_for_graph;
|
|
|
|
auto atomic_formulas = getAtomicConstraintData();
|
|
|
|
for (auto & atomic_formula : atomic_formulas)
|
|
|
|
{
|
2021-04-10 20:46:53 +00:00
|
|
|
Poco::Logger::get("atomic_formula: before:").information(atomic_formula.ast->dumpTree() + " " + std::to_string(atomic_formula.negative));
|
2021-04-03 12:12:45 +00:00
|
|
|
pushNotIn(atomic_formula);
|
|
|
|
auto * func = atomic_formula.ast->as<ASTFunction>();
|
|
|
|
if (func && relations.count(func->name))
|
|
|
|
{
|
|
|
|
if (atomic_formula.negative)
|
|
|
|
throw Exception(": ", ErrorCodes::LOGICAL_ERROR);
|
2021-04-10 20:46:53 +00:00
|
|
|
Poco::Logger::get("atomic_formula: after:").information(atomic_formula.ast->dumpTree() + " " + std::to_string(atomic_formula.negative));
|
2021-04-03 12:12:45 +00:00
|
|
|
constraints_for_graph.push_back(atomic_formula.ast);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ComparisonGraph(constraints_for_graph);
|
|
|
|
}
|
|
|
|
|
2021-01-03 15:02:00 +00:00
|
|
|
ConstraintsExpressions ConstraintsDescription::getExpressionsToCheck(const DB::Context & context,
|
2019-05-25 14:07:45 +00:00
|
|
|
const DB::NamesAndTypesList & source_columns_) const
|
|
|
|
{
|
|
|
|
ConstraintsExpressions res;
|
|
|
|
res.reserve(constraints.size());
|
|
|
|
for (const auto & constraint : constraints)
|
|
|
|
{
|
2020-05-12 16:38:11 +00:00
|
|
|
auto * constraint_ptr = constraint->as<ASTConstraintDeclaration>();
|
2021-01-03 15:02:00 +00:00
|
|
|
if (constraint_ptr->type == ASTConstraintDeclaration::Type::CHECK)
|
|
|
|
{
|
|
|
|
// TreeRewriter::analyze has query as non-const argument so to avoid accidental query changes we clone it
|
|
|
|
ASTPtr expr = constraint_ptr->expr->clone();
|
|
|
|
auto syntax_result = TreeRewriter(context).analyze(expr, source_columns_);
|
|
|
|
res.push_back(ExpressionAnalyzer(constraint_ptr->expr->clone(), syntax_result, context).getActions(false));
|
|
|
|
}
|
2019-05-25 14:07:45 +00:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-06-05 17:29:40 +00:00
|
|
|
ConstraintsDescription::ConstraintsDescription(const ConstraintsDescription & other)
|
|
|
|
{
|
|
|
|
constraints.reserve(other.constraints.size());
|
|
|
|
for (const auto & constraint : other.constraints)
|
|
|
|
constraints.emplace_back(constraint->clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstraintsDescription & ConstraintsDescription::operator=(const ConstraintsDescription & other)
|
|
|
|
{
|
|
|
|
constraints.resize(other.constraints.size());
|
|
|
|
for (size_t i = 0; i < constraints.size(); ++i)
|
|
|
|
constraints[i] = other.constraints[i]->clone();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2019-05-17 04:08:03 +00:00
|
|
|
}
|