2019-08-24 13:00:04 +00:00
|
|
|
#include <DataStreams/ExpressionBlockInputStream.h>
|
2019-05-19 05:27:00 +00:00
|
|
|
#include <DataStreams/CheckConstraintsBlockOutputStream.h>
|
2019-06-05 07:33:34 +00:00
|
|
|
#include <Parsers/formatAST.h>
|
2019-06-05 08:05:46 +00:00
|
|
|
#include <Columns/ColumnsCommon.h>
|
2019-08-24 13:00:04 +00:00
|
|
|
#include <Common/assert_cast.h>
|
2019-08-24 21:35:07 +00:00
|
|
|
#include <Common/FieldVisitors.h>
|
2019-08-24 13:00:04 +00:00
|
|
|
|
2019-05-19 05:27:00 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2019-08-24 13:00:04 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int VIOLATED_CONSTRAINT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CheckConstraintsBlockOutputStream::CheckConstraintsBlockOutputStream(
|
|
|
|
const String & table_,
|
|
|
|
const BlockOutputStreamPtr & output_,
|
|
|
|
const Block & header_,
|
|
|
|
const ConstraintsDescription & constraints_,
|
|
|
|
const Context & context_)
|
|
|
|
: table(table_),
|
|
|
|
output(output_),
|
|
|
|
header(header_),
|
|
|
|
constraints(constraints_),
|
|
|
|
expressions(constraints_.getExpressions(context_, header.getNamesAndTypesList()))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-19 05:27:00 +00:00
|
|
|
void CheckConstraintsBlockOutputStream::write(const Block & block)
|
|
|
|
{
|
2019-08-24 13:00:04 +00:00
|
|
|
if (block.rows() > 0)
|
2019-06-05 07:33:34 +00:00
|
|
|
{
|
2019-08-24 21:20:20 +00:00
|
|
|
std::cerr << "Checking " << expressions.size() << " constraints\n";
|
2019-08-24 13:00:04 +00:00
|
|
|
for (size_t i = 0; i < expressions.size(); ++i)
|
2019-07-28 12:33:40 +00:00
|
|
|
{
|
2019-08-24 21:20:20 +00:00
|
|
|
std::cerr << serializeAST(*(constraints.constraints[i]->expr), true) << "\n";
|
|
|
|
|
2019-08-24 13:00:04 +00:00
|
|
|
Block block_to_calculate = block;
|
|
|
|
auto constraint_expr = expressions[i];
|
|
|
|
|
|
|
|
constraint_expr->execute(block_to_calculate);
|
|
|
|
ColumnWithTypeAndName res_column = block_to_calculate.getByPosition(block_to_calculate.columns() - 1);
|
|
|
|
const ColumnUInt8 & res_column_uint8 = assert_cast<const ColumnUInt8 &>(*res_column.column);
|
|
|
|
|
|
|
|
const UInt8 * data = res_column_uint8.getData().data();
|
|
|
|
size_t size = res_column_uint8.size();
|
|
|
|
|
|
|
|
/// Is violated.
|
|
|
|
if (!memoryIsByte(data, size, 1))
|
2019-07-29 10:05:43 +00:00
|
|
|
{
|
2019-08-24 13:00:04 +00:00
|
|
|
size_t row_idx = 0;
|
|
|
|
for (; row_idx < size; ++row_idx)
|
|
|
|
if (data[row_idx] != 1)
|
|
|
|
break;
|
2019-07-28 12:33:40 +00:00
|
|
|
|
2019-08-24 21:35:07 +00:00
|
|
|
Names related_columns = constraint_expr->getRequiredColumns();
|
|
|
|
|
|
|
|
std::stringstream exception_message;
|
|
|
|
|
|
|
|
exception_message << "Constraint " << backQuote(constraints.constraints[i]->name)
|
|
|
|
<< " for table " << backQuote(table)
|
|
|
|
<< " is violated at row " << (rows_written + row_idx + 1)
|
|
|
|
<< ". Expression: (" << serializeAST(*(constraints.constraints[i]->expr), true) << ")"
|
|
|
|
<< ". Column values";
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
for (const auto & name : related_columns)
|
|
|
|
{
|
|
|
|
const IColumn & column = *block.getByName(name).column;
|
|
|
|
assert(row_idx < column.size());
|
|
|
|
|
|
|
|
exception_message << (first ? ": " : ", ")
|
|
|
|
<< backQuoteIfNeed(name) << " = " << applyVisitor(FieldVisitorToString(), column[row_idx]);
|
|
|
|
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw Exception{exception_message.str(), ErrorCodes::VIOLATED_CONSTRAINT};
|
2019-08-24 13:00:04 +00:00
|
|
|
}
|
2019-07-28 12:33:40 +00:00
|
|
|
}
|
2019-06-05 07:33:34 +00:00
|
|
|
}
|
2019-08-24 13:00:04 +00:00
|
|
|
|
2019-05-19 05:27:00 +00:00
|
|
|
output->write(block);
|
2019-07-28 12:33:40 +00:00
|
|
|
rows_written += block.rows();
|
2019-05-19 05:27:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CheckConstraintsBlockOutputStream::flush()
|
|
|
|
{
|
|
|
|
output->flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CheckConstraintsBlockOutputStream::writePrefix()
|
|
|
|
{
|
|
|
|
output->writePrefix();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CheckConstraintsBlockOutputStream::writeSuffix()
|
|
|
|
{
|
|
|
|
output->writeSuffix();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|