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