Skip to content

Commit a0bcab4

Browse files
Merge pull request #12954 from ClickHouse/backport/20.3/12042
Backport #12042 to 20.3: Fix constraints check for constant columns, step 1.
2 parents bb3add1 + f63a09b commit a0bcab4

File tree

4 files changed

+67
-27
lines changed

4 files changed

+67
-27
lines changed

src/DataStreams/CheckConstraintsBlockOutputStream.cpp

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <Interpreters/ExpressionActions.h>
55
#include <Columns/ColumnsCommon.h>
66
#include <Columns/ColumnsNumber.h>
7+
#include <Columns/ColumnConst.h>
78
#include <Common/assert_cast.h>
89
#include <Common/quoteString.h>
910
#include <Common/FieldVisitors.h>
@@ -15,6 +16,7 @@ namespace DB
1516
namespace ErrorCodes
1617
{
1718
extern const int VIOLATED_CONSTRAINT;
19+
extern const int LOGICAL_ERROR;
1820
}
1921

2022

@@ -41,45 +43,72 @@ void CheckConstraintsBlockOutputStream::write(const Block & block)
4143
for (size_t i = 0; i < expressions.size(); ++i)
4244
{
4345
auto constraint_expr = expressions[i];
44-
4546
constraint_expr->execute(block_to_calculate);
47+
48+
auto * constraint_ptr = constraints.constraints[i]->as<ASTConstraintDeclaration>();
49+
4650
ColumnWithTypeAndName res_column = block_to_calculate.getByPosition(block_to_calculate.columns() - 1);
47-
const ColumnUInt8 & res_column_uint8 = assert_cast<const ColumnUInt8 &>(*res_column.column);
4851

49-
const UInt8 * data = res_column_uint8.getData().data();
50-
size_t size = res_column_uint8.size();
52+
if (!isUInt8(res_column.type))
53+
throw Exception(ErrorCodes::LOGICAL_ERROR, "Constraint {} does not return a value of type UInt8",
54+
backQuote(constraint_ptr->name));
5155

52-
/// Is violated.
53-
if (!memoryIsByte(data, size, 1))
56+
if (const ColumnConst * res_const = typeid_cast<const ColumnConst *>(res_column.column.get()))
5457
{
55-
size_t row_idx = 0;
56-
for (; row_idx < size; ++row_idx)
57-
if (data[row_idx] != 1)
58-
break;
58+
UInt8 value = res_const->getValue<UInt64>();
5959

60-
Names related_columns = constraint_expr->getRequiredColumns();
60+
/// Is violated.
61+
if (!value)
62+
{
63+
std::stringstream exception_message;
6164

62-
std::stringstream exception_message;
65+
exception_message << "Constraint " << backQuote(constraint_ptr->name)
66+
<< " for table " << table_id.getNameForLogs()
67+
<< " is violated, because it is a constant expression returning 0."
68+
<< " It is most likely an error in table definition.";
69+
70+
throw Exception{exception_message.str(), ErrorCodes::VIOLATED_CONSTRAINT};
71+
}
72+
}
73+
else
74+
{
75+
const ColumnUInt8 & res_column_uint8 = assert_cast<const ColumnUInt8 &>(*res_column.column);
6376

64-
exception_message << "Constraint " << backQuote(constraints.constraints[i]->name)
65-
<< " for table " << backQuote(table)
66-
<< " is violated at row " << (rows_written + row_idx + 1)
67-
<< ". Expression: (" << serializeAST(*(constraints.constraints[i]->expr), true) << ")"
68-
<< ". Column values";
77+
const UInt8 * data = res_column_uint8.getData().data();
78+
size_t size = res_column_uint8.size();
6979

70-
bool first = true;
71-
for (const auto & name : related_columns)
80+
/// Is violated.
81+
if (!memoryIsByte(data, size, 1))
7282
{
73-
const IColumn & column = *block.getByName(name).column;
74-
assert(row_idx < column.size());
83+
size_t row_idx = 0;
84+
for (; row_idx < size; ++row_idx)
85+
if (data[row_idx] != 1)
86+
break;
7587

76-
exception_message << (first ? ": " : ", ")
77-
<< backQuoteIfNeed(name) << " = " << applyVisitor(FieldVisitorToString(), column[row_idx]);
88+
Names related_columns = constraint_expr->getRequiredColumns();
7889

79-
first = false;
80-
}
90+
std::stringstream exception_message;
91+
92+
exception_message << "Constraint " << backQuote(constraint_ptr->name)
93+
<< " for table " << table_id.getNameForLogs()
94+
<< " is violated at row " << (rows_written + row_idx + 1)
95+
<< ". Expression: (" << serializeAST(*(constraint_ptr->expr), true) << ")"
96+
<< ". Column values";
97+
98+
bool first = true;
99+
for (const auto & name : related_columns)
100+
{
101+
const IColumn & column = *block.getByName(name).column;
102+
assert(row_idx < column.size());
81103

82-
throw Exception{exception_message.str(), ErrorCodes::VIOLATED_CONSTRAINT};
104+
exception_message << (first ? ": " : ", ")
105+
<< backQuoteIfNeed(name) << " = " << applyVisitor(FieldVisitorToString(), column[row_idx]);
106+
107+
first = false;
108+
}
109+
110+
throw Exception{exception_message.str(), ErrorCodes::VIOLATED_CONSTRAINT};
111+
}
83112
}
84113
}
85114
}

src/Interpreters/InterpreterCreateQuery.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,6 @@ ColumnsDescription InterpreterCreateQuery::getColumnsDescription(const ASTExpres
296296
const auto tmp_column_name = final_column_name + "_tmp";
297297
const auto data_type_ptr = column_names_and_types.back().type.get();
298298

299-
300299
default_expr_list->children.emplace_back(
301300
setAlias(addTypeConversionToAST(std::make_shared<ASTIdentifier>(tmp_column_name), data_type_ptr->getName()),
302301
final_column_name));

tests/queries/0_stateless/01358_constexpr_constraint.reference

Whitespace-only changes.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TEMPORARY TABLE constrained
2+
(
3+
`URL` String,
4+
CONSTRAINT is_yandex CHECK domainWithoutWWW(URL) = domainWithoutWWW(URL),
5+
CONSTRAINT is_utf8 CHECK isValidUTF8(URL)
6+
);
7+
8+
insert into constrained values ('a');
9+
10+
DROP TEMPORARY TABLE constrained;
11+
CREATE TEMPORARY TABLE constrained (x UInt8, CONSTRAINT bogus CHECK 0);
12+
INSERT INTO constrained VALUES (1); -- { serverError 469 }

0 commit comments

Comments
 (0)