struct TABLE_SHARE { TABLE_SHARE() {} /* Remove gcc warning */ /** Category of this table. */ TABLE_CATEGORY table_category; /* hash of field names (contains pointers to elements of field array) */ HASH name_hash; /* hash of field names */ MEM_ROOT mem_root; TYPELIB keynames; /* Pointers to keynames */ TYPELIB fieldnames; /* Pointer to fieldnames */ TYPELIB *intervals; /* pointer to interval info */ mysql_mutex_t LOCK_ha_data; /* To protect access to ha_data */ TABLE_SHARE *next, **prev; /* Link to unused shares */ /* Doubly-linked (back-linked) lists of used and unused TABLE objects for this share. */ I_P_List <TABLE, TABLE_share> used_tables; I_P_List <TABLE, TABLE_share> free_tables; /* The following is copied to each TABLE on OPEN */ Field **field; Field **found_next_number_field; Field *timestamp_field; /* Used only during open */ KEY *key_info; /* data of keys in database */ uint *blob_field; /* Index to blobs in Field arrray*/ uchar *default_values; /* row with default values */ LEX_STRING comment; /* Comment about table */ CHARSET_INFO *table_charset; /* Default charset of string fields */ MY_BITMAP all_set; /* Key which is used for looking-up table in table cache and in the list of thread's temporary tables. Has the form of: "database_name\0table_name\0" + optional part for temporary tables. Note that all three 'table_cache_key', 'db' and 'table_name' members must be set (and be non-zero) for tables in table cache. They also should correspond to each other. To ensure this one can use set_table_cache() methods. */ LEX_STRING table_cache_key; LEX_STRING db; /* Pointer to db */ LEX_STRING table_name; /* Table name (for open) */ LEX_STRING path; /* Path to .frm file (from datadir) */ LEX_STRING normalized_path; /* unpack_filename(path) */ LEX_STRING connect_string; /* Set of keys in use, implemented as a Bitmap. Excludes keys disabled by ALTER TABLE ... DISABLE KEYS. */ key_map keys_in_use; key_map keys_for_keyread; ha_rows min_rows, max_rows; /* create information */ ulong avg_row_length; /* create information */ ulong version, mysql_version; ulong reclength; /* Recordlength */ plugin_ref db_plugin; /* storage engine plugin */ inline handlerton *db_type() const /* table_type for handler */ { // DBUG_ASSERT(db_plugin); return db_plugin ? plugin_data(db_plugin, handlerton*) : NULL; } enum row_type row_type; /* How rows are stored */ enum tmp_table_type tmp_table; uint ref_count; /* How many TABLE objects uses this */ uint blob_ptr_size; /* 4 or 8 */ uint key_block_size; /* create key_block_size, if used */ uint null_bytes, last_null_bit_pos; uint fields; /* Number of fields */ uint rec_buff_length; /* Size of table->record[] buffer */ uint keys, key_parts; uint max_key_length, max_unique_length, total_key_length; uint uniques; /* Number of UNIQUE index */ uint null_fields; /* number of null fields */ uint blob_fields; /* number of blob fields */ uint timestamp_field_offset; /* Field number for timestamp field */ uint varchar_fields; /* number of varchar fields */ uint db_create_options; /* Create options from database */ uint db_options_in_use; /* Options in use */ uint db_record_offset; /* if HA_REC_IN_SEQ */ uint rowid_field_offset; /* Field_nr +1 to rowid field */ /* Primary key index number, used in TABLE::key_info[] */ uint primary_key; uint next_number_index; /* autoincrement key number */ uint next_number_key_offset; /* autoinc keypart offset in a key */ uint next_number_keypart; /* autoinc keypart number in a key */ uint error, open_errno, errarg; /* error from open_table_def() */ uint column_bitmap_size; uchar frm_version; bool null_field_first; bool system; /* Set if system table (one record) */ bool crypted; /* If .frm file is crypted */ bool db_low_byte_first; /* Portable row format */ bool crashed; bool is_view; ulong table_map_id; /* for row-based replication */ /* Cache for row-based replication table share checks that does not need to be repeated. Possible values are: -1 when cache value is not calculated yet, 0 when table *shall not* be replicated, 1 when table *may* be replicated. */ int cached_row_logging_check; /* Storage media to use for this table (unless another storage media has been specified on an individual column - in versions where that is supported) */ enum ha_storage_media default_storage_media; /* Name of the tablespace used for this table */ char *tablespace; #ifdef WITH_PARTITION_STORAGE_ENGINE /* filled in when reading from frm */ bool auto_partitioned; char *partition_info_str; uint partition_info_str_len; uint partition_info_buffer_size; handlerton *default_part_db_type; #endif /** Cache the checked structure of this table. The pointer data is used to describe the structure that a instance of the table must have. Each element of the array specifies a field that must exist on the table. The pointer is cached in order to perform the check only once -- when the table is loaded from the disk. */ const TABLE_FIELD_DEF *table_field_def_cache; /** place to store storage engine specific data */ void *ha_data; void (*ha_data_destroy)(void *); /* An optional destructor for ha_data */ #ifdef WITH_PARTITION_STORAGE_ENGINE /** place to store partition specific data, LOCK_ha_data hold while init. */ HA_DATA_PARTITION *ha_part_data; /* Destructor for ha_part_data */ void (*ha_part_data_destroy)(HA_DATA_PARTITION *); #endif /** Instrumentation for this table share. */ PSI_table_share *m_psi; /** List of tickets representing threads waiting for the share to be flushed. */ Wait_for_flush_list m_flush_tickets; /* Set share's table cache key and update its db and table name appropriately. SYNOPSIS set_table_cache_key() key_buff Buffer with already built table cache key to be referenced from share. key_length Key length. NOTES Since 'key_buff' buffer will be referenced from share it should has same life-time as share itself. This method automatically ensures that TABLE_SHARE::table_name/db have appropriate values by using table cache key as their source. */ void set_table_cache_key(char *key_buff, uint key_length) { table_cache_key.str= key_buff; table_cache_key.length= key_length; /* Let us use the fact that the key is "db/0/table_name/0" + optional part for temporary tables. */ db.str= table_cache_key.str; db.length= strlen(db.str); table_name.str= db.str + db.length + ; table_name.length= strlen(table_name.str); } /* Set share's table cache key and update its db and table name appropriately. SYNOPSIS set_table_cache_key() key_buff Buffer to be used as storage for table cache key (should be at least key_length bytes). key Value for table cache key. key_length Key length. NOTE Since 'key_buff' buffer will be used as storage for table cache key it should has same life-time as share itself. */ void set_table_cache_key(char *key_buff, const char *key, uint key_length) { memcpy(key_buff, key, key_length); set_table_cache_key(key_buff, key_length); } inline bool honor_global_locks() { return ((table_category == TABLE_CATEGORY_USER) || (table_category == TABLE_CATEGORY_SYSTEM)); } inline bool require_write_privileges() { return (table_category == TABLE_CATEGORY_LOG); } inline ulong get_table_def_version() { return table_map_id; } /** Is this table share being expelled from the table definition cache? */ inline bool has_old_version() const { return version != refresh_version; } /** Convert unrelated members of TABLE_SHARE to one enum representing its type. @todo perhaps we need to have a member instead of a function. */ enum enum_table_ref_type get_table_ref_type() const { if (is_view) return TABLE_REF_VIEW; switch (tmp_table) { case NO_TMP_TABLE: return TABLE_REF_BASE_TABLE; case SYSTEM_TMP_TABLE: return TABLE_REF_I_S_TABLE; default: return TABLE_REF_TMP_TABLE; } } /** Return a table metadata version. * for base tables, we return table_map_id. It is assigned from a global counter incremented for each new table loaded into the table definition cache (TDC). * for temporary tables it's table_map_id again. But for temporary tables table_map_id is assigned from thd->query_id. The latter is assigned from a thread local counter incremented for every new SQL statement. Since temporary tables are thread-local, each temporary table gets a unique id. * for everything else (views, information schema tables), the version id is zero. This choice of version id is a large compromise to have a working prepared statement validation in 5.1. In future version ids will be persistent, as described in WL#4180. Let's try to explain why and how this limited solution allows to validate prepared statements. Firstly, sets (in mathematical sense) of version numbers never intersect for different table types. Therefore, version id of a temporary table is never compared with a version id of a view, and vice versa. Secondly, for base tables, we know that each DDL flushes the respective share from the TDC. This ensures that whenever a table is altered or dropped and recreated, it gets a new version id. Unfortunately, since elements of the TDC are also flushed on LRU basis, this choice of version ids leads to false positives. E.g. when the TDC size is too small, we may have a SELECT * FROM INFORMATION_SCHEMA.TABLES flush all its elements, which in turn will lead to a validation error and a subsequent reprepare of all prepared statements. This is considered acceptable, since as long as prepared statements are automatically reprepared, spurious invalidation is only a performance hit. Besides, no better simple solution exists. For temporary tables, using thd->query_id ensures that if a temporary table was altered or recreated, a new version id is assigned. This suits validation needs very well and will perhaps never change. Metadata of information schema tables never changes. Thus we can safely assume 0 for a good enough version id. Views are a special and tricky case. A view is always inlined into the parse tree of a prepared statement at prepare. Thus, when we execute a prepared statement, the parse tree will not get modified even if the view is replaced with another view. Therefore, we can safely choose 0 for version id of views and effectively never invalidate a prepared statement when a view definition is altered. Note, that this leads to wrong binary log in statement-based replication, since we log prepared statement execution in form Query_log_events containing conventional statements. But since there is no metadata locking for views, the very same problem exists for conventional statements alone, as reported in Bug#25144. The only difference between prepared and conventional execution is, effectively, that for prepared statements the race condition window is much wider. In 6.0 we plan to support view metadata locking (WL#3726) and extend table definition cache to cache views (WL#4298). When this is done, views will be handled in the same fashion as the base tables. Finally, by taking into account table type, we always track that a change has taken place when a view is replaced with a base table, a base table is replaced with a temporary table and so on. @sa TABLE_LIST::is_table_ref_id_equal() */ ulong get_table_ref_version() const { : table_map_id; } bool visit_subgraph(Wait_for_flush *waiting_ticket, MDL_wait_for_graph_visitor *gvisitor); bool wait_for_old_version(THD *thd, struct timespec *abstime, uint deadlock_weight); /** Release resources and free memory occupied by the table share. */ void destroy(); };