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 #ifndef FAKE_TABLE_H
24 #define FAKE_TABLE_H
25 
26 #include <string.h>
27 #include <sys/types.h>
28 #include <ostream>
29 #include <string>
30 #include <vector>
31 
32 #include "gtest/gtest.h"
33 #include "lex_string.h"
34 #include "my_alloc.h"
35 #include "my_bitmap.h"
36 #include "my_dbug.h"
37 #include "my_inttypes.h"
38 #include "mysql_com.h"
39 #include "sql/current_thd.h"
40 #include "sql/field.h"
41 #include "sql/item.h"
42 #include "sql/key.h"
43 #include "sql/sql_bitmap.h"
44 #include "sql/sql_const.h"
45 #include "sql/sql_lex.h"
46 #include "sql/sql_list.h"
47 #include "sql/table.h"
48 #include "sql/thr_malloc.h"
49 #include "unittest/gunit/handler-t.h"
50 #include "unittest/gunit/mock_field_long.h"  // todo: put this #include first
51 
52 class handler;
53 struct handlerton;
54 
55 using std::string;
56 using std::vector;
57 using ::testing::NiceMock;
58 
59 static const uint MAX_TABLE_COLUMNS = sizeof(int) * 8;
60 
61 /*
62   A fake class for setting up TABLE_LIST object, required for table id mgmt.
63 */
64 class Fake_TABLE_LIST : public TABLE_LIST {
65  public:
Fake_TABLE_LIST()66   Fake_TABLE_LIST() {}
~Fake_TABLE_LIST()67   ~Fake_TABLE_LIST() {}
68 };
69 
70 /*
71   A fake class to make setting up a TABLE object a little easier.
72 */
73 class Fake_TABLE_SHARE : public TABLE_SHARE {
74   uint32 all_set_buf;
75 
76  public:
77   /**
78     Creates a TABLE_SHARE with the requested number of columns
79 
80     @param  number_of_columns  The number of columns in the table
81   */
Fake_TABLE_SHARE(uint number_of_columns)82   Fake_TABLE_SHARE(uint number_of_columns) {
83     static const char *fakepath = "fakepath";
84     fields = number_of_columns;
85     db_create_options = 0;
86     primary_key = 0;
87     column_bitmap_size = sizeof(int);
88     tmp_table = NO_TMP_TABLE;
89     db_low_byte_first = true;
90     path.str = const_cast<char *>(fakepath);
91     path.length = strlen(path.str);
92 
93     EXPECT_EQ(0, bitmap_init(&all_set, &all_set_buf, fields));
94     bitmap_set_above(&all_set, 0, true);
95   }
~Fake_TABLE_SHARE()96   ~Fake_TABLE_SHARE() {}
97 };
98 
99 /*
100   A fake class to make setting up a TABLE object a little easier. The
101   table has a local fake table share.
102 */
103 class Fake_TABLE : public TABLE {
104   // make room for 8 indexes (mysql permits 64)
105   static const int max_keys = 8;
106   KEY m_keys[max_keys];
107   // make room for up to 8 keyparts per index
108   KEY_PART_INFO m_key_part_infos[max_keys][8];
109 
110   static const int max_record_length = MAX_FIELD_WIDTH * MAX_TABLE_COLUMNS;
111   uchar m_record[max_record_length];
112 
113   Fake_TABLE_LIST table_list;
114   Fake_TABLE_SHARE table_share;
115   // Storage space for the handler's handlerton
116   Fake_handlerton fake_handlerton;
117   MY_BITMAP write_set_struct;
118   uint32 write_set_buf;
119   MY_BITMAP read_set_struct;
120   uint32 read_set_buf;
121   Field *m_field_array[MAX_TABLE_COLUMNS];
122   Mock_field_long *m_mock_field_array[MAX_TABLE_COLUMNS];
123 
124   // Counter for creating unique index id's. See create_index().
125   int highest_index_id;
126 
127   // Counter for creating unique table id's. See initialize().
128   static int highest_table_id;
129 
130  private:
initialize()131   void initialize() {
132     TABLE *as_table = static_cast<TABLE *>(this);
133     new (as_table) TABLE();
134     s = &table_share;
135     in_use = current_thd;
136     null_row = '\0';
137     read_set = &read_set_struct;
138     write_set = &write_set_struct;
139     next_number_field = nullptr;  // No autoinc column
140     pos_in_table_list = &table_list;
141     pos_in_table_list->select_lex =
142         new (&mem_root) SELECT_LEX(&mem_root, nullptr, nullptr);
143     table_list.table = this;
144     EXPECT_EQ(0, bitmap_init(write_set, &write_set_buf, s->fields));
145     EXPECT_EQ(0, bitmap_init(read_set, &read_set_buf, s->fields));
146 
147     const_table = false;
148     table_list.set_tableno(highest_table_id);
149     highest_table_id = (highest_table_id + 1) % MAX_TABLES;
150     key_info = &m_keys[0];
151     record[0] = &m_record[0];
152     memset(record[0], 0, max_record_length);
153     for (int i = 0; i < max_keys; i++)
154       key_info[i].key_part = m_key_part_infos[i];
155     // We choose non-zero to avoid it working by coincidence.
156     highest_index_id = 3;
157 
158     set_handler(&mock_handler);
159     mock_handler.change_table_ptr(this, &table_share);
160     field = m_field_array;
161   }
162 
163  public:
164   /**
165     Unless you hand it anything else, this class will create
166     Mock_field_long columns, and this is their pack_length.
167   */
168   static const int DEFAULT_PACK_LENGTH = Mock_field_long::PACK_LENGTH;
169   NiceMock<Mock_HANDLER> mock_handler;
170 
Fake_TABLE(List<Field> fields)171   Fake_TABLE(List<Field> fields)
172       : table_share(fields.elements),
173         mock_handler(static_cast<handlerton *>(nullptr), &table_share) {
174     initialize();
175     List_iterator<Field> it(fields);
176     int nbr_fields = 0;
177     for (Field *cur_field = it++; cur_field; cur_field = it++)
178       add(cur_field, nbr_fields++);
179   }
180 
Fake_TABLE(Field * column)181   Fake_TABLE(Field *column)
182       : table_share(1),
183         mock_handler(static_cast<handlerton *>(nullptr), &table_share) {
184     initialize();
185     add(column, 0);
186   }
187 
Fake_TABLE(Field * column1,Field * column2)188   Fake_TABLE(Field *column1, Field *column2)
189       : table_share(2),
190         mock_handler(static_cast<handlerton *>(nullptr), &table_share) {
191     initialize();
192     add(column1, 0);
193     add(column2, 1);
194   }
195 
Fake_TABLE(Field * column1,Field * column2,Field * column3)196   Fake_TABLE(Field *column1, Field *column2, Field *column3)
197       : table_share(3),
198         mock_handler(static_cast<handlerton *>(nullptr), &table_share) {
199     initialize();
200     add(column1, 0);
201     add(column2, 1);
202     add(column3, 2);
203   }
204 
205   /**
206     Creates a table with the requested number of columns without
207     creating indexes.
208 
209     @param  column_count     The number of columns in the table
210     @param  cols_nullable    Whether or not columns are allowed to be NULL
211   */
Fake_TABLE(int column_count,bool cols_nullable)212   Fake_TABLE(int column_count, bool cols_nullable)
213       : table_share(column_count),
214         mock_handler(&fake_handlerton, &table_share) {
215     DBUG_ASSERT(static_cast<size_t>(column_count) <= sizeof(int) * 8);
216     initialize();
217     for (int i = 0; i < column_count; ++i) {
218       std::stringstream str;
219       str << "field_" << (i + 1);
220       add(new (*THR_MALLOC)
221               Mock_field_long(str.str().c_str(), cols_nullable, false),
222           i);
223     }
224   }
225 
226   /**
227     Creates a fake TABLE and stores the values in their corresponding Fields.
228 
229     @param column_values The column values to be stored.
230     @param are_nullable Whether the columns are nullable.
231   */
232   Fake_TABLE(std::initializer_list<int> column_values, bool are_nullable = true)
233       : table_share(column_values.size()),
234         mock_handler(static_cast<handlerton *>(nullptr), &table_share) {
235     field = m_field_array;
236     initialize();
237     for (size_t i = 0; i < column_values.size(); ++i) {
238       std::stringstream s;
239       s << "field_" << i + 1;
240       field[i] =
241           new (*THR_MALLOC) Mock_field_long(s.str(), are_nullable, false);
242       field[i]->table = this;
243       const ptrdiff_t field_offset = i * MAX_FIELD_WIDTH;
244       field[i]->set_field_ptr(record[0] + field_offset + 1);
245       if (are_nullable) field[i]->set_null_ptr(record[0] + field_offset, 1);
246     }
247     int i = 0;
248     for (auto column_value : column_values) {
249       auto item = new Item_int(column_value);
250       item->save_in_field_no_warnings(field[i++], true);
251     }
252   }
253 
~Fake_TABLE()254   ~Fake_TABLE() {
255     /*
256       This DTOR should be empty, since we inherit from TABLE,
257       which cannot have virtual member functions.
258     */
259   }
260 
261   // Defines an index over (column1, column2) and generates a unique id.
create_index(Field * column1,Field * column2)262   int create_index(Field *column1, Field *column2) {
263     column1->set_flag(PART_KEY_FLAG);
264     column2->set_flag(PART_KEY_FLAG);
265     int index_id = highest_index_id++;
266     column1->key_start.set_bit(index_id);
267     keys_in_use_for_query.set_bit(index_id);
268     return index_id;
269   }
270 
set_handler(handler * h)271   void set_handler(handler *h) { file = h; }
get_share()272   TABLE_SHARE *get_share() { return &table_share; }
273 
274  private:
add(Field * new_field,int pos)275   void add(Field *new_field, int pos) {
276     field[pos] = new_field;
277     new_field->table = this;
278     new_field->orig_table = this;
279     static const char *table_name = "Fake";
280     new_field->table_name = &table_name;
281     new_field->set_field_index(pos);
282     bitmap_set_bit(read_set, pos);
283     const ptrdiff_t field_offset = pos * MAX_FIELD_WIDTH;
284     new_field->set_field_ptr(record[0] + field_offset + 1);
285     if (new_field->get_null_ptr() != nullptr)
286       new_field->set_null_ptr(record[0] + field_offset, 1);
287   }
288 };
289 
290 #endif  // FAKE_TABLE_H
291