From 5c7dccebc1edde47f1100991f46b100a0e810660 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 16 Jun 2015 21:50:44 +0300 Subject: [PATCH 1/4] dbms: allowed to compare Date and DateTime with strings in IN [#METR-2944]. --- dbms/src/Interpreters/Set.cpp | 34 ++++++++++++++++--- ..._time_with_constant_string_in_in.reference | 8 +++++ ...e_date_time_with_constant_string_in_in.sql | 8 +++++ 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00174_compare_date_time_with_constant_string_in_in.reference create mode 100644 dbms/tests/queries/0_stateless/00174_compare_date_time_with_constant_string_in_in.sql diff --git a/dbms/src/Interpreters/Set.cpp b/dbms/src/Interpreters/Set.cpp index 08a6c6e0564..1f1b0cca266 100644 --- a/dbms/src/Interpreters/Set.cpp +++ b/dbms/src/Interpreters/Set.cpp @@ -336,11 +336,37 @@ static Field convertToType(const Field & src, const IDataType & type) } else if (is_date || is_datetime) { - if (src.getType() != Field::Types::UInt64) - throw Exception("Type mismatch in IN section: " + type.getName() + " at left, " - + Field::Types::toString(src.getType()) + " at right"); + if (src.getType() == Field::Types::UInt64) + return src; - return src; + if (src.getType() == Field::Types::String) + { + /// Возможность сравнивать даты и даты-с-временем со строкой. + const String & str = src.get(); + ReadBufferFromString in(str); + + if (is_date) + { + DayNum_t date{}; + readDateText(date, in); + if (!in.eof()) + throw Exception("String is too long for Date: " + str); + + return Field(UInt64(date)); + } + else + { + time_t date_time{}; + readDateTimeText(date_time, in); + if (!in.eof()) + throw Exception("String is too long for DateTime: " + str); + + return Field(UInt64(date_time)); + } + } + + throw Exception("Type mismatch in IN section: " + type.getName() + " at left, " + + Field::Types::toString(src.getType()) + " at right"); } } else diff --git a/dbms/tests/queries/0_stateless/00174_compare_date_time_with_constant_string_in_in.reference b/dbms/tests/queries/0_stateless/00174_compare_date_time_with_constant_string_in_in.reference new file mode 100644 index 00000000000..1173f1db5af --- /dev/null +++ b/dbms/tests/queries/0_stateless/00174_compare_date_time_with_constant_string_in_in.reference @@ -0,0 +1,8 @@ +1 +0 +1 +0 +0 +1 +0 +1 diff --git a/dbms/tests/queries/0_stateless/00174_compare_date_time_with_constant_string_in_in.sql b/dbms/tests/queries/0_stateless/00174_compare_date_time_with_constant_string_in_in.sql new file mode 100644 index 00000000000..565163cfc31 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00174_compare_date_time_with_constant_string_in_in.sql @@ -0,0 +1,8 @@ +SELECT toDate('2015-02-05') IN ('2015-02-04', '2015-02-05'); +SELECT toDate('2015-02-05') IN ('2015-02-04', '2015-02-06'); +SELECT toDateTime('2015-02-03 04:05:06') IN ('2015-02-03 04:05:06', '2015-02-03 05:06:07'); +SELECT toDateTime('2015-02-03 04:05:06') IN ('2015-02-04 04:05:06', '2015-02-03 05:06:07'); +SELECT toDate('2015-02-05') NOT IN ('2015-02-04', '2015-02-05'); +SELECT toDate('2015-02-05') NOT IN ('2015-02-04', '2015-02-06'); +SELECT toDateTime('2015-02-03 04:05:06') NOT IN ('2015-02-03 04:05:06', '2015-02-03 05:06:07'); +SELECT toDateTime('2015-02-03 04:05:06') NOT IN ('2015-02-04 04:05:06', '2015-02-03 05:06:07'); From 73072b58c7b043052002354d7d2945230a5325a1 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 17 Jun 2015 00:41:47 +0300 Subject: [PATCH 2/4] dbms: fixed comment [#METR-2944]. --- dbms/include/DB/Interpreters/InterpreterSelectQuery.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/include/DB/Interpreters/InterpreterSelectQuery.h b/dbms/include/DB/Interpreters/InterpreterSelectQuery.h index 405691fa966..9152ff9eb5e 100644 --- a/dbms/include/DB/Interpreters/InterpreterSelectQuery.h +++ b/dbms/include/DB/Interpreters/InterpreterSelectQuery.h @@ -100,7 +100,7 @@ private: // Переименовать столбцы каждого запроса цепочки UNION ALL в такие же имена, как в первом запросе. void renameColumns(); - /** Из какой таблицы читать. JOIN-ы не поддерживаются. + /** Из какой таблицы читать. При JOIN, возвращается "левая" таблицы. */ void getDatabaseAndTableNames(String & database_name, String & table_name); From bb83c867fd69e5e19e4f54320eafc0605bb04d41 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 17 Jun 2015 00:42:18 +0300 Subject: [PATCH 3/4] dbms: added support for Array arguments of function 'if' (incomplete) [#METR-16700]. --- .../DB/Functions/FunctionsConditional.h | 490 ++++++++++++++++-- 1 file changed, 440 insertions(+), 50 deletions(-) diff --git a/dbms/include/DB/Functions/FunctionsConditional.h b/dbms/include/DB/Functions/FunctionsConditional.h index 6c5ae79c3cf..c2f44b47ff3 100644 --- a/dbms/include/DB/Functions/FunctionsConditional.h +++ b/dbms/include/DB/Functions/FunctionsConditional.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -14,7 +15,7 @@ namespace DB /** Функция выбора по условию: if(cond, then, else). * cond - UInt8 - * then, else - либо числа/даты/даты-с-временем, либо строки. + * then, else - числовые типы, для которых есть общий тип, либо даты, даты-с-временем, либо строки, либо массивы таких типов. */ @@ -275,6 +276,224 @@ struct StringIfImpl }; +template +struct NumArrayIfImpl +{ + template + static ALWAYS_INLINE void copy_from_vector( + size_t i, + const PODArray & from_data, const ColumnArray::Offsets_t & from_offsets, ColumnArray::Offset_t from_prev_offset, + PODArray & to_data, ColumnArray::Offsets_t & to_offsets, ColumnArray::Offset_t & to_prev_offset) + { + size_t size_to_write = from_offsets[i] - from_prev_offset; + to_data.resize(to_data.size() + size_to_write); + + for (size_t i = 0; i < size_to_write; ++i) + to_data[to_prev_offset + i] = static_cast(from_data[from_prev_offset + i]); + + to_prev_offset += size_to_write; + to_offsets[i] = to_prev_offset; + } + + template + static ALWAYS_INLINE void copy_from_constant( + size_t i, + const PODArray & from_data, + PODArray & to_data, ColumnArray::Offsets_t & to_offsets, ColumnArray::Offset_t & to_prev_offset) + { + size_t size_to_write = from_data.size(); + to_data.resize(to_data.size() + size_to_write); + memcpy(&to_data[to_prev_offset], from_data.data(), size_to_write * sizeof(from_data[0])); + to_prev_offset += size_to_write; + to_offsets[i] = to_prev_offset; + } + + static void create_result_column( + Block & block, size_t result, + PODArray ** c_data, ColumnArray::Offsets_t ** c_offsets) + { + ColumnVector * col_res_vec = new ColumnVector; + ColumnArray * col_res_array = new ColumnArray(col_res_vec); + block.getByPosition(result).column = col_res_array; + + *c_data = &col_res_vec->getData(); + *c_offsets = &col_res_array->getOffsets(); + } + + + static void vector_vector( + const PODArray & cond, + const PODArray & a_data, const ColumnArray::Offsets_t & a_offsets, + const PODArray & b_data, const ColumnArray::Offsets_t & b_offsets, + Block & block, size_t result) + { + PODArray * c_data = nullptr; + ColumnArray::Offsets_t * c_offsets = nullptr; + create_result_column(block, result, &c_data, &c_offsets); + + size_t size = cond.size(); + c_offsets->resize(size); + c_data->reserve(std::max(a_data.size(), b_data.size())); + + ColumnArray::Offset_t a_prev_offset = 0; + ColumnArray::Offset_t b_prev_offset = 0; + ColumnArray::Offset_t c_prev_offset = 0; + + for (size_t i = 0; i < size; ++i) + { + if (cond[i]) + copy_from_vector(i, a_data, a_offsets, a_prev_offset, *c_data, *c_offsets, c_prev_offset); + else + copy_from_vector(i, b_data, b_offsets, b_prev_offset, *c_data, *c_offsets, c_prev_offset); + + a_prev_offset = a_offsets[i]; + b_prev_offset = b_offsets[i]; + } + } + + static void vector_constant( + const PODArray & cond, + const PODArray & a_data, const ColumnArray::Offsets_t & a_offsets, + const Array & b, + Block & block, size_t result) + { + PODArray * c_data = nullptr; + ColumnArray::Offsets_t * c_offsets = nullptr; + create_result_column(block, result, &c_data, &c_offsets); + + PODArray b_converted(b.size()); + for (size_t i = 0, size = b.size(); i < size; ++i) + b_converted[i] = b[i].get::Type>(); + + size_t size = cond.size(); + c_offsets->resize(size); + c_data->reserve(a_data.size()); + + ColumnArray::Offset_t a_prev_offset = 0; + ColumnArray::Offset_t c_prev_offset = 0; + + for (size_t i = 0; i < size; ++i) + { + if (cond[i]) + copy_from_vector(i, a_data, a_offsets, a_prev_offset, *c_data, *c_offsets, c_prev_offset); + else + copy_from_constant(i, b_converted, *c_data, *c_offsets, c_prev_offset); + + a_prev_offset = a_offsets[i]; + } + } + + static void constant_vector( + const PODArray & cond, + const Array & a, + const PODArray & b_data, const ColumnArray::Offsets_t & b_offsets, + Block & block, size_t result) + { + PODArray * c_data = nullptr; + ColumnArray::Offsets_t * c_offsets = nullptr; + create_result_column(block, result, &c_data, &c_offsets); + + PODArray a_converted(a.size()); + for (size_t i = 0, size = a.size(); i < size; ++i) + a_converted[i] = a[i].get::Type>(); + + size_t size = cond.size(); + c_offsets->resize(size); + c_data->reserve(b_data.size()); + + ColumnArray::Offset_t b_prev_offset = 0; + ColumnArray::Offset_t c_prev_offset = 0; + + for (size_t i = 0; i < size; ++i) + { + if (cond[i]) + copy_from_constant(i, a_converted, *c_data, *c_offsets, c_prev_offset); + else + copy_from_vector(i, b_data, b_offsets, b_prev_offset, *c_data, *c_offsets, c_prev_offset); + + b_prev_offset = b_offsets[i]; + } + } + + static void constant_constant( + const PODArray & cond, + const Array & a, const Array & b, + Block & block, size_t result) + { + PODArray * c_data = nullptr; + ColumnArray::Offsets_t * c_offsets = nullptr; + create_result_column(block, result, &c_data, &c_offsets); + + PODArray a_converted(a.size()); + for (size_t i = 0, size = a.size(); i < size; ++i) + a_converted[i] = a[i].get::Type>(); + + PODArray b_converted(b.size()); + for (size_t i = 0, size = b.size(); i < size; ++i) + b_converted[i] = b[i].get::Type>(); + + size_t size = cond.size(); + c_offsets->resize(size); + c_data->reserve((std::max(a.size(), b.size())) * size); + + ColumnArray::Offset_t c_prev_offset = 0; + + for (size_t i = 0; i < size; ++i) + { + if (cond[i]) + copy_from_constant(i, a_converted, *c_data, *c_offsets, c_prev_offset); + else + copy_from_constant(i, b_converted, *c_data, *c_offsets, c_prev_offset); + } + } +}; + +template +struct NumArrayIfImpl +{ +private: + static void throw_error() + { + throw Exception("Internal logic error: invalid types of arguments 2 and 3 of if", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } +public: + static void vector_vector( + const PODArray & cond, + const PODArray & a_data, const ColumnArray::Offsets_t & a_offsets, + const PODArray & b_data, const ColumnArray::Offsets_t & b_offsets, + Block & block, size_t result) + { + throw_error(); + } + + static void vector_constant( + const PODArray & cond, + const PODArray & a_data, const ColumnArray::Offsets_t & a_offsets, + const Array & b, + Block & block, size_t result) + { + throw_error(); + } + + static void constant_vector( + const PODArray & cond, + const Array & a, + const PODArray & b_data, const ColumnArray::Offsets_t & b_offsets, + Block & block, size_t result) + { + throw_error(); + } + + static void constant_constant( + const PODArray & cond, + const Array & a, const Array & b, + Block & block, size_t result) + { + throw_error(); + } +}; + + template struct DataTypeFromFieldTypeOrError { @@ -347,8 +566,8 @@ private: size_t result, const ColumnVector * col_left) { - ColumnVector * col_right_vec = typeid_cast *>(&*block.getByPosition(arguments[2]).column); - ColumnConst * col_right_const = typeid_cast *>(&*block.getByPosition(arguments[2]).column); + const ColumnVector * col_right_vec = typeid_cast *>(&*block.getByPosition(arguments[2]).column); + const ColumnConst * col_right_const = typeid_cast *>(&*block.getByPosition(arguments[2]).column); if (!col_right_vec && !col_right_const) return false; @@ -371,8 +590,8 @@ private: size_t result, const ColumnConst * col_left) { - ColumnVector * col_right_vec = typeid_cast *>(&*block.getByPosition(arguments[2]).column); - ColumnConst * col_right_const = typeid_cast *>(&*block.getByPosition(arguments[2]).column); + const ColumnVector * col_right_vec = typeid_cast *>(&*block.getByPosition(arguments[2]).column); + const ColumnConst * col_right_const = typeid_cast *>(&*block.getByPosition(arguments[2]).column); if (!col_right_vec && !col_right_const) return false; @@ -387,10 +606,131 @@ private: return true; } + template + bool executeRightTypeArray( + const ColumnVector * cond_col, + Block & block, + const ColumnNumbers & arguments, + size_t result, + const ColumnArray * col_left_array, + const ColumnVector * col_left) + { + const IColumn * col_right_untyped = block.getByPosition(arguments[2]).column.get(); + + const ColumnArray * col_right_array = typeid_cast(col_right_untyped); + const ColumnConstArray * col_right_const_array = typeid_cast(col_right_untyped); + + if (!col_right_array && !col_right_const_array) + return false; + + typedef typename NumberTraits::ResultOfIf::Type ResultType; + + if (col_right_array) + { + std::cerr << "col_right_array\n"; + + const ColumnVector * col_right_vec = typeid_cast *>(&col_right_array->getData()); + + if (!col_right_vec) + return false; + + std::cerr << "!\n"; + + NumArrayIfImpl::vector_vector( + cond_col->getData(), + col_left->getData(), col_left_array->getOffsets(), + col_right_vec->getData(), col_right_array->getOffsets(), + block, result); + } + else + { + std::cerr << "col_right_const_array\n"; + + NumArrayIfImpl::vector_constant( + cond_col->getData(), + col_left->getData(), col_left_array->getOffsets(), + col_right_const_array->getData(), + block, result); + } + + return true; + } + + template + bool executeConstRightTypeArray( + const ColumnVector * cond_col, + Block & block, + const ColumnNumbers & arguments, + size_t result, + const ColumnConstArray * col_left_const_array) + { + const IColumn * col_right_untyped = block.getByPosition(arguments[2]).column.get(); + + const ColumnArray * col_right_array = typeid_cast(col_right_untyped); + const ColumnConstArray * col_right_const_array = typeid_cast(col_right_untyped); + + if (!col_right_array && !col_right_const_array) + return false; + + typedef typename NumberTraits::ResultOfIf::Type ResultType; + + if (col_right_array) + { + std::cerr << "col_right_array\n"; + + const ColumnVector * col_right_vec = typeid_cast *>(&col_right_array->getData()); + + if (!col_right_vec) + return false; + + std::cerr << "!\n"; + + NumArrayIfImpl::constant_vector( + cond_col->getData(), + col_left_const_array->getData(), + col_right_vec->getData(), col_right_array->getOffsets(), + block, result); + } + else + { + std::cerr << "col_right_const_array\n"; + + NumArrayIfImpl::constant_constant( + cond_col->getData(), + col_left_const_array->getData(), + col_right_const_array->getData(), + block, result); + } + + return true; + } + template bool executeLeftType(const ColumnVector * cond_col, Block & block, const ColumnNumbers & arguments, size_t result) { - if (ColumnVector * col_left = typeid_cast *>(&*block.getByPosition(arguments[1]).column)) + const IColumn * col_left_untyped = block.getByPosition(arguments[1]).column.get(); + + const ColumnVector * col_left = nullptr; + const ColumnConst * col_const_left = nullptr; + const ColumnArray * col_arr_left = nullptr; + const ColumnConstArray * col_const_arr_left = nullptr; + + col_left = typeid_cast *>(col_left_untyped); + if (!col_left) + { + col_const_left = typeid_cast *>(col_left_untyped); + if (!col_const_left) + { + col_arr_left = typeid_cast(col_left_untyped); + + if (col_arr_left) + col_left = typeid_cast *>(&col_arr_left->getData()); + else + col_const_arr_left = typeid_cast(col_left_untyped); + } + } + + if (col_left) { if ( executeRightType(cond_col, block, arguments, result, col_left) || executeRightType(cond_col, block, arguments, result, col_left) @@ -405,21 +745,61 @@ private: return true; else throw Exception("Illegal column " + block.getByPosition(arguments[2]).column->getName() - + " of third argument of function " + getName(), - ErrorCodes::ILLEGAL_COLUMN); + + " of third argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); } - else if (ColumnConst * col_left = typeid_cast *>(&*block.getByPosition(arguments[1]).column)) + else if (col_const_left) { - if ( executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left) - || executeConstRightType(cond_col, block, arguments, result, col_left)) + if ( executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left) + || executeConstRightType(cond_col, block, arguments, result, col_const_left)) + return true; + else + throw Exception("Illegal column " + block.getByPosition(arguments[2]).column->getName() + + " of third argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } + else if (col_arr_left && col_left) + { + std::cerr << "col_arr_left\n"; + + if ( executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left)) + return true; + else + throw Exception("Illegal column " + block.getByPosition(arguments[2]).column->getName() + + " of third argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } + else if (col_const_arr_left) + { + std::cerr << "col_const_arr_left\n"; + + if ( executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) + || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left)) return true; else throw Exception("Illegal column " + block.getByPosition(arguments[2]).column->getName() @@ -432,10 +812,10 @@ private: bool executeString(const ColumnVector * cond_col, Block & block, const ColumnNumbers & arguments, size_t result) { - ColumnString * col_then = typeid_cast(&*block.getByPosition(arguments[1]).column); - ColumnString * col_else = typeid_cast(&*block.getByPosition(arguments[2]).column); - ColumnConstString * col_then_const = typeid_cast(&*block.getByPosition(arguments[1]).column); - ColumnConstString * col_else_const = typeid_cast(&*block.getByPosition(arguments[2]).column); + const ColumnString * col_then = typeid_cast(&*block.getByPosition(arguments[1]).column); + const ColumnString * col_else = typeid_cast(&*block.getByPosition(arguments[2]).column); + const ColumnConstString * col_then_const = typeid_cast(&*block.getByPosition(arguments[1]).column); + const ColumnConstString * col_else_const = typeid_cast(&*block.getByPosition(arguments[2]).column); ColumnString * col_res = new ColumnString; block.getByPosition(result).column = col_res; @@ -446,31 +826,31 @@ private: if (col_then && col_else) StringIfImpl::vector_vector( cond_col->getData(), - col_then->getChars(), col_then->getOffsets(), - col_else->getChars(), col_else->getOffsets(), - res_vec, res_offsets); - else if (col_then && col_else_const) - StringIfImpl::vector_constant( - cond_col->getData(), - col_then->getChars(), col_then->getOffsets(), - col_else_const->getData(), - res_vec, res_offsets); - else if (col_then_const && col_else) - StringIfImpl::constant_vector( - cond_col->getData(), - col_then_const->getData(), - col_else->getChars(), col_else->getOffsets(), - res_vec, res_offsets); - else if (col_then_const && col_else_const) - StringIfImpl::constant_constant( - cond_col->getData(), - col_then_const->getData(), - col_else_const->getData(), - res_vec, res_offsets); - else - return false; + col_then->getChars(), col_then->getOffsets(), + col_else->getChars(), col_else->getOffsets(), + res_vec, res_offsets); + else if (col_then && col_else_const) + StringIfImpl::vector_constant( + cond_col->getData(), + col_then->getChars(), col_then->getOffsets(), + col_else_const->getData(), + res_vec, res_offsets); + else if (col_then_const && col_else) + StringIfImpl::constant_vector( + cond_col->getData(), + col_then_const->getData(), + col_else->getChars(), col_else->getOffsets(), + res_vec, res_offsets); + else if (col_then_const && col_else_const) + StringIfImpl::constant_constant( + cond_col->getData(), + col_then_const->getData(), + col_else_const->getData(), + res_vec, res_offsets); + else + return false; - return true; + return true; } public: @@ -492,6 +872,9 @@ public: throw Exception("Illegal type of first argument (condition) of function if. Must be UInt8.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + const DataTypeArray * type_arr1 = typeid_cast(arguments[1].get()); + const DataTypeArray * type_arr2 = typeid_cast(arguments[2].get()); + if (arguments[1]->behavesAsNumber() && arguments[2]->behavesAsNumber()) { DataTypePtr type_res; @@ -509,6 +892,11 @@ public: ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return type_res; } + else if (type_arr1 && type_arr2) + { + /// NOTE Сообщения об ошибках будут относится к типам элементов массивов, что немного некорректно. + return new DataTypeArray(getReturnType({arguments[0], type_arr1->getNestedType(), type_arr2->getNestedType()})); + } else if (arguments[1]->getName() != arguments[2]->getName()) { throw Exception("Incompatible second and third arguments for function " + getName() + ": " @@ -542,6 +930,7 @@ public: cond_col = typeid_cast *>(&*materialized_cond_col); } } + if (cond_col) { if (!( executeLeftType(cond_col, block, arguments, result) @@ -558,11 +947,12 @@ public: throw Exception("Illegal columns " + block.getByPosition(arguments[1]).column->getName() + " and " + block.getByPosition(arguments[2]).column->getName() + " of second (then) and third (else) arguments of function " + getName(), - ErrorCodes::ILLEGAL_COLUMN); + ErrorCodes::ILLEGAL_COLUMN); } else - throw Exception("Illegal column " + cond_col->getName() + " of first argument of function " + getName() + ". Must be ColumnUInt8 or ColumnConstUInt8.", - ErrorCodes::ILLEGAL_COLUMN); + throw Exception("Illegal column " + cond_col->getName() + " of first argument of function " + getName() + + ". Must be ColumnUInt8 or ColumnConstUInt8.", + ErrorCodes::ILLEGAL_COLUMN); } }; From 0e01dad0a3645a9f5b81fb17b57af6ce5cb732e7 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 17 Jun 2015 05:02:53 +0300 Subject: [PATCH 4/4] dbms: added support for numeric arrays for arguments of function if [#METR-16700]. --- .../DB/Functions/FunctionsConditional.h | 60 ++-- .../0_stateless/00175_if_num_arrays.reference | 288 ++++++++++++++++++ .../0_stateless/00175_if_num_arrays.sql | 30 ++ 3 files changed, 345 insertions(+), 33 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00175_if_num_arrays.reference create mode 100644 dbms/tests/queries/0_stateless/00175_if_num_arrays.sql diff --git a/dbms/include/DB/Functions/FunctionsConditional.h b/dbms/include/DB/Functions/FunctionsConditional.h index c2f44b47ff3..5a46247a7fb 100644 --- a/dbms/include/DB/Functions/FunctionsConditional.h +++ b/dbms/include/DB/Functions/FunctionsConditional.h @@ -295,10 +295,9 @@ struct NumArrayIfImpl to_offsets[i] = to_prev_offset; } - template static ALWAYS_INLINE void copy_from_constant( size_t i, - const PODArray & from_data, + const PODArray & from_data, PODArray & to_data, ColumnArray::Offsets_t & to_offsets, ColumnArray::Offset_t & to_prev_offset) { size_t size_to_write = from_data.size(); @@ -361,7 +360,7 @@ struct NumArrayIfImpl ColumnArray::Offsets_t * c_offsets = nullptr; create_result_column(block, result, &c_data, &c_offsets); - PODArray b_converted(b.size()); + PODArray b_converted(b.size()); for (size_t i = 0, size = b.size(); i < size; ++i) b_converted[i] = b[i].get::Type>(); @@ -393,7 +392,7 @@ struct NumArrayIfImpl ColumnArray::Offsets_t * c_offsets = nullptr; create_result_column(block, result, &c_data, &c_offsets); - PODArray a_converted(a.size()); + PODArray a_converted(a.size()); for (size_t i = 0, size = a.size(); i < size; ++i) a_converted[i] = a[i].get::Type>(); @@ -424,11 +423,11 @@ struct NumArrayIfImpl ColumnArray::Offsets_t * c_offsets = nullptr; create_result_column(block, result, &c_data, &c_offsets); - PODArray a_converted(a.size()); + PODArray a_converted(a.size()); for (size_t i = 0, size = a.size(); i < size; ++i) a_converted[i] = a[i].get::Type>(); - PODArray b_converted(b.size()); + PODArray b_converted(b.size()); for (size_t i = 0, size = b.size(); i < size; ++i) b_converted[i] = b[i].get::Type>(); @@ -627,15 +626,11 @@ private: if (col_right_array) { - std::cerr << "col_right_array\n"; - const ColumnVector * col_right_vec = typeid_cast *>(&col_right_array->getData()); if (!col_right_vec) return false; - std::cerr << "!\n"; - NumArrayIfImpl::vector_vector( cond_col->getData(), col_left->getData(), col_left_array->getOffsets(), @@ -644,7 +639,9 @@ private: } else { - std::cerr << "col_right_const_array\n"; + if (!typeid_cast::Type *>( + typeid_cast(*col_right_const_array->getDataType()).getNestedType().get())) + return false; NumArrayIfImpl::vector_constant( cond_col->getData(), @@ -676,15 +673,11 @@ private: if (col_right_array) { - std::cerr << "col_right_array\n"; - const ColumnVector * col_right_vec = typeid_cast *>(&col_right_array->getData()); if (!col_right_vec) return false; - std::cerr << "!\n"; - NumArrayIfImpl::constant_vector( cond_col->getData(), col_left_const_array->getData(), @@ -693,7 +686,9 @@ private: } else { - std::cerr << "col_right_const_array\n"; + if (!typeid_cast::Type *>( + typeid_cast(*col_right_const_array->getDataType()).getNestedType().get())) + return false; NumArrayIfImpl::constant_constant( cond_col->getData(), @@ -713,6 +708,7 @@ private: const ColumnVector * col_left = nullptr; const ColumnConst * col_const_left = nullptr; const ColumnArray * col_arr_left = nullptr; + const ColumnVector * col_arr_left_elems = nullptr; const ColumnConstArray * col_const_arr_left = nullptr; col_left = typeid_cast *>(col_left_untyped); @@ -724,7 +720,7 @@ private: col_arr_left = typeid_cast(col_left_untyped); if (col_arr_left) - col_left = typeid_cast *>(&col_arr_left->getData()); + col_arr_left_elems = typeid_cast *>(&col_arr_left->getData()); else col_const_arr_left = typeid_cast(col_left_untyped); } @@ -766,30 +762,28 @@ private: + " of third argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); } - else if (col_arr_left && col_left) + else if (col_arr_left && col_arr_left_elems) { - std::cerr << "col_arr_left\n"; - - if ( executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left) - || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_left)) + if ( executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems) + || executeRightTypeArray(cond_col, block, arguments, result, col_arr_left, col_arr_left_elems)) return true; else throw Exception("Illegal column " + block.getByPosition(arguments[2]).column->getName() + " of third argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); } - else if (col_const_arr_left) + else if (col_const_arr_left + && typeid_cast::Type *>( + typeid_cast(*col_const_arr_left->getDataType()).getNestedType().get())) { - std::cerr << "col_const_arr_left\n"; - if ( executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) || executeConstRightTypeArray(cond_col, block, arguments, result, col_const_arr_left) diff --git a/dbms/tests/queries/0_stateless/00175_if_num_arrays.reference b/dbms/tests/queries/0_stateless/00175_if_num_arrays.reference new file mode 100644 index 00000000000..3defad5015a --- /dev/null +++ b/dbms/tests/queries/0_stateless/00175_if_num_arrays.reference @@ -0,0 +1,288 @@ +res +Array(UInt8) +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +res +Array(UInt8) +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +res +Array(UInt8) +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +res +Array(UInt8) +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +[3,4,5] +[1,2] +res +Array(Int64) +[] +[1,2] +[] +[1,2] +[] +[1,2] +[] +[1,2] +[] +[1,2] +res +Array(UInt64) +[] +[1,2] +[0,1] +[1,2] +[0,1,2,3] +[1,2] +[0,1,2,3,4,5] +[1,2] +[0,1,2,3,4,5,6,7] +[1,2] +res +Array(UInt64) +[0,1,2,3,4,5,6,7,8,9] +[0] +[0,1,2,3,4,5,6,7] +[0,1,2] +[0,1,2,3,4,5] +[0,1,2,3,4] +[0,1,2,3] +[0,1,2,3,4,5,6] +[0,1] +[0,1,2,3,4,5,6,7,8] +res +Array(Int32) +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +res +Array(Int16) +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +res +Array(Int32) +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +res +Array(Int64) +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +res +Array(Int32) +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +res +Array(Int16) +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +res +Array(Int32) +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +res +Array(Int64) +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +res +Array(Int32) +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +res +Array(Int16) +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +res +Array(Int32) +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +res +Array(Int64) +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +res +Array(Int32) +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +[300,-500000,500] +[256,257] +res +Array(Int16) +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +[3,4,-5] +[1,2] +res +Array(Int32) +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +[3,4,-5] +[256] +res +Array(Int64) +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +[-1] +[4294967295] +res +Array(Float64) +[] +[1.1,2] +[] +[1.1,2] +[] +[1.1,2] +[] +[1.1,2] +[] +[1.1,2] diff --git a/dbms/tests/queries/0_stateless/00175_if_num_arrays.sql b/dbms/tests/queries/0_stateless/00175_if_num_arrays.sql new file mode 100644 index 00000000000..11cae872ca3 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00175_if_num_arrays.sql @@ -0,0 +1,30 @@ +SELECT number % 2 ? [1, 2] : [3, 4, 5] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? materialize([1, 2]) : [3, 4, 5] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? [1, 2] : materialize([3, 4, 5]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? materialize([1, 2]) : materialize([3, 4, 5]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; + +SELECT number % 2 ? [1, 2] : emptyArrayInt64() AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? [1, 2] : range(number) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? range(number) : range(toUInt64(10 - number)) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; + +SELECT number % 2 ? [256, 257] : [300, -500000, 500] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? [1, 2] : [3, 4, -5] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? [256] : [3, 4, -5] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? [0xFFFFFFFF] : [-1] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; + +SELECT number % 2 ? materialize([256, 257]) : [300, -500000, 500] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? materialize([1, 2]) : [3, 4, -5] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? materialize([256]) : [3, 4, -5] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? materialize([0xFFFFFFFF]) : [-1] AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; + +SELECT number % 2 ? [256, 257] : materialize([300, -500000, 500]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? [1, 2] : materialize([3, 4, -5]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? [256] : materialize([3, 4, -5]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? [0xFFFFFFFF] : materialize([-1]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; + +SELECT number % 2 ? materialize([256, 257]) : materialize([300, -500000, 500]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? materialize([1, 2]) : materialize([3, 4, -5]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? materialize([256]) : materialize([3, 4, -5]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; +SELECT number % 2 ? materialize([0xFFFFFFFF]) : materialize([-1]) AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes; + +SELECT number % 2 ? [1.1, 2] : emptyArrayInt32() AS res FROM system.numbers LIMIT 10 FORMAT TabSeparatedWithNamesAndTypes;