1 /* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include <gtest/gtest.h>
24 #include <sys/types.h>
25
26 #include "my_inttypes.h"
27 #include "sql/filesort.h"
28 #include "sql/sort_param.h"
29 #include "sql/sql_lex.h"
30 #include "sql/sql_sort.h"
31 #include "sql/sys_vars.h"
32 #include "unittest/gunit/fake_table.h"
33 #include "unittest/gunit/test_utils.h"
34
35 namespace make_sortkey_unittest {
36
37 using my_testing::Mock_error_handler;
38 using my_testing::Server_initializer;
39
40 /**
41 Test that sortlength() and make_sortkey() agree on what to do:
42 i.e. that there is no buffer underwrite/overwrite in make_sortkey()
43 if sortlength() has set a very small size.
44
45 We allocate a buffer, fill it with 'a's and then tell make_sortkey()
46 to put it's result somewhere in the middle.
47 The buffer should be unchanged outside of the area determined by sortlength.
48 */
49 class MakeSortKeyTest : public ::testing::Test {
50 protected:
MakeSortKeyTest()51 MakeSortKeyTest() {
52 m_sort_fields[0] = st_sort_field();
53 m_sort_fields[1] = st_sort_field();
54 m_sort_param.local_sortorder =
55 Bounds_checked_array<st_sort_field>(m_sort_fields, 1);
56 memset(m_buff, 'a', sizeof(m_buff));
57 m_to = Bounds_checked_array<uchar>(&m_buff[8], sizeof(m_buff) - 8);
58 }
59
SetUp()60 virtual void SetUp() { initializer.SetUp(); }
TearDown()61 virtual void TearDown() { initializer.TearDown(); }
62
thd()63 THD *thd() { return initializer.thd(); }
64
verify_buff(uint length)65 void verify_buff(uint length) {
66 for (uchar *pu = m_buff; pu < m_to.array(); ++pu) {
67 EXPECT_EQ('a', *pu) << " position " << pu - m_buff;
68 }
69 for (uchar *pu = m_to.array() + length; pu < m_buff + 100; ++pu) {
70 EXPECT_EQ('a', *pu) << " position " << pu - m_buff;
71 }
72 }
73
74 Server_initializer initializer;
75
76 Sort_param m_sort_param;
77 st_sort_field m_sort_fields[2]; // sortlength() adds an end marker !!
78 uchar m_ref_buff[4]; // unused, but needed for make_sortkey()
79 uchar m_buff[100];
80 Bounds_checked_array<uchar> m_to;
81 };
82
TEST_F(MakeSortKeyTest,IntResult)83 TEST_F(MakeSortKeyTest, IntResult) {
84 thd()->variables.max_sort_length = 4U;
85 m_sort_fields[0].item = new Item_int(42);
86
87 const uint total_length = sortlength(thd(), m_sort_fields, 1);
88 EXPECT_EQ(sizeof(longlong), total_length);
89 EXPECT_EQ(sizeof(longlong), m_sort_fields[0].length);
90 EXPECT_EQ(INT_RESULT, m_sort_fields[0].result_type);
91
92 size_t longest_addon_so_far = 0; // Unused.
93 m_sort_param.make_sortkey(m_to, m_ref_buff, &longest_addon_so_far);
94 SCOPED_TRACE("");
95 verify_buff(total_length);
96 }
97
TEST_F(MakeSortKeyTest,IntResultNull)98 TEST_F(MakeSortKeyTest, IntResultNull) {
99 thd()->variables.max_sort_length = 4U;
100 Item *int_item = m_sort_fields[0].item = new Item_int(42);
101 int_item->maybe_null = true;
102 int_item->null_value = true;
103
104 const uint total_length = sortlength(thd(), m_sort_fields, 1);
105 EXPECT_EQ(1 + sizeof(longlong), total_length);
106 EXPECT_EQ(sizeof(longlong), m_sort_fields[0].length);
107 EXPECT_EQ(INT_RESULT, m_sort_fields[0].result_type);
108
109 size_t longest_addon_so_far = 0; // Unused.
110 m_sort_param.make_sortkey(m_to, m_ref_buff, &longest_addon_so_far);
111 SCOPED_TRACE("");
112 verify_buff(total_length);
113 }
114
TEST_F(MakeSortKeyTest,DecimalResult)115 TEST_F(MakeSortKeyTest, DecimalResult) {
116 const char dec_str[] = "1234567890.1234567890";
117 thd()->variables.max_sort_length = 4U;
118 m_sort_fields[0].item =
119 new Item_decimal(POS(), dec_str, strlen(dec_str), &my_charset_bin);
120 Parse_context pc(thd(), thd()->lex->current_select());
121 EXPECT_FALSE(m_sort_fields[0].item->itemize(&pc, &m_sort_fields[0].item));
122
123 const uint total_length = sortlength(thd(), m_sort_fields, 1);
124 EXPECT_EQ(10U, total_length);
125 EXPECT_EQ(10U, m_sort_fields[0].length);
126 EXPECT_EQ(DECIMAL_RESULT, m_sort_fields[0].result_type);
127
128 size_t longest_addon_so_far = 0; // Unused.
129 m_sort_param.make_sortkey(m_to, m_ref_buff, &longest_addon_so_far);
130 SCOPED_TRACE("");
131 verify_buff(total_length);
132 }
133
TEST_F(MakeSortKeyTest,RealResult)134 TEST_F(MakeSortKeyTest, RealResult) {
135 const char dbl_str[] = "1234567890.1234567890";
136 thd()->variables.max_sort_length = 4U;
137 m_sort_fields[0].item = new Item_float(dbl_str, strlen(dbl_str));
138
139 const uint total_length = sortlength(thd(), m_sort_fields, 1);
140 EXPECT_EQ(sizeof(double), total_length);
141 EXPECT_EQ(sizeof(double), m_sort_fields[0].length);
142 EXPECT_EQ(REAL_RESULT, m_sort_fields[0].result_type);
143
144 size_t longest_addon_so_far = 0; // Unused.
145 m_sort_param.make_sortkey(m_to, m_ref_buff, &longest_addon_so_far);
146 SCOPED_TRACE("");
147 verify_buff(total_length);
148 }
149
TEST_F(MakeSortKeyTest,AddonFields)150 TEST_F(MakeSortKeyTest, AddonFields) {
151 m_sort_fields[0].item = new Item_int(42);
152 const uint total_length = sortlength(thd(), m_sort_fields, 1);
153 EXPECT_EQ(sizeof(longlong), total_length);
154 EXPECT_EQ(sizeof(longlong), m_sort_fields[0].length);
155 EXPECT_EQ(INT_RESULT, m_sort_fields[0].result_type);
156
157 Sort_addon_field addon_field;
158 float val = M_PI;
159 Field_float field(nullptr, 0, nullptr, '\0', Field::NONE, "", 0, false,
160 false);
161 Fake_TABLE table(&field);
162 table.s->db_low_byte_first = false;
163 field.set_field_ptr(reinterpret_cast<unsigned char *>(&val));
164 addon_field.field = &field;
165 addon_field.offset = 4; // Need room for the length bytes.
166 addon_field.max_length = field.max_packed_col_length();
167 Addon_fields addon_fields(make_array(&addon_field, 1));
168 addon_fields.set_using_packed_addons(true);
169 m_sort_param.addon_fields = &addon_fields;
170
171 // Test regular packing.
172 size_t longest_addon_so_far = 0; // Unused.
173 size_t len =
174 m_sort_param.make_sortkey(m_to, m_ref_buff, &longest_addon_so_far);
175 EXPECT_EQ(total_length + sizeof(float) + addon_field.offset, len);
176 float unpacked_val;
177 field.unpack(reinterpret_cast<uchar *>(&unpacked_val),
178 m_to.array() + m_sort_fields[0].length + addon_field.offset,
179 /*param_data=*/0);
180 EXPECT_EQ(unpacked_val, val);
181
182 // Test truncation. (The actual contents don't matter in this case.)
183 std::unique_ptr<uchar[]> trunc_buf(new uchar[len - 4]);
184 size_t trunc_len = m_sort_param.make_sortkey(
185 make_array(trunc_buf.get(), len - 4), m_ref_buff, &longest_addon_so_far);
186 EXPECT_GT(trunc_len, len - 4)
187 << "make_sortkey() should report back that there was not enough room.";
188 }
189
190 } // namespace make_sortkey_unittest
191