diff --git a/mysql-test/r/innodb_cache.result b/mysql-test/r/innodb_cache.result index 7d351a13e16..04540bebd1a 100644 --- a/mysql-test/r/innodb_cache.result +++ b/mysql-test/r/innodb_cache.result @@ -10,7 +10,7 @@ a 3 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 drop table t1; commit; set autocommit=1; @@ -24,7 +24,7 @@ a 3 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 0 +Qcache_queries_in_cache 1 drop table t1; commit; create table t1 (a int not null) type=innodb; @@ -97,7 +97,7 @@ Qcache_hits 0 commit; show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 1 +Qcache_queries_in_cache 3 drop table if exists t1; CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) TYPE=InnoDB; select count(*) from t1; diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index dd42e7ab9e2..f1669e9b6c7 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -166,6 +166,7 @@ class ha_berkeley: public handler } longlong get_auto_increment(); void print_error(int error, myf errflag); + uint8 table_cache_type() { return HA_CACHE_TBL_TRANSACT; } }; extern bool berkeley_skip, berkeley_shared_data; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index a037c6989aa..16f39ab2170 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -462,7 +462,7 @@ If thd is not in the autocommit state, this function also starts a new transaction for thd if there is no active trx yet, and assigns a consistent read view to it if there is no read view yet. */ -my_bool +bool innobase_query_caching_of_table_permitted( /*======================================*/ /* out: TRUE if permitted, FALSE if not; diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 86fb5d1947b..7022bed12e9 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -168,6 +168,7 @@ class ha_innobase: public handler enum thr_lock_type lock_type); void init_table_handle_for_HANDLER(); longlong get_auto_increment(); + uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; } }; extern bool innodb_skip; @@ -207,5 +208,5 @@ int innobase_close_connection(THD *thd); int innobase_drop_database(char *path); int innodb_show_status(THD* thd); -my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name, - uint full_name_len); +bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name, + uint full_name_len); diff --git a/sql/handler.cc b/sql/handler.cc index dcc732ba25a..734b0e3ccf6 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -839,6 +839,16 @@ int handler::delete_all_rows() return (my_errno=HA_ERR_WRONG_COMMAND); } +bool handler::caching_allowed(THD* thd, char* table_key, + uint key_length, uint8 cache_type) +{ + if (cache_type == HA_CACHE_TBL_ASKTRANSACT) + return innobase_query_caching_of_table_permitted(thd, table_key, + key_length); + else + return 1; +} + /**************************************************************************** ** Some general functions that isn't in the handler class ****************************************************************************/ diff --git a/sql/handler.h b/sql/handler.h index 6cbd83af282..3aaa1c6c1e1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -116,6 +116,11 @@ #define HA_OPTION_NO_DELAY_KEY_WRITE (1L << 18) #define HA_MAX_REC_LENGTH 65535 +/* Table caching type */ +#define HA_CACHE_TBL_NONTRANSACT 0 +#define HA_CACHE_TBL_ASKTRANSACT 1 +#define HA_CACHE_TBL_TRANSACT 2 + enum db_type { DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1, DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM, DB_TYPE_RMS_ISAM, DB_TYPE_HEAP, DB_TYPE_ISAM, @@ -342,6 +347,16 @@ public: virtual THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type)=0; + + /* Type of table for caching query */ + virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; } + /* + Is query with this cable cachable (have sense only for ASKTRANSACT + tables) + */ + static bool caching_allowed(THD* thd, char* table_key, + uint key_length, uint8 cahe_type); + }; /* Some extern variables used with handlers */ diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 90fd61ebeb7..fcff8c13beb 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -750,9 +750,11 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) DBUG_ENTER("Query_cache::store_query"); if (query_cache_size == 0) DBUG_VOID_RETURN; + uint8 tables_type= 0; if ((local_tables = is_cacheable(thd, thd->query_length, - thd->query, &thd->lex, tables_used))) + thd->query, &thd->lex, tables_used, + &tables_type))) { NET *net= &thd->net; byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); @@ -831,6 +833,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) net->query_cache_query= (gptr) query_block; header->writer(net); + header->tables_type(tables_type); // init_n_lock make query block locked BLOCK_UNLOCK_WR(query_block); } @@ -877,15 +880,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Query_cache_block_table *block_table, *block_table_end; ulong tot_length; byte flags; + bool check_tables; DBUG_ENTER("Query_cache::send_result_to_client"); - if (query_cache_size == 0 || - /* - it is not possible to check has_transactions() function of handler - because tables not opened yet - */ - (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) || - thd->variables.query_cache_type == 0) + if (query_cache_size == 0 || thd->variables.query_cache_type == 0) goto err; @@ -968,6 +966,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) } DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query)); + check_tables= query->tables_type() & HA_CACHE_TBL_ASKTRANSACT; // Check access; block_table= query_block->table(0); block_table_end= block_table+query_block->n_tables; @@ -995,9 +994,22 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s", table_list.db, table_list.alias)); BLOCK_UNLOCK_RD(query_block); - thd->lex.safe_to_cache_query=0; // Don't try to cache this + thd->lex.safe_to_cache_query= 0; // Don't try to cache this goto err_unlock; // Parse query } + if (check_tables && !handler::caching_allowed(thd, table->db(), + table->key_length(), + table->type())) + { + DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s", + table_list.db, table_list.alias)); + BLOCK_UNLOCK_RD(query_block); + thd->lex.safe_to_cache_query= 0; // Don't try to cache this + goto err_unlock; // Parse query + } + else + DBUG_PRINT("qcache", ("handler allow caching (%d) %s,%s", + check_tables, table_list.db, table_list.alias)); } move_to_query_list_end(query_block); hits++; @@ -1059,7 +1071,8 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used, if (tables_used->derived) continue; if (using_transactions && - tables_used->table->file->has_transactions()) + (tables_used->table->file->table_cache_type() == + HA_CACHE_TBL_TRANSACT)) /* Tables_used->table can't be 0 in transaction. Only 'drop' invalidate not opened table, but 'drop' @@ -1113,7 +1126,8 @@ void Query_cache::invalidate(THD *thd, TABLE *table, { using_transactions = using_transactions && (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)); - if (using_transactions && table->file->has_transactions()) + if (using_transactions && + (table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT)) thd->add_changed_table(table); else invalidate_table(table); @@ -1932,7 +1946,8 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, block_table->n=n; if (!insert_table(tables_used->table->key_length, tables_used->table->table_cache_key, block_table, - tables_used->db_length)) + tables_used->db_length, + tables_used->table->file->table_cache_type())) break; if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM) @@ -1945,11 +1960,12 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, { char key[MAX_DBKEY_LENGTH]; uint32 db_length; - uint key_length =filename_2_table_key(key, table->table->filename, + uint key_length= filename_2_table_key(key, table->table->filename, &db_length); (++block_table)->n= ++n; if (!insert_table(key_length, key, block_table, - db_length)) + db_length, + tables_used->table->file->table_cache_type())) goto err; } } @@ -1976,7 +1992,7 @@ err: my_bool Query_cache::insert_table(uint key_len, char *key, Query_cache_block_table *node, - uint32 db_length) + uint32 db_length, uint8 cache_type) { DBUG_ENTER("Query_cache::insert_table"); DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d", @@ -2014,6 +2030,8 @@ Query_cache::insert_table(uint key_len, char *key, } char *db = header->db(); header->table(db + db_length + 1); + header->key_length(key_len); + header->type(cache_type); } Query_cache_block_table *list_root = table_block->table(0); @@ -2444,7 +2462,9 @@ void Query_cache::double_linked_list_join(Query_cache_block *head_tail, TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, - LEX *lex, TABLE_LIST *tables_used) + LEX *lex, + TABLE_LIST *tables_used, + uint8 *tables_type) { TABLE_COUNTER_TYPE table_count = 0; DBUG_ENTER("Query_cache::is_cacheable"); @@ -2455,7 +2475,6 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, OPTION_TO_QUERY_CACHE))) && lex->safe_to_cache_query) { - my_bool has_transactions = 0; DBUG_PRINT("qcache", ("options %lx %lx, type %u", OPTION_TO_QUERY_CACHE, lex->select_lex.options, @@ -2467,8 +2486,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, DBUG_PRINT("qcache", ("table %s, db %s, type %u", tables_used->real_name, tables_used->db, tables_used->table->db_type)); - has_transactions = (has_transactions || - tables_used->table->file->has_transactions()); + *tables_type|= tables_used->table->file->table_cache_type(); if (tables_used->table->db_type == DB_TYPE_MRG_ISAM || tables_used->table->tmp_table != NO_TMP_TABLE || @@ -2500,7 +2518,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, } if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && - has_transactions) + ((*tables_type)&HA_CACHE_TBL_TRANSACT)) { DBUG_PRINT("qcache", ("not in autocommin mode")); DBUG_RETURN(0); @@ -2941,7 +2959,7 @@ void Query_cache::bins_dump() { uint i; - if (!initialized) + if (!initialized || query_cache_size == 0) { DBUG_PRINT("qcache", ("Query Cache not initialized")); return; @@ -2982,7 +3000,7 @@ void Query_cache::bins_dump() void Query_cache::cache_dump() { - if (!initialized) + if (!initialized || query_cache_size == 0) { DBUG_PRINT("qcache", ("Query Cache not initialized")); return; @@ -3071,7 +3089,7 @@ void Query_cache::queries_dump() void Query_cache::tables_dump() { - if (!initialized) + if (!initialized || query_cache_size == 0) { DBUG_PRINT("qcache", ("Query Cache not initialized")); return; diff --git a/sql/sql_cache.h b/sql/sql_cache.h index b15df28f54b..9cf8977ee79 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -115,18 +115,21 @@ struct Query_cache_query Query_cache_block *res; NET *wri; ulong len; + uint8 tbls_type; inline void init_n_lock(); void unlock_n_destroy(); inline ulonglong found_rows() { return limit_found_rows; } - inline void found_rows(ulonglong rows) { limit_found_rows = rows; } + inline void found_rows(ulonglong rows) { limit_found_rows= rows; } inline Query_cache_block *result() { return res; } - inline void result(Query_cache_block *p) { res=p; } + inline void result(Query_cache_block *p) { res= p; } inline NET *writer() { return wri; } - inline void writer(NET *p) { wri=p; } + inline void writer(NET *p) { wri= p; } + inline uint8 tables_type() { return tbls_type; } + inline void tables_type(uint8 type) { tbls_type= type; } inline ulong length() { return len; } - inline ulong add(ulong packet_len) { return(len += packet_len); } - inline void length(ulong length) { len = length; } + inline ulong add(ulong packet_len) { return(len+= packet_len); } + inline void length(ulong length) { len= length; } inline gptr query() { return (gptr)(((byte*)this)+ @@ -144,10 +147,16 @@ struct Query_cache_query struct Query_cache_table { char *tbl; + uint key_len; + uint8 table_type; inline char *db() { return (char *) data(); } inline char *table() { return tbl; } - inline void table(char *table) { tbl = table; } + inline void table(char *table) { tbl= table; } + inline uint key_length() { return key_len; } + inline void key_length(uint len) { key_len= len; } + inline uint8 type() { return table_type; } + inline void type(uint8 t) { table_type= t; } inline gptr data() { return (gptr)(((byte*)this)+ @@ -276,7 +285,7 @@ protected: TABLE_COUNTER_TYPE tables); my_bool insert_table(uint key_len, char *key, Query_cache_block_table *node, - uint32 db_length); + uint32 db_length, uint8 cache_type); void unlink_table(Query_cache_block_table *node); Query_cache_block *get_free_block (ulong len, my_bool not_less, ulong min); @@ -334,7 +343,8 @@ protected: (query without tables not cached) */ TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query, - LEX *lex, TABLE_LIST *tables_used); + LEX *lex, TABLE_LIST *tables_used, + uint8 *tables_type); public: Query_cache(ulong query_cache_limit = ULONG_MAX,