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