diff --git a/dbms/include/DB/Functions/FunctionsArray.h b/dbms/include/DB/Functions/FunctionsArray.h index 8db734bb9ba..34cc8c2a1b6 100644 --- a/dbms/include/DB/Functions/FunctionsArray.h +++ b/dbms/include/DB/Functions/FunctionsArray.h @@ -189,7 +189,8 @@ public: template struct ArrayElementNumImpl { - /** Если negative = false - передаётся индекс с начала массива, начиная с нуля. + /** Процедура для константного идекса + * Если negative = false - передаётся индекс с начала массива, начиная с нуля. * Если negative = true - передаётся индекс с конца массива, начиная с нуля. */ template @@ -215,6 +216,9 @@ struct ArrayElementNumImpl } } + /** Процедура для неконстантного идекса + * index_type - тип данных идекса + */ template static void vector( const PODArray & data, const ColumnArray::Offsets_t & offsets, @@ -232,9 +236,7 @@ struct ArrayElementNumImpl if (index[i].getType() == Field::Types::UInt64) { UInt64 cur_id = safeGet(index[i]); - if (cur_id == 0) - throw Exception("Array indices is 1-based", ErrorCodes::ZERO_ARRAY_OR_TUPLE_INDEX); - else if (cur_id <= array_size) + if (cur_id > 0 && cur_id <= array_size) result[i] = data[current_offset + cur_id - 1]; else result[i] = T(); @@ -242,9 +244,7 @@ struct ArrayElementNumImpl else if (index[i].getType() == Field::Types::Int64) { Int64 cur_id = safeGet(index[i]); - if (cur_id == 0) - throw Exception("Array indices is 1-based", ErrorCodes::ZERO_ARRAY_OR_TUPLE_INDEX); - else if (cur_id > 0 && cur_id <= array_size) + if (cur_id > 0 && cur_id <= array_size) result[i] = data[current_offset + cur_id - 1]; else if (cur_id < 0 && -cur_id <= array_size) result[i] = data[offsets[i] + cur_id]; @@ -261,6 +261,10 @@ struct ArrayElementNumImpl struct ArrayElementStringImpl { + /** Процедура для константного идекса + * Если negative = false - передаётся индекс с начала массива, начиная с нуля. + * Если negative = true - передаётся индекс с конца массива, начиная с нуля. + */ template static void vectorConst( const ColumnString::Chars_t & data, const ColumnArray::Offsets_t & offsets, const ColumnString::Offsets_t & string_offsets, @@ -305,6 +309,9 @@ struct ArrayElementStringImpl } } + /** Процедура для неконстантного идекса + * index_type - тип данных идекса + */ template static void vector( const ColumnString::Chars_t & data, const ColumnArray::Offsets_t & offsets, const ColumnString::Offsets_t & string_offsets, @@ -325,10 +332,10 @@ struct ArrayElementStringImpl if (index[i].getType() == Field::Types::UInt64) { UInt64 cur_id = safeGet(index[i]); - if (cur_id == 0) - adjusted_index = array_size; /// Индекс не вписывается в рамки массива, заменяем заведомо слишком большим - else + if (cur_id > 0 && cur_id <= array_size) adjusted_index = cur_id - 1; + else + adjusted_index = array_size; /// Индекс не вписывается в рамки массива, заменяем заведомо слишком большим } else if (index[i].getType() == Field::Types::Int64) { @@ -577,7 +584,6 @@ private: return true; } - public: /// Получить имя функции. String getName() const diff --git a/dbms/tests/queries/0_stateless/00036_array_element.reference b/dbms/tests/queries/0_stateless/00036_array_element.reference index 6033afb6984..7ace3b06635 100644 --- a/dbms/tests/queries/0_stateless/00036_array_element.reference +++ b/dbms/tests/queries/0_stateless/00036_array_element.reference @@ -3,23 +3,28 @@ 13 11 0 +0 12 0 11 0 +0 Df ERT Ab + Df ABC + [1,2,3] 2 [1,2,3] 1 [1,2,3] 0 [1,2,3] 3 +[1,2,3] 0 [1,2,3] 2 [1,2,3] 1 [1,2,3] 0 @@ -28,3 +33,4 @@ ABC [1,2,3] 3 [1,2,3] 0 [1,2,3] 1 +[1,2,3] 0 diff --git a/dbms/tests/queries/0_stateless/00036_array_element.sql b/dbms/tests/queries/0_stateless/00036_array_element.sql index 4492e77feed..e0fc8a3c43b 100644 --- a/dbms/tests/queries/0_stateless/00036_array_element.sql +++ b/dbms/tests/queries/0_stateless/00036_array_element.sql @@ -1,31 +1,31 @@ DROP TABLE IF EXISTS array_element_test; CREATE TABLE array_element_test (arr Array(Int32), id Int32) ENGINE = Memory; -insert into array_element_test VALUES ([11,12,13], 2), ([11,12], 3), ([11,12,13], -1), ([11,12], -2), ([11,12], -3); +insert into array_element_test VALUES ([11,12,13], 2), ([11,12], 3), ([11,12,13], -1), ([11,12], -2), ([11,12], -3), ([11], 0); select arr[id] from array_element_test; DROP TABLE IF EXISTS array_element_test; CREATE TABLE array_element_test (arr Array(Int32), id UInt32) ENGINE = Memory; -insert into array_element_test VALUES ([11,12,13], 2), ([11,12], 3), ([11,12,13], 1), ([11,12], 4); +insert into array_element_test VALUES ([11,12,13], 2), ([11,12], 3), ([11,12,13], 1), ([11,12], 4), ([11], 0); select arr[id] from array_element_test; DROP TABLE IF EXISTS array_element_test; CREATE TABLE array_element_test (arr Array(String), id Int32) ENGINE = Memory; -insert into array_element_test VALUES (['Abc','Df','Q'], 2), (['Abc','DEFQ'], 3), (['ABC','Q','ERT'], -1), (['Ab','ber'], -2), (['AB','asd'], -3); +insert into array_element_test VALUES (['Abc','Df','Q'], 2), (['Abc','DEFQ'], 3), (['ABC','Q','ERT'], -1), (['Ab','ber'], -2), (['AB','asd'], -3), (['A'], 0); select arr[id] from array_element_test; DROP TABLE IF EXISTS array_element_test; CREATE TABLE array_element_test (arr Array(String), id UInt32) ENGINE = Memory; -insert into array_element_test VALUES (['Abc','Df','Q'], 2), (['Abc','DEFQ'], 3), (['ABC','Q','ERT'], 1), (['Ab','ber'], 4); +insert into array_element_test VALUES (['Abc','Df','Q'], 2), (['Abc','DEFQ'], 3), (['ABC','Q','ERT'], 1), (['Ab','ber'], 4), (['A'], 0); select arr[id] from array_element_test; DROP TABLE IF EXISTS array_element_test; CREATE TABLE array_element_test (id UInt32) ENGINE = Memory; -insert into array_element_test VALUES (2), (1), (4), (3); +insert into array_element_test VALUES (2), (1), (4), (3), (0); select [1, 2, 3] as arr, arr[id] from array_element_test; DROP TABLE IF EXISTS array_element_test; CREATE TABLE array_element_test (id Int32) ENGINE = Memory; -insert into array_element_test VALUES (-2), (1), (-4), (3), (2), (-1), (4), (-3); +insert into array_element_test VALUES (-2), (1), (-4), (3), (2), (-1), (4), (-3), (0); select [1, 2, 3] as arr, arr[id] from array_element_test; DROP TABLE IF EXISTS array_element_test;