diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/mysql_priv.h | 5 | ||||
-rw-r--r-- | sql/net_pkg.cc | 7 | ||||
-rw-r--r-- | sql/net_serv.cc | 3 | ||||
-rw-r--r-- | sql/sql_cache.cc | 223 | ||||
-rw-r--r-- | sql/sql_cache.h | 16 | ||||
-rw-r--r-- | sql/sql_do.cc | 1 | ||||
-rw-r--r-- | sql/sql_parse.cc | 40 |
7 files changed, 174 insertions, 121 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 27dba4d62fd..629f29a343e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -283,8 +283,9 @@ uint cached_tables(void); void kill_mysql(void); void close_connection(NET *net,uint errcode=0,bool lock=1); bool check_access(THD *thd,uint access,const char *db=0,uint *save_priv=0, - bool no_grant=0); -bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables); + bool no_grant=0, bool no_errors=0); +bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables, + bool no_errors=0); bool check_process_priv(THD *thd=0); int mysql_backup_table(THD* thd, TABLE_LIST* table_list); diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc index 9fb478ca664..2f26ad81bd5 100644 --- a/sql/net_pkg.cc +++ b/sql/net_pkg.cc @@ -30,6 +30,7 @@ void send_error(NET *net, uint sql_errno, const char *err) err ? err : net->last_error[0] ? net->last_error : "NULL")); + query_cache_abort(net); if (thd) thd->query_error = 1; // needed to catch query errors during replication if (!err) @@ -102,9 +103,9 @@ net_printf(NET *net, uint errcode, ...) DBUG_ENTER("net_printf"); DBUG_PRINT("enter",("message: %u",errcode)); - if(thd) thd->query_error = 1; - // if we are here, something is wrong :-) - + if (thd) + thd->query_error = 1; // if we are here, something is wrong :-) + query_cache_abort(net); // Safety va_start(args,errcode); format=ER(errcode); offset= net->return_errno ? 2 : 0; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 666c572ccee..3e4dcb75ebb 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -330,7 +330,8 @@ net_real_write(NET *net,const char *packet,ulong len) DBUG_ENTER("net_real_write"); #ifdef MYSQL_SERVER - query_cache_insert(net, packet, len); + if (net->query_cache_query != 0) + query_cache_insert(net, packet, len); #endif if (net->error == 2) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 5051c9b775b..3486ccc18c5 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB 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 @@ -530,9 +530,14 @@ byte *query_cache_query_get_key(const byte *record, uint *length, } /***************************************************************************** - Functions to store things into the query cache + Functions to store things into the query cache *****************************************************************************/ +/* + Insert the packet into the query cache. + This should only be called if net->query_cache_query != 0 +*/ + void query_cache_insert(NET *net, const char *packet, ulong length) { DBUG_ENTER("query_cache_insert"); @@ -543,45 +548,41 @@ void query_cache_insert(NET *net, const char *packet, ulong length) DBUG_VOID_RETURN; #endif - // Quick check on unlocked structure - if (net->query_cache_query != 0) + STRUCT_LOCK(&query_cache.structure_guard_mutex); + Query_cache_block *query_block = ((Query_cache_block*) + net->query_cache_query); + if (query_block) { - STRUCT_LOCK(&query_cache.structure_guard_mutex); - Query_cache_block *query_block = ((Query_cache_block*) - net->query_cache_query); - if (query_block) - { - Query_cache_query *header = query_block->query(); - Query_cache_block *result = header->result(); + Query_cache_query *header = query_block->query(); + Query_cache_block *result = header->result(); - DUMP(&query_cache); - BLOCK_LOCK_WR(query_block); - DBUG_PRINT("qcache", ("insert packet %lu bytes long",length)); + DUMP(&query_cache); + BLOCK_LOCK_WR(query_block); + DBUG_PRINT("qcache", ("insert packet %lu bytes long",length)); - /* - On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be - done by query_cache.append_result_data if success (if not we need - query_cache.structure_guard_mutex locked to free query) - */ - if (!query_cache.append_result_data(&result, length, (gptr) packet, - query_block)) - { - query_cache.refused++; - DBUG_PRINT("warning", ("Can't append data")); - header->result(result); - DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block)); - // The following call will remove the lock on query_block - query_cache.free_query(query_block); - // append_result_data no success => we need unlock - STRUCT_UNLOCK(&query_cache.structure_guard_mutex); - DBUG_VOID_RETURN; - } + /* + On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be + done by query_cache.append_result_data if success (if not we need + query_cache.structure_guard_mutex locked to free query) + */ + if (!query_cache.append_result_data(&result, length, (gptr) packet, + query_block)) + { + query_cache.refused++; + DBUG_PRINT("warning", ("Can't append data")); header->result(result); - BLOCK_UNLOCK_WR(query_block); - } - else + DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block)); + // The following call will remove the lock on query_block + query_cache.free_query(query_block); + // append_result_data no success => we need unlock STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_VOID_RETURN; + } + header->result(result); + BLOCK_UNLOCK_WR(query_block); } + else + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); DBUG_EXECUTE("check_querycache",query_cache.check_integrity();); DBUG_VOID_RETURN; } @@ -607,11 +608,11 @@ void query_cache_abort(NET *net) BLOCK_LOCK_WR(query_block); // The following call will remove the lock on query_block query_cache.free_query(query_block); - net->query_cache_query=0; } + net->query_cache_query=0; STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_EXECUTE("check_querycache",query_cache.check_integrity();); } - DBUG_EXECUTE("check_querycache",query_cache.check_integrity();); DBUG_VOID_RETURN; } @@ -648,7 +649,6 @@ void query_cache_end_of_result(NET *net) #endif header->found_rows(current_thd->limit_found_rows); header->result()->type = Query_cache_block::RESULT; - net->query_cache_query=0; header->writer(0); BLOCK_UNLOCK_WR(query_block); } @@ -658,8 +658,8 @@ void query_cache_end_of_result(NET *net) STRUCT_UNLOCK(&query_cache.structure_guard_mutex); } net->query_cache_query=0; + DBUG_EXECUTE("check_querycache",query_cache.check_integrity();); } - DBUG_EXECUTE("check_querycache",query_cache.check_integrity();); DBUG_VOID_RETURN; } @@ -724,6 +724,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) (Not important at this stage) */ TABLE_COUNTER_TYPE tables; + ulong tot_length; DBUG_ENTER("Query_cache::store_query"); if (query_cache_size == 0) DBUG_VOID_RETURN; @@ -739,6 +740,17 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) DBUG_VOID_RETURN; DUMP(this); + /* Key is query + database + flag */ + if (thd->db_length) + { + memcpy(thd->query+thd->query_length, thd->db, thd->db_length); + DBUG_PRINT("qcache", ("database : %s length %u", + thd->db, thd->db_length)); + } + else + { + DBUG_PRINT("qcache", ("No active database")); + } /* Prepare flags: most significant bit - CLIENT_LONG_FLAG, @@ -749,32 +761,19 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) flags|= (byte) thd->convert_set->number(); DBUG_ASSERT(thd->convert_set->number() < 128); } + tot_length=thd->query_length+1+thd->db_length; + thd->query[tot_length-1] = (char) flags; /* Check if another thread is processing the same query? */ - thd->query[thd->query_length] = (char) flags; - if (thd->db_length) - { - memcpy(thd->query+thd->query_length+1, thd->db, thd->db_length); - DBUG_PRINT("qcache", ("database : %s length %u", - thd->db, thd->db_length)); - } - else - { - DBUG_PRINT("qcache", ("No active database")); - } - Query_cache_block *competitor = (Query_cache_block *) - hash_search(&queries, (byte*) thd->query, - thd->query_length+1+thd->db_length); + hash_search(&queries, (byte*) thd->query, tot_length); DBUG_PRINT("qcache", ("competitor 0x%lx, flags %x", (ulong) competitor, flags)); if (competitor == 0) { /* Query is not in cache and no one is working with it; Store it */ - thd->query[thd->query_length] = (char) flags; Query_cache_block *query_block; - query_block= write_block_data(thd->query_length+1+thd->db_length, - (gptr) thd->query, + query_block= write_block_data(tot_length, (gptr) thd->query, ALIGN_SIZE(sizeof(Query_cache_query)), Query_cache_block::QUERY, tables, 1); if (query_block != 0) @@ -801,7 +800,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) header->unlock_n_destroy(); free_memory_block(query_block); STRUCT_UNLOCK(&structure_guard_mutex); - DBUG_VOID_RETURN; + goto end; } double_linked_list_simple_include(query_block, &queries_blocks); inserts++; @@ -837,13 +836,26 @@ end: DBUG_VOID_RETURN; } +/* + Check if the query is in the cache. If it was cached, send it + to the user. + + RESULTS + 1 Query was not cached. + 0 The query was cached and user was sent the result. + -1 The query was cached but we didn't have rights to use it. + No error is sent to the client yet. +*/ + + -my_bool +int Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) { Query_cache_query *query; Query_cache_block *first_result_block, *result_block; Query_cache_block_table *block_table, *block_table_end; + ulong tot_length; byte flags; DBUG_ENTER("Query_cache::send_result_to_client"); @@ -856,9 +868,13 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) thd->query_cache_type == 0) { - DBUG_PRINT("qcache", ("query cache disabled on not in autocommit mode")); + DBUG_PRINT("qcache", ("query cache disabled or not in autocommit mode")); goto err; } + + /* Check that we haven't forgot to reset the query cache variables */ + DBUG_ASSERT(thd->net.query_cache_query == 0); + /* We can't cache the query if we are using a temporary table because we don't know if the query is using a temporary table. @@ -868,7 +884,9 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) */ if (thd->temporary_tables != 0 || !thd->safe_to_cache_query) { - DBUG_PRINT("qcache", ("SELECT is non-cacheable")); + DBUG_PRINT("qcache", ("SELECT is non-cacheable: tmp_tables: %d safe: %d", + thd->temporary_tables, + thd->safe_to_cache_query)); goto err; } @@ -888,13 +906,22 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size == 0) { - DBUG_PRINT("qcache", ("query cache disabled and not in autocommit mode")); - STRUCT_UNLOCK(&structure_guard_mutex); - goto err; + DBUG_PRINT("qcache", ("query cache disabled")); + goto err_unlock; } - DBUG_PRINT("qcache", (" sql %u '%s'", query_length, sql)); Query_cache_block *query_block; + tot_length=query_length+thd->db_length+1; + if (thd->db_length) + { + memcpy(sql+query_length, thd->db, thd->db_length); + DBUG_PRINT("qcache", ("database: '%s' length %u", + thd->db, thd->db_length)); + } + else + { + DBUG_PRINT("qcache", ("No active database")); + } /* prepare flags: Most significant bit - CLIENT_LONG_FLAG, @@ -906,31 +933,19 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) flags |= (byte) thd->convert_set->number(); DBUG_ASSERT(thd->convert_set->number() < 128); } - sql[query_length] = (char) flags; - if (thd->db_length) - { - memcpy(sql+query_length+1, thd->db, thd->db_length); - DBUG_PRINT("qcache", ("database : %s length %u", - thd->db, thd->db_length)); - } - else - { - DBUG_PRINT("qcache", ("No active database")); - } + sql[tot_length-1] = (char) flags; query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql, - query_length+1+ - thd->db_length); + tot_length); - sql[query_length] = '\0'; + sql[query_length] = '\0'; // Restore end null /* Quick abort on unlocked data */ if (query_block == 0 || query_block->query()->result() == 0 || query_block->query()->result()->type != Query_cache_block::RESULT) { - STRUCT_UNLOCK(&structure_guard_mutex); DBUG_PRINT("qcache", ("No query in query hash or no results")); - goto err; + goto err_unlock; } DBUG_PRINT("qcache", ("Query in query hash 0x%lx", (ulong)query_block)); @@ -945,7 +960,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) /* The query is probably yet processed */ DBUG_PRINT("qcache", ("query found, but no data or data incomplete")); BLOCK_UNLOCK_RD(query_block); - goto err; + goto err_unlock; } DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query)); @@ -960,14 +975,24 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Query_cache_table *table = block_table->parent; table_list.db = table->db(); table_list.name = table_list.real_name = table->table(); - if (check_table_access(thd,SELECT_ACL,&table_list)) + if (check_table_access(thd,SELECT_ACL,&table_list,1)) { DBUG_PRINT("qcache", ("probably no SELECT access to %s.%s => return to normal processing", table_list.db, table_list.name)); - BLOCK_UNLOCK_RD(query_block); + refused++; // This is actually a hit STRUCT_UNLOCK(&structure_guard_mutex); - goto err; + thd->safe_to_cache_query=0; // Don't try to cache this + BLOCK_UNLOCK_RD(query_block); + DBUG_RETURN(-1); // Privilege error + } + if (table_list.grant.want_privilege) + { + DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s", + table_list.db, table_list.name)); + BLOCK_UNLOCK_RD(query_block); + thd->safe_to_cache_query=0; // Don't try to cache this + goto err_unlock; // Parse query } } move_to_query_list_end(query_block); @@ -996,10 +1021,12 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) thd->limit_found_rows = query->found_rows(); BLOCK_UNLOCK_RD(query_block); - DBUG_RETURN(0); + DBUG_RETURN(1); // Result sent to client +err_unlock: + STRUCT_UNLOCK(&structure_guard_mutex); err: - DBUG_RETURN(1); + DBUG_RETURN(0); // Query was not cached } /* @@ -2307,7 +2334,7 @@ void Query_cache::double_linked_list_join(Query_cache_block *head_tail, *****************************************************************************/ /* - if query is cacheable return number tables in query + If query is cacheable return number tables in query (query without tables are not cached) */ @@ -2554,10 +2581,12 @@ my_bool Query_cache::move_by_type(byte **border, Query_cache_query *new_query= ((Query_cache_query *) new_block->data()); pthread_cond_init(&new_query->lock, NULL); pthread_mutex_init(&new_query->clients_guard,MY_MUTEX_INIT_FAST); + NET *net = new_block->query()->writer(); + /* QQ: When could this happen ? */ if (net != 0) { - net->query_cache_query = (gptr) new_block; + net->query_cache_query= (gptr) new_block; } /* Fix hash to point at moved block */ hash_replace(&queries, queries.current_record, (byte*) new_block); @@ -2747,7 +2776,19 @@ uint Query_cache::filename_2_table_key (char *key, const char *path) Functions to be used when debugging ****************************************************************************/ -#ifndef DBUG_OFF +#if defined(DBUG_OFF) && !defined(USE_QUERY_CACHE_INTEGRITY_CHECK) + +void wreck(uint line, const char *message) {} +void bins_dump() {} +void cache_dump() {} +void queries_dump() {} +void tables_dump() {} +my_bool check_integrity() {} +my_bool in_list(Query_cache_block * root, Query_cache_block * point, + const char *name) { return 0;} +my_bool in_blocks(Query_cache_block * point) { return 0; } + +#else void Query_cache::wreck(uint line, const char *message) { @@ -2836,10 +2877,10 @@ void Query_cache::queries_dump() { uint len; char *str = (char*) query_cache_query_get_key((byte*) block, &len, 0); - byte flags = (byte) str[len-1]; + uint flags = (uint) (uchar) str[len-1]; DBUG_PRINT("qcache", ("%u (%u,%u) %.*s",len, ((flags & QUERY_CACHE_CLIENT_LONG_FLAG_MASK)? 1:0), - (flags & QUERY_CACHE_CHARSET_CONVERT_MASK), len, + (flags & QUERY_CACHE_CHARSET_CONVERT_MASK), len-1, str)); DBUG_PRINT("qcache", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong) block, (ulong) block->next, (ulong) block->prev, diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 6f8d9bb6dbf..50ae765e446 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -354,7 +354,7 @@ protected: Check if the query is in the cache and if this is true send the data to client. */ - my_bool send_result_to_client(THD *thd, char *query, uint query_length); + int send_result_to_client(THD *thd, char *query, uint query_length); /* Remove all queries that uses any of the listed following tables */ void invalidate(TABLE_LIST *tables_used); @@ -375,7 +375,15 @@ protected: void destroy(); -#ifndef DBUG_OFF + friend void query_cache_insert(NET *net, const char *packet, ulong length); + friend void query_cache_end_of_result(NET *net); + friend void query_cache_abort(NET *net); + + /* + The following functions are only used when debugging + We don't protect these with ifndef DEBUG_OFF to not have to recompile + everything if we want to add checks of the cache at some places. + */ void wreck(uint line, const char *message); void bins_dump(); void cache_dump(); @@ -385,10 +393,6 @@ protected: my_bool in_list(Query_cache_block * root, Query_cache_block * point, const char *name); my_bool in_blocks(Query_cache_block * point); -#endif - friend void query_cache_insert(NET *net, const char *packet, ulong length); - friend void query_cache_end_of_result(NET *net); - friend void query_cache_abort(NET *net); }; extern Query_cache query_cache; diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 77be253766c..70124c2d796 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -22,7 +22,6 @@ int mysql_do(THD *thd, List<Item> &values) { - int error; List_iterator<Item> li(values); Item *value; DBUG_ENTER("mysql_do"); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e61bb83ee29..af6bd07cdc5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -842,7 +842,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { char *pos=packet-1+packet_length; // Point at end null /* Remove garage at end of query */ - while (packet_length > 0 && pos[-1] == ';') + while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1]))) { pos--; packet_length--; @@ -2261,7 +2261,7 @@ error: bool check_access(THD *thd,uint want_access,const char *db, uint *save_priv, - bool dont_check_global_grants) + bool dont_check_global_grants, bool no_errors) { uint db_access,dummy; if (save_priv) @@ -2271,7 +2271,8 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv, if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */ + if (!no_errors) + send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */ return TRUE; /* purecov: tested */ } @@ -2283,10 +2284,11 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv, if ((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL) || ! db && dont_check_global_grants) { // We can never grant this - net_printf(&thd->net,ER_ACCESS_DENIED_ERROR, - thd->priv_user, - thd->host_or_ip, - thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */ + if (!no_errors) + net_printf(&thd->net,ER_ACCESS_DENIED_ERROR, + thd->priv_user, + thd->host_or_ip, + thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */ return TRUE; /* purecov: tested */ } @@ -2306,10 +2308,11 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv, ((grant_option && !dont_check_global_grants) && !(want_access & ~TABLE_ACLS))) return FALSE; /* Ok */ - net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, - thd->priv_user, - thd->host_or_ip, - db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */ + if (!no_errors) + net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, + thd->priv_user, + thd->host_or_ip, + db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */ return TRUE; /* purecov: tested */ } @@ -2326,7 +2329,8 @@ bool check_process_priv(THD *thd) */ bool -check_table_access(THD *thd,uint want_access,TABLE_LIST *tables) +check_table_access(THD *thd,uint want_access,TABLE_LIST *tables, + bool no_errors) { uint found=0,found_access=0; TABLE_LIST *org_tables=tables; @@ -2341,18 +2345,20 @@ check_table_access(THD *thd,uint want_access,TABLE_LIST *tables) tables->grant.privilege=found_access; else { - if (check_access(thd,want_access,tables->db,&tables->grant.privilege)) + if (check_access(thd,want_access,tables->db,&tables->grant.privilege, + 0, no_errors)) return TRUE; // Access denied found_access=tables->grant.privilege; found=1; } } - else if (check_access(thd,want_access,tables->db,&tables->grant.privilege)) + else if (check_access(thd,want_access,tables->db,&tables->grant.privilege, + 0, no_errors)) return TRUE; // Access denied } if (grant_option) return check_grant(thd,want_access & ~EXTRA_ACL,org_tables, - test(want_access & EXTRA_ACL)); + test(want_access & EXTRA_ACL), no_errors); return FALSE; } @@ -2474,6 +2480,7 @@ mysql_init_query(THD *thd) thd->fatal_error=0; // Safety thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0; thd->sent_row_count=thd->examined_row_count=0; + thd->safe_to_cache_query=1; DBUG_VOID_RETURN; } @@ -2522,9 +2529,8 @@ mysql_parse(THD *thd,char *inBuf,uint length) mysql_init_query(thd); thd->query_length = length; - if (query_cache.send_result_to_client(thd, inBuf, length)) + if (query_cache.send_result_to_client(thd, inBuf, length) <= 0) { - thd->safe_to_cache_query=1; LEX *lex=lex_start(thd, (uchar*) inBuf, length); if (!yyparse() && ! thd->fatal_error) { |