Fixed absolutely incorrect code; added test [#CLICKHOUSE-2755].

This commit is contained in:
Alexey Milovidov 2017-02-10 13:20:06 +03:00
parent 74cef1d69e
commit 0673f75265
4 changed files with 169 additions and 53 deletions

View File

@ -195,67 +195,45 @@ int ColumnNullable::compareAt(size_t n, size_t m, const IColumn & rhs_, int null
void ColumnNullable::getPermutation(bool reverse, size_t limit, Permutation & res) const
{
nested_column->getPermutation(reverse, limit, res);
size_t s = res.size();
/// Cannot pass limit because of unknown amount of NULLs.
nested_column->getPermutation(reverse, 0, res);
/// Since we have created a permutation "res" that sorts a subset of the column values
/// and some of these values may actually be nulls, there is no guarantee that
/// these null values are well positioned. So we create a permutation "p" which
/// operates on the result of "res" by moving all the null values to the required
/// direction and leaving the order of the remaining elements unchanged.
/// Shift all NULL values to the end.
/// Create the permutation p.
Permutation p;
p.resize(s);
size_t read_idx = 0;
size_t write_idx = 0;
size_t end_idx = res.size();
size_t pos_left = 0;
size_t pos_right = s - 1;
if (!limit)
limit = end_idx;
if (reverse)
while (read_idx < limit && !isNullAt(res[read_idx]))
{
/// Move the null elements to the right.
for (size_t i = 0; i < s; ++i)
{
if (isNullAt(res[i]))
{
p[i] = pos_right;
--pos_right;
}
else
{
p[i] = pos_left;
++pos_left;
}
}
}
else
{
/// Move the null elements to the left.
for (size_t i = 0; i < s; ++i)
{
size_t j = s - i - 1;
if (isNullAt(res[j]))
{
p[j] = pos_left;
++pos_left;
}
else
{
p[j] = pos_right;
--pos_right;
}
}
++read_idx;
++write_idx;
}
/// Combine the permutations res and p.
Permutation res2;
res2.resize(s);
++read_idx;
for (size_t i = 0; i < s; ++i)
res2[i] = res[p[i]];
/// Invariants:
/// write_idx < read_idx
/// write_idx points to NULL
/// read_idx will be incremented to position of next not-NULL
/// there are range of NULLs between write_idx and read_idx - 1,
/// We are moving elements from end to begin of this range,
/// so range will "bubble" towards the end.
/// Relative order of NULL elements could be changed,
/// but relative order of non-NULLs is preserved.
res = std::move(res2);
while (read_idx < end_idx && write_idx < limit)
{
if (!isNullAt(res[read_idx]))
{
std::swap(res[read_idx], res[write_idx]);
++write_idx;
}
++read_idx;
}
}
void ColumnNullable::reserve(size_t n)

View File

@ -98,7 +98,7 @@ void sortBlock(Block & block, const SortDescription & description, size_t limit)
if (!block)
return;
/// Если столбец сортировки один
/// If only one column to sort by
if (description.size() == 1)
{
bool reverse = description[0].direction == -1;

View File

@ -0,0 +1,116 @@
0
0
0
0
0
0
0
0
0
0
0
1
2
2
3
4
12
\N
12
4
3
2
2
1
0
0
0
0
0
0
0
0
0
0
0
\N
1
2
4
5
7
8
\N
\N
\N
\N
8
7
5
4
2
1
\N
\N
\N
\N
1
2
4
5
7
8
\N
\N
\N
\N
8
7
5
4
2
1
\N
\N
\N
\N
1 1
2 2
4 4
5 5
7 7
8 8
\N 0
\N 3
\N 6
\N 9
8 8
7 7
5 5
4 4
2 2
1 1
\N 0
\N 3
\N 6
\N 9
1 1
2 2
4 4
5 5
7 7
8 8
\N 0
\N 3
\N 6
\N 9
8 8
7 7
5 5
4 4
2 2
1 1
\N 0
\N 3
\N 6
\N 9

View File

@ -0,0 +1,22 @@
SELECT arrayJoin([0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,4,12,NULL]) AS x ORDER BY x;
SELECT arrayJoin([0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,4,12,NULL]) AS x ORDER BY x DESC;
SET max_block_size = 1000;
SELECT nullIf(number, number % 3 = 0 ? number : 0) AS x FROM (SELECT * FROM system.numbers LIMIT 10) ORDER BY x;
SELECT nullIf(number, number % 3 = 0 ? number : 0) AS x FROM (SELECT * FROM system.numbers LIMIT 10) ORDER BY x DESC;
SET max_block_size = 5;
SELECT nullIf(number, number % 3 = 0 ? number : 0) AS x FROM (SELECT * FROM system.numbers LIMIT 10) ORDER BY x;
SELECT nullIf(number, number % 3 = 0 ? number : 0) AS x FROM (SELECT * FROM system.numbers LIMIT 10) ORDER BY x DESC;
SET max_block_size = 1000;
SELECT nullIf(number, number % 3 = 0 ? number : 0) AS x, number AS y FROM (SELECT * FROM system.numbers LIMIT 10) ORDER BY x, y;
SELECT nullIf(number, number % 3 = 0 ? number : 0) AS x, number AS y FROM (SELECT * FROM system.numbers LIMIT 10) ORDER BY x DESC, y;
SET max_block_size = 5;
SELECT nullIf(number, number % 3 = 0 ? number : 0) AS x, number AS y FROM (SELECT * FROM system.numbers LIMIT 10) ORDER BY x, y;
SELECT nullIf(number, number % 3 = 0 ? number : 0) AS x, number AS y FROM (SELECT * FROM system.numbers LIMIT 10) ORDER BY x DESC, y;