mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 23:21:59 +00:00
Ignore non-convertible values at any depth on the right side of IN
operator. The values that are not convertible to the left argument type can't match anyway, so it is safe to discard them.
This commit is contained in:
parent
22dfc611c9
commit
160d8a6416
@ -225,21 +225,23 @@ Field convertFieldToTypeImpl(const Field & src, const IDataType & type, const ID
|
||||
{
|
||||
if (src.getType() == Field::Types::Array)
|
||||
{
|
||||
const DataTypePtr nested_type = removeNullable(type_array->getNestedType());
|
||||
|
||||
const Array & src_arr = src.get<Array>();
|
||||
size_t src_arr_size = src_arr.size();
|
||||
|
||||
auto & element_type = *(type_array->getNestedType());
|
||||
bool have_unconvertible_element = false;
|
||||
Array res(src_arr_size);
|
||||
for (size_t i = 0; i < src_arr_size; ++i)
|
||||
{
|
||||
res[i] = convertFieldToType(src_arr[i], *nested_type);
|
||||
if (res[i].isNull() && !type_array->getNestedType()->isNullable())
|
||||
throw Exception("Type mismatch of array elements in IN or VALUES section. Expected: " + type_array->getNestedType()->getName()
|
||||
+ ". Got NULL in position " + toString(i + 1), ErrorCodes::TYPE_MISMATCH);
|
||||
res[i] = convertFieldToType(src_arr[i], element_type);
|
||||
if (res[i].isNull() && !element_type.isNullable())
|
||||
{
|
||||
// See the comment for Tuples below.
|
||||
have_unconvertible_element = true;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return have_unconvertible_element ? Field(Null()) : Field(res);
|
||||
}
|
||||
}
|
||||
else if (const DataTypeTuple * type_tuple = typeid_cast<const DataTypeTuple *>(&type))
|
||||
@ -255,10 +257,33 @@ Field convertFieldToTypeImpl(const Field & src, const IDataType & type, const ID
|
||||
+ toString(dst_tuple_size) + ", actual size: " + toString(src_tuple_size), ErrorCodes::TYPE_MISMATCH);
|
||||
|
||||
TupleBackend res(dst_tuple_size);
|
||||
bool have_unconvertible_element = false;
|
||||
for (size_t i = 0; i < dst_tuple_size; ++i)
|
||||
res[i] = convertFieldToType(src_tuple[i], *type_tuple->getElements()[i]);
|
||||
{
|
||||
auto & element_type = *(type_tuple->getElements()[i]);
|
||||
res[i] = convertFieldToType(src_tuple[i], element_type);
|
||||
if (!res[i].isNull() || element_type.isNullable())
|
||||
continue;
|
||||
|
||||
return res;
|
||||
/*
|
||||
* Either the source element was Null, or the conversion did not
|
||||
* succeed, because the source and the requested types of the
|
||||
* element are compatible, but the value is not convertible
|
||||
* (e.g. trying to convert -1 from Int8 to UInt8). In these
|
||||
* cases, consider the whole tuple also compatible but not
|
||||
* convertible. According to the specification of this function,
|
||||
* we must return Null in this case.
|
||||
*
|
||||
* The following elements might be not even compatible, so it
|
||||
* makes sense to check them to detect user errors. Remember
|
||||
* that there is an unconvertible element, and try to process
|
||||
* the remaining ones. The convertFieldToType for each element
|
||||
* will throw if it detects incompatibility.
|
||||
*/
|
||||
have_unconvertible_element = true;
|
||||
}
|
||||
|
||||
return have_unconvertible_element ? Field(Null()) : Field(res);
|
||||
}
|
||||
}
|
||||
else if (const DataTypeAggregateFunction * agg_func_type = typeid_cast<const DataTypeAggregateFunction *>(&type))
|
||||
|
@ -26,7 +26,7 @@ namespace ErrorCodes
|
||||
extern const int CANNOT_READ_ARRAY_FROM_TEXT;
|
||||
extern const int CANNOT_PARSE_DATE;
|
||||
extern const int SYNTAX_ERROR;
|
||||
extern const int VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE;
|
||||
extern const int TYPE_MISMATCH;
|
||||
extern const int SUPPORT_IS_DISABLED;
|
||||
}
|
||||
|
||||
@ -291,11 +291,10 @@ ValuesBlockInputFormat::parseExpression(IColumn & column, size_t column_idx)
|
||||
if (value.isNull() && !type.isNullable())
|
||||
{
|
||||
buf.rollbackToCheckpoint();
|
||||
throw Exception{"Expression returns value " + applyVisitor(FieldVisitorToString(), value)
|
||||
+ ", that is out of range of type " + type.getName()
|
||||
+ ", at: " +
|
||||
throw Exception{"Cannot insert NULL value into a column of type '" + type.getName() + "'"
|
||||
+ " at: " +
|
||||
String(buf.position(), std::min(SHOW_CHARS_ON_SYNTAX_ERROR, buf.buffer().end() - buf.position())),
|
||||
ErrorCodes::VALUE_IS_OUT_OF_RANGE_OF_DATA_TYPE};
|
||||
ErrorCodes::TYPE_MISMATCH};
|
||||
}
|
||||
|
||||
column.insert(value);
|
||||
|
@ -0,0 +1,3 @@
|
||||
1
|
||||
0
|
||||
1
|
@ -1,5 +1,5 @@
|
||||
SET send_logs_level = 'none';
|
||||
|
||||
SELECT globalNotIn(['"wh'], [NULL]); -- { serverError 53 }
|
||||
SELECT globalIn([''], [NULL]); -- { serverError 53 }
|
||||
SELECT notIn([['']], [[NULL]]); -- { serverError 53 }
|
||||
SELECT globalNotIn(['"wh'], [NULL]);
|
||||
SELECT globalIn([''], [NULL]);
|
||||
SELECT notIn([['']], [[NULL]]);
|
||||
|
@ -0,0 +1,6 @@
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
@ -0,0 +1,13 @@
|
||||
-- When left and right element types are compatible, but the particular value
|
||||
-- on the right is not in the range of the left type, it should be ignored.
|
||||
select (toUInt8(1)) in (-1);
|
||||
select (toUInt8(0)) in (-1);
|
||||
select (toUInt8(255)) in (-1);
|
||||
|
||||
select [toUInt8(1)] in [-1];
|
||||
select [toUInt8(0)] in [-1];
|
||||
select [toUInt8(255)] in [-1];
|
||||
|
||||
-- When left and right element types are not compatible, we should get an error.
|
||||
select (toUInt8(1)) in ('a'); -- { serverError 53 }
|
||||
select [toUInt8(1)] in ['a']; -- { serverError 53 }
|
Loading…
Reference in New Issue
Block a user