summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <df@pippilotta.erinye.com>2007-08-23 17:43:47 +0200
committerunknown <df@pippilotta.erinye.com>2007-08-23 17:43:47 +0200
commit0ff829bb7162a12845ab25282b3e2677eac89ba1 (patch)
tree639c7e3e6dd6a4ca28c50d13b8772122ec22554f
parente4659ee132456837fda9c23d07788ba9b47b7781 (diff)
parent3dbffd24c84cf2011489063482f89cdeab54a0d7 (diff)
downloadmariadb-git-0ff829bb7162a12845ab25282b3e2677eac89ba1.tar.gz
Merge pippilotta.erinye.com:/shared/home/df/mysql/build/mysql-5.0-marvel
into pippilotta.erinye.com:/shared/home/df/mysql/build/mysql-5.0.48 sql/sql_base.cc: Auto merged sql/sql_cache.cc: Auto merged
-rw-r--r--include/my_pthread.h32
-rw-r--r--mysql-test/r/handler.result7
-rw-r--r--mysql-test/r/query_cache.result29
-rw-r--r--mysql-test/r/query_cache_with_views.result (renamed from mysql-test/r/view_query_cache.result)0
-rw-r--r--mysql-test/t/handler.test14
-rw-r--r--mysql-test/t/query_cache.test33
-rw-r--r--mysql-test/t/query_cache_with_views.test (renamed from mysql-test/t/view_query_cache.test)0
-rw-r--r--mysys/my_thr_init.c17
-rw-r--r--sql/lock.cc1
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/sql_base.cc9
-rw-r--r--sql/sql_cache.cc35
-rw-r--r--sql/sql_cache.h8
-rw-r--r--sql/sql_handler.cc80
14 files changed, 191 insertions, 76 deletions
diff --git a/include/my_pthread.h b/include/my_pthread.h
index d64b5348666..1cedbbc4fd0 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -30,25 +30,6 @@ extern "C" {
#define EXTERNC
#endif /* __cplusplus */
-/*
- BUG#24507: Race conditions inside current NPTL pthread_exit() implementation.
-
- If macro NPTL_PTHREAD_EXIT_HACK is defined then a hack described in the bug
- report will be implemented inside my_thread_global_init() in my_thr_init.c.
-
- This amounts to spawning a dummy thread which does nothing but executes
- pthread_exit(0).
-
- This bug is fixed in version 2.5 of glibc library.
-
- TODO: Remove this code when fixed versions of glibc6 are in common use.
- */
-
-#if defined(TARGET_OS_LINUX) && defined(HAVE_NPTL) && \
- defined(__GLIBC__) && ( __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 5 )
-#define NPTL_PTHREAD_EXIT_BUG 1
-#endif
-
#if defined(__WIN__) || defined(OS2)
#ifdef OS2
@@ -199,7 +180,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *);
#define pthread_mutex_unlock(A) LeaveCriticalSection(A)
#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
#define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B))
-#define pthread_kill(A,B) pthread_dummy(0)
+#define pthread_kill(A,B) pthread_dummy(ESRCH)
#endif /* OS2 */
/* Dummy defines for easier code */
@@ -463,14 +444,14 @@ struct tm *gmtime_r(const time_t *clock, struct tm *res);
#define pthread_attr_setdetachstate(A,B) pthread_dummy(0)
#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D))
#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C))
-#define pthread_kill(A,B) pthread_dummy(0)
+#define pthread_kill(A,B) pthread_dummy(ESRCH)
#undef pthread_detach_this_thread
#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); }
#endif
#ifdef HAVE_DARWIN5_THREADS
#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C))
-#define pthread_kill(A,B) pthread_dummy(0)
+#define pthread_kill(A,B) pthread_dummy(ESRCH)
#define pthread_condattr_init(A) pthread_dummy(0)
#define pthread_condattr_destroy(A) pthread_dummy(0)
#undef pthread_detach_this_thread
@@ -490,7 +471,7 @@ struct tm *gmtime_r(const time_t *clock, struct tm *res);
#ifndef pthread_sigmask
#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C))
#endif
-#define pthread_kill(A,B) pthread_dummy(0)
+#define pthread_kill(A,B) pthread_dummy(ESRCH)
#undef pthread_detach_this_thread
#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); }
#elif !defined(__NETWARE__) /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */
@@ -717,6 +698,11 @@ extern pthread_mutexattr_t my_errorcheck_mutexattr;
#define MY_MUTEX_INIT_ERRCHK NULL
#endif
+#ifndef ESRCH
+/* Define it to something */
+#define ESRCH 1
+#endif
+
extern my_bool my_thread_global_init(void);
extern void my_thread_global_end(void);
extern my_bool my_thread_init(void);
diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result
index 85cf47b5806..5e123df9103 100644
--- a/mysql-test/r/handler.result
+++ b/mysql-test/r/handler.result
@@ -482,3 +482,10 @@ ERROR 42S02: Table 'test.t1' doesn't exist
drop table if exists t1;
Warnings:
Note 1051 Unknown table 't1'
+drop table if exists t1;
+create table t1 (a int) ENGINE=MEMORY;
+--> client 2
+handler t1 open;
+ERROR HY000: Table storage engine for 't1' doesn't have this option
+--> client 1
+drop table t1;
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index 25c6d58dee2..68f18d1b0b2 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -1621,6 +1621,35 @@ a (select count(*) from t2)
3 0
4 0
drop table t1,t2;
+DROP DATABASE IF EXISTS bug30269;
+FLUSH STATUS;
+CREATE DATABASE bug30269;
+USE bug30269;
+CREATE TABLE test1 (id int, name varchar(23));
+CREATE VIEW view1 AS SELECT * FROM test1;
+INSERT INTO test1 VALUES (5, 'testit');
+GRANT SELECT (id) ON TABLE bug30269.test1 TO 'bug30269'@'localhost';
+GRANT SELECT ON TABLE bug30269.view1 TO 'bug30269'@'localhost';
+set global query_cache_size= 81920;
+USE bug30269;
+show status like 'Qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 0
+# Select statement not stored in query cache because of column privileges.
+SELECT id FROM test1 WHERE id>2;
+id
+5
+show status like 'Qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 0
+SELECT id FROM view1 WHERE id>2;
+id
+5
+show status like 'Qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 1
+DROP DATABASE bug30269;
+DROP USER 'bug30269'@'localhost';
set GLOBAL query_cache_type=default;
set GLOBAL query_cache_limit=default;
set GLOBAL query_cache_min_res_unit=default;
diff --git a/mysql-test/r/view_query_cache.result b/mysql-test/r/query_cache_with_views.result
index 03430bd504b..03430bd504b 100644
--- a/mysql-test/r/view_query_cache.result
+++ b/mysql-test/r/query_cache_with_views.result
diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test
index bf18b8da941..4edd5b5ec32 100644
--- a/mysql-test/t/handler.test
+++ b/mysql-test/t/handler.test
@@ -427,3 +427,17 @@ select * from t1;
# Just to be sure and not confuse the next test case writer.
drop table if exists t1;
+#
+# Bug#25856 - HANDLER table OPEN in one connection lock DROP TABLE in another one
+#
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a int) ENGINE=MEMORY;
+--echo --> client 2
+connection con2;
+--error 1031
+handler t1 open;
+--echo --> client 1
+connection default;
+drop table t1;
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
index 3091284d061..44b63df9739 100644
--- a/mysql-test/t/query_cache.test
+++ b/mysql-test/t/query_cache.test
@@ -1220,9 +1220,40 @@ connection default;
disconnect user1;
disconnect user2;
disconnect user3;
+
+#
+# Bug #30269 Query cache eats memory
+#
+--disable_warnings
+DROP DATABASE IF EXISTS bug30269;
+--enable_warnings
+FLUSH STATUS;
+CREATE DATABASE bug30269;
+USE bug30269;
+CREATE TABLE test1 (id int, name varchar(23));
+CREATE VIEW view1 AS SELECT * FROM test1;
+INSERT INTO test1 VALUES (5, 'testit');
+GRANT SELECT (id) ON TABLE bug30269.test1 TO 'bug30269'@'localhost';
+GRANT SELECT ON TABLE bug30269.view1 TO 'bug30269'@'localhost';
+set global query_cache_size= 81920;
+connect (bug30269, localhost, bug30269,,);
+connection bug30269;
+USE bug30269;
+show status like 'Qcache_queries_in_cache';
+--echo # Select statement not stored in query cache because of column privileges.
+SELECT id FROM test1 WHERE id>2;
+show status like 'Qcache_queries_in_cache';
+SELECT id FROM view1 WHERE id>2;
+show status like 'Qcache_queries_in_cache';
+
+connection default;
+DROP DATABASE bug30269;
+disconnect bug30269;
+DROP USER 'bug30269'@'localhost';
+
set GLOBAL query_cache_type=default;
set GLOBAL query_cache_limit=default;
set GLOBAL query_cache_min_res_unit=default;
set GLOBAL query_cache_size=default;
-# End of 5.0 tests
+# End of 5.0 tests
diff --git a/mysql-test/t/view_query_cache.test b/mysql-test/t/query_cache_with_views.test
index d4ebe45b7ac..d4ebe45b7ac 100644
--- a/mysql-test/t/view_query_cache.test
+++ b/mysql-test/t/query_cache_with_views.test
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
index cf7ea0a800f..c446808c7da 100644
--- a/mysys/my_thr_init.c
+++ b/mysys/my_thr_init.c
@@ -47,7 +47,7 @@ pthread_mutexattr_t my_fast_mutexattr;
pthread_mutexattr_t my_errorcheck_mutexattr;
#endif
-#ifdef NPTL_PTHREAD_EXIT_BUG /* see my_pthread.h */
+#ifdef TARGET_OS_LINUX
/*
Dummy thread spawned in my_thread_global_init() below to avoid
@@ -62,7 +62,7 @@ nptl_pthread_exit_hack_handler(void *arg __attribute__((unused)))
return 0;
}
-#endif
+#endif /* TARGET_OS_LINUX */
static uint get_thread_lib(void);
@@ -88,7 +88,7 @@ my_bool my_thread_global_init(void)
return 1;
}
-#ifdef NPTL_PTHREAD_EXIT_BUG
+#ifdef TARGET_OS_LINUX
/*
BUG#24507: Race conditions inside current NPTL pthread_exit()
implementation.
@@ -112,7 +112,7 @@ my_bool my_thread_global_init(void)
pthread_create(&dummy_thread,&dummy_thread_attr,
nptl_pthread_exit_hack_handler, NULL);
}
-#endif
+#endif /* TARGET_OS_LINUX */
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
/*
@@ -178,10 +178,17 @@ void my_thread_global_end(void)
&abstime);
if (error == ETIMEDOUT || error == ETIME)
{
+#ifdef HAVE_PTHREAD_KILL
+ /*
+ We shouldn't give an error here, because if we don't have
+ pthread_kill(), programs like mysqld can't ensure that all threads
+ are killed when we enter here.
+ */
if (THR_thread_count)
fprintf(stderr,
"Error in my_thread_global_end(): %d threads didn't exit\n",
THR_thread_count);
+#endif
all_threads_killed= 0;
break;
}
@@ -206,7 +213,7 @@ void my_thread_global_end(void)
if (all_threads_killed)
{
pthread_mutex_destroy(&THR_LOCK_threads);
- pthread_cond_destroy (&THR_COND_threads);
+ pthread_cond_destroy(&THR_COND_threads);
}
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
pthread_mutex_destroy(&LOCK_localtime_r);
diff --git a/sql/lock.cc b/sql/lock.cc
index f730ac56d35..0036d0aef77 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -730,6 +730,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
continue;
lock_type= table->reginfo.lock_type;
+ DBUG_ASSERT (lock_type != TL_WRITE_DEFAULT);
if (lock_type >= TL_WRITE_ALLOW_WRITE)
{
*write_lock_used=table;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d033331385b..08c2b60fa79 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1233,7 +1233,7 @@ static void wait_for_signal_thread_to_end()
*/
for (i= 0 ; i < 100 && signal_thread_in_use; i++)
{
- if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
+ if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL) != ESRCH)
break;
my_sleep(100); // Give it time to die
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index c1fe7699769..289924ff418 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1529,7 +1529,6 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
HASH_SEARCH_STATE state;
DBUG_ENTER("open_table");
- DBUG_ASSERT (table_list->lock_type != TL_WRITE_DEFAULT);
/* find a unused table in the open table cache */
if (refresh)
*refresh=0;
@@ -2700,11 +2699,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
{
safe_to_ignore_table= FALSE;
- if (tables->lock_type == TL_WRITE_DEFAULT)
- {
- tables->lock_type= thd->update_lock_default;
- DBUG_ASSERT (tables->lock_type >= TL_WRITE_ALLOW_WRITE);
- }
/*
Ignore placeholders for derived tables. After derived tables
processing, link to created temporary table will be put here.
@@ -2849,7 +2843,8 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
}
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
- tables->table->reginfo.lock_type=tables->lock_type;
+ tables->table->reginfo.lock_type= tables->lock_type == TL_WRITE_DEFAULT ?
+ thd->update_lock_default : tables->lock_type;
tables->table->grant= tables->grant;
process_view_routines:
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 0d8ef568550..e1df1ce8d9a 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -3000,14 +3000,42 @@ void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
>0 number of tables
*/
-static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
- uint8 *tables_type)
+TABLE_COUNTER_TYPE
+Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used,
+ uint8 *tables_type)
{
DBUG_ENTER("process_and_count_tables");
TABLE_COUNTER_TYPE table_count = 0;
for (; tables_used; tables_used= tables_used->next_global)
{
table_count++;
+#ifdef HAVE_QUERY_CACHE
+ /*
+ Disable any attempt to store this statement if there are
+ column level grants on any referenced tables.
+ The grant.want_privileges flag was set to 1 in the
+ check_grant() function earlier if the TABLE_LIST object
+ had any associated column privileges.
+
+ We need to check that the TABLE_LIST object isn't part
+ of a VIEW definition because we want to be able to cache
+ views.
+
+ TODO: Although it is possible to cache views, the privilege
+ check on view tables always fall back on column privileges
+ even if there are more generic table privileges. Thus it isn't
+ currently possible to retrieve cached view-tables unless the
+ client has the super user privileges.
+ */
+ if (tables_used->grant.want_privilege &&
+ tables_used->belong_to_view == NULL)
+ {
+ DBUG_PRINT("qcache", ("Don't cache statement as it refers to "
+ "tables with column privileges."));
+ thd->lex->safe_to_cache_query= 0;
+ DBUG_RETURN(0);
+ }
+#endif
if (tables_used->view)
{
DBUG_PRINT("qcache", ("view: %s db: %s",
@@ -3080,7 +3108,8 @@ Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex,
(long) lex->select_lex.options,
(int) thd->variables.query_cache_type));
- if (!(table_count= process_and_count_tables(tables_used, tables_type)))
+ if (!(table_count= process_and_count_tables(thd, tables_used,
+ tables_type)))
DBUG_RETURN(0);
if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index bc00f7ea629..34fc3a5c8d5 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -368,10 +368,12 @@ protected:
If query is cacheable return number tables in query
(query without tables not cached)
*/
- static
TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query,
- LEX *lex, TABLE_LIST *tables_used,
- uint8 *tables_type);
+ LEX *lex, TABLE_LIST *tables_used,
+ uint8 *tables_type);
+ TABLE_COUNTER_TYPE process_and_count_tables(THD *thd,
+ TABLE_LIST *tables_used,
+ uint8 *tables_type);
static my_bool ask_handler_allowance(THD *thd, TABLE_LIST *tables_used);
public:
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 9ef955a4bc2..83c141f099f 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -119,6 +119,44 @@ static void mysql_ha_hash_free(TABLE_LIST *tables)
my_free((char*) tables, MYF(0));
}
+/**
+ Close a HANDLER table.
+
+ @param thd Thread identifier.
+ @param tables A list of tables with the first entry to close.
+
+ @note Though this function takes a list of tables, only the first list entry
+ will be closed.
+ @note Broadcasts refresh if it closed the table.
+*/
+
+static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables)
+{
+ TABLE **table_ptr;
+
+ /*
+ Though we could take the table pointer from hash_tables->table,
+ we must follow the thd->handler_tables chain anyway, as we need the
+ address of the 'next' pointer referencing this table
+ for close_thread_table().
+ */
+ for (table_ptr= &(thd->handler_tables);
+ *table_ptr && (*table_ptr != tables->table);
+ table_ptr= &(*table_ptr)->next)
+ ;
+
+ if (*table_ptr)
+ {
+ (*table_ptr)->file->ha_index_or_rnd_end();
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (close_thread_table(thd, table_ptr))
+ {
+ /* Tell threads waiting for refresh that something has happened */
+ broadcast_refresh();
+ }
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+}
/*
Open a HANDLER table.
@@ -145,7 +183,7 @@ static void mysql_ha_hash_free(TABLE_LIST *tables)
bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
{
- TABLE_LIST *hash_tables;
+ TABLE_LIST *hash_tables = NULL;
char *db, *name, *alias;
uint dblen, namelen, aliaslen, counter;
int error;
@@ -197,7 +235,6 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
{
if (! reopen)
my_error(ER_ILLEGAL_HA, MYF(0), tables->alias);
- mysql_ha_close(thd, tables);
goto err;
}
@@ -225,11 +262,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
/* add to hash */
if (my_hash_insert(&thd->handler_tables_hash, (byte*) hash_tables))
- {
- my_free((char*) hash_tables, MYF(0));
- mysql_ha_close(thd, tables);
goto err;
- }
}
if (! reopen)
@@ -238,13 +271,17 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
DBUG_RETURN(FALSE);
err:
+ if (hash_tables)
+ my_free((char*) hash_tables, MYF(0));
+ if (tables->table)
+ mysql_ha_close_table(thd, tables);
DBUG_PRINT("exit",("ERROR"));
DBUG_RETURN(TRUE);
}
/*
- Close a HANDLER table.
+ Close a HANDLER table by alias or table name
SYNOPSIS
mysql_ha_close()
@@ -252,9 +289,8 @@ err:
tables A list of tables with the first entry to close.
DESCRIPTION
- Though this function takes a list of tables, only the first list entry
- will be closed.
- Broadcasts refresh if it closed the table.
+ Closes the table that is associated (on the handler tables hash) with the
+ name (table->alias) of the specified table.
RETURN
FALSE ok
@@ -264,7 +300,6 @@ err:
bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
{
TABLE_LIST *hash_tables;
- TABLE **table_ptr;
DBUG_ENTER("mysql_ha_close");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias));
@@ -273,28 +308,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
(byte*) tables->alias,
strlen(tables->alias) + 1)))
{
- /*
- Though we could take the table pointer from hash_tables->table,
- we must follow the thd->handler_tables chain anyway, as we need the
- address of the 'next' pointer referencing this table
- for close_thread_table().
- */
- for (table_ptr= &(thd->handler_tables);
- *table_ptr && (*table_ptr != hash_tables->table);
- table_ptr= &(*table_ptr)->next)
- ;
-
- if (*table_ptr)
- {
- (*table_ptr)->file->ha_index_or_rnd_end();
- VOID(pthread_mutex_lock(&LOCK_open));
- if (close_thread_table(thd, table_ptr))
- {
- /* Tell threads waiting for refresh that something has happened */
- broadcast_refresh();
- }
- VOID(pthread_mutex_unlock(&LOCK_open));
- }
+ mysql_ha_close_table(thd, hash_tables);
hash_delete(&thd->handler_tables_hash, (byte*) hash_tables);
}
else