/* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FAKE_TABLE_H #define FAKE_TABLE_H #include "sql_class.h" #include "handler-t.h" #include #include "mock_field_long.h" // todo: put this #include first using ::testing::NiceMock; using std::vector; using std::string; static const uint MAX_TABLE_COLUMNS= sizeof(int) * 8; /* A fake class for setting up TABLE_LIST object, required for table id mgmt. */ class Fake_TABLE_LIST : public TABLE_LIST { public: Fake_TABLE_LIST() { } ~Fake_TABLE_LIST() { } }; /* A fake class to make setting up a TABLE object a little easier. */ class Fake_TABLE_SHARE : public TABLE_SHARE { uint32 all_set_buf; public: /** Creates a TABLE_SHARE with the requested number of columns @param number_of_columns The number of columns in the table */ Fake_TABLE_SHARE(uint number_of_columns) { static const char *fakepath= "fakepath"; fields= number_of_columns; db_create_options= 0; primary_key= 0; column_bitmap_size= sizeof(int); tmp_table= NO_TMP_TABLE; db_low_byte_first= true; path.str= const_cast(fakepath); path.length= strlen(path.str); EXPECT_EQ(0, bitmap_init(&all_set, &all_set_buf, fields, false)); bitmap_set_above(&all_set, 0, 1); } ~Fake_TABLE_SHARE() {} }; /* A fake class to make setting up a TABLE object a little easier. The table has a local fake table share. */ class Fake_TABLE: public TABLE { // make room for 8 indexes (mysql permits 64) static const int max_keys= 8; KEY m_keys[max_keys]; // make room for up to 8 keyparts per index KEY_PART_INFO m_key_part_infos[max_keys][8]; Fake_TABLE_LIST table_list; Fake_TABLE_SHARE table_share; // Storage space for the handler's handlerton Fake_handlerton fake_handlerton; MY_BITMAP write_set_struct; uint32 write_set_buf; MY_BITMAP read_set_struct; uint32 read_set_buf; Field *m_field_array[MAX_TABLE_COLUMNS]; Mock_field_long *m_mock_field_array[MAX_TABLE_COLUMNS]; // Counter for creating unique index id's. See create_index(). int highest_index_id; // Counter for creating unique table id's. See initialize(). static int highest_table_id; void initialize() { s= &table_share; in_use= current_thd; null_row= '\0'; read_set= &read_set_struct; write_set= &write_set_struct; next_number_field= NULL; // No autoinc column pos_in_table_list= &table_list; table_list.table= this; EXPECT_EQ(0, bitmap_init(write_set, &write_set_buf, s->fields, false)); EXPECT_EQ(0, bitmap_init(read_set, &read_set_buf, s->fields, false)); const_table= false; table_list.set_tableno(highest_table_id); highest_table_id= (highest_table_id + 1) % MAX_TABLES; key_info= &m_keys[0]; for (int i= 0; i < max_keys; i++) key_info[i].key_part= m_key_part_infos[i]; // We choose non-zero to avoid it working by coincidence. highest_index_id= 3; set_handler(&mock_handler); mock_handler.change_table_ptr(this, &table_share); field= m_field_array; } public: /** Unless you hand it anything else, this class will create Mock_field_long columns, and this is their pack_length. */ static const int DEFAULT_PACK_LENGTH= Mock_field_long::PACK_LENGTH; NiceMock mock_handler; Fake_TABLE(List fields) : table_share(fields.elements), mock_handler(static_cast(NULL), &table_share) { field= m_field_array; List_iterator it(fields); int nbr_fields= 0; for (Field *cur_field= it++; cur_field; cur_field= it++) add(cur_field, nbr_fields++); initialize(); } Fake_TABLE(Field *column) : table_share(1), mock_handler(static_cast(NULL), &table_share) { initialize(); add(column, 0); } Fake_TABLE(Field *column1, Field *column2) : table_share(2), mock_handler(static_cast(NULL), &table_share) { initialize(); add(column1, 0); add(column2, 1); } Fake_TABLE(Field *column1, Field *column2, Field *column3) : table_share(3), mock_handler(static_cast(NULL), &table_share) { initialize(); add(column1, 0); add(column2, 1); add(column3, 2); } /** Creates a table with the requested number of columns without creating indexes. @param column_count The number of columns in the table @param cols_nullable Whether or not columns are allowed to be NULL */ Fake_TABLE(int column_count, bool cols_nullable) : table_share(column_count), mock_handler(&fake_handlerton, &table_share) { DBUG_ASSERT(static_cast(column_count) <= sizeof(int) * 8); initialize(); for (int i= 0; i < column_count; ++i) { std::stringstream str; str << "field_" << (i + 1); add(new Mock_field_long(str.str().c_str(), cols_nullable), i); } } /** Creates a one-column fake table and stores the value in the one field. @param column_value Item holding the integer value to be stored. */ Fake_TABLE(Item_int *column_value) : table_share(1), mock_handler(&fake_handlerton, &table_share) { initialize(); add(new Mock_field_long("field_1"), 0); column_value->save_in_field_no_warnings(field[0], true); } /** Creates a two-column fake table and stores the values in their corresponding fields. @param column1_value Item holding integer value to be stored. @param column2_value Item holding integer value to be stored. */ Fake_TABLE(Item_int *column1_value, Item_int *column2_value) : table_share(2), mock_handler(static_cast(NULL), &table_share) { field= m_field_array; field[0]= new Mock_field_long("field_1"); field[0]->table= this; field[1]= new Mock_field_long("field_2"); field[1]->table= this; initialize(); column1_value->save_in_field_no_warnings(field[0], true); column2_value->save_in_field_no_warnings(field[1], true); } ~Fake_TABLE() { /* This DTOR should be empty, since we inherit from TABLE, which cannot have virtual member functions. */ } // Defines an index over (column1, column2) and generates a unique id. int create_index(Field *column1, Field *column2) { column1->flags|= PART_KEY_FLAG; column2->flags|= PART_KEY_FLAG; int index_id= highest_index_id++; column1->key_start.set_bit(index_id); keys_in_use_for_query.set_bit(index_id); return index_id; } void set_handler(handler *h) { file= h; } TABLE_SHARE *get_share() { return &table_share; } private: void add(Field *new_field, int pos) { field[pos]= new_field; new_field->table= this; static const char *table_name= "Fake"; new_field->table_name= &table_name; new_field->field_index= pos; bitmap_set_bit(read_set, pos); } }; // We choose non-zero to avoid it working by coincidence. int Fake_TABLE::highest_table_id= 5; #endif // FAKE_TABLE_H