Bug#31210 - INSERT DELAYED crashes server when used on

            partitioned table

Trying INSERT DELAYED on a partitioned table, that has not been
used right before, crashes the server. When a table is used for
select or update, it is kept open for some time. This period I
mean with "right before".

Information about partitioning of a table is stored in form of
a string in the .frm file. Parsing of this string requires a
correctly set up lexical analyzer (lex). The partitioning code
uses a new temporary instance of a lex. But it does still refer
to the previously active lex. The delayd insert thread does not
initialize its lex though...

Added initialization for thd->lex before open table in the delayed
thread and at all other places where it is necessary to call
lex_start() if all tables would be partitioned and need to parse
the .frm file.
parent 5777cc29
...@@ -183,3 +183,7 @@ c1 c2 c3 ...@@ -183,3 +183,7 @@ c1 c2 c3
182 abc 2002-11-09 182 abc 2002-11-09
184 abc 2002-11-22 184 abc 2002-11-22
drop table t1; drop table t1;
CREATE TABLE t1 (c1 INT) ENGINE=MyISAM PARTITION BY HASH(c1) PARTITIONS 1;
INSERT DELAYED INTO t1 VALUES (1);
ERROR HY000: Table storage engine for 't1' doesn't have this option
DROP TABLE t1;
...@@ -144,3 +144,11 @@ select * from t1 where c3 between '2002-01-01' and '2002-12-31'; ...@@ -144,3 +144,11 @@ select * from t1 where c3 between '2002-01-01' and '2002-12-31';
drop table t1; drop table t1;
#
# Bug#31210 - INSERT DELAYED crashes server when used on partitioned table
#
CREATE TABLE t1 (c1 INT) ENGINE=MyISAM PARTITION BY HASH(c1) PARTITIONS 1;
--error ER_ILLEGAL_HA
INSERT DELAYED INTO t1 VALUES (1);
DROP TABLE t1;
...@@ -127,6 +127,7 @@ post_init_event_thread(THD *thd) ...@@ -127,6 +127,7 @@ post_init_event_thread(THD *thd)
thd->cleanup(); thd->cleanup();
return TRUE; return TRUE;
} }
lex_start(thd);
pthread_mutex_lock(&LOCK_thread_count); pthread_mutex_lock(&LOCK_thread_count);
threads.append(thd); threads.append(thd);
......
...@@ -884,6 +884,7 @@ Events::init(my_bool opt_noacl) ...@@ -884,6 +884,7 @@ Events::init(my_bool opt_noacl)
*/ */
thd->thread_stack= (char*) &thd; thd->thread_stack= (char*) &thd;
thd->store_globals(); thd->store_globals();
lex_start(thd);
/* /*
We will need Event_db_repository anyway, even if the scheduler is We will need Event_db_repository anyway, even if the scheduler is
......
...@@ -3621,6 +3621,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) ...@@ -3621,6 +3621,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
pthread_exit(0); pthread_exit(0);
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
} }
lex_start(thd);
thd->init_for_queries(); thd->init_for_queries();
thd->command= COM_DAEMON; thd->command= COM_DAEMON;
......
...@@ -1510,6 +1510,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) ...@@ -1510,6 +1510,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
delete thd; delete thd;
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
lex_start(thd);
if (thd_type == SLAVE_THD_SQL) if (thd_type == SLAVE_THD_SQL)
thd->proc_info= "Waiting for the next event in relay log"; thd->proc_info= "Waiting for the next event in relay log";
......
...@@ -277,6 +277,7 @@ my_bool acl_init(bool dont_read_acl_tables) ...@@ -277,6 +277,7 @@ my_bool acl_init(bool dont_read_acl_tables)
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
thd->thread_stack= (char*) &thd; thd->thread_stack= (char*) &thd;
thd->store_globals(); thd->store_globals();
lex_start(thd);
/* /*
It is safe to call acl_reload() since acl_* arrays and hashes which It is safe to call acl_reload() since acl_* arrays and hashes which
will be freed there are global static objects and thus are initialized will be freed there are global static objects and thus are initialized
...@@ -3493,6 +3494,7 @@ my_bool grant_init() ...@@ -3493,6 +3494,7 @@ my_bool grant_init()
DBUG_RETURN(1); /* purecov: deadcode */ DBUG_RETURN(1); /* purecov: deadcode */
thd->thread_stack= (char*) &thd; thd->thread_stack= (char*) &thd;
thd->store_globals(); thd->store_globals();
lex_start(thd);
return_val= grant_reload(thd); return_val= grant_reload(thd);
delete thd; delete thd;
/* Remember that we don't have a THD */ /* Remember that we don't have a THD */
......
...@@ -2248,6 +2248,9 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, ...@@ -2248,6 +2248,9 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
HASH_SEARCH_STATE state; HASH_SEARCH_STATE state;
DBUG_ENTER("open_table"); DBUG_ENTER("open_table");
/* Parsing of partitioning information from .frm needs thd->lex set up. */
DBUG_ASSERT(thd->lex->is_lex_started);
/* find a unused table in the open table cache */ /* find a unused table in the open table cache */
if (refresh) if (refresh)
*refresh=0; *refresh=0;
......
...@@ -1087,6 +1087,7 @@ pthread_handler_t handle_one_connection(void *arg) ...@@ -1087,6 +1087,7 @@ pthread_handler_t handle_one_connection(void *arg)
{ {
NET *net= &thd->net; NET *net= &thd->net;
lex_start(thd);
if (login_connection(thd)) if (login_connection(thd))
goto end_thread; goto end_thread;
......
...@@ -2264,7 +2264,12 @@ pthread_handler_t handle_delayed_insert(void *arg) ...@@ -2264,7 +2264,12 @@ pthread_handler_t handle_delayed_insert(void *arg)
goto err; goto err;
} }
/* open table */ /*
Open table requires an initialized lex in case the table is
partitioned. The .frm file contains a partial SQL string which is
parsed using a lex, that depends on initialized thd->lex.
*/
lex_start(thd);
if (!(di->table=open_ltable(thd, &di->table_list, TL_WRITE_DELAYED, 0))) if (!(di->table=open_ltable(thd, &di->table_list, TL_WRITE_DELAYED, 0)))
{ {
thd->fatal_error(); // Abort waiting inserts thd->fatal_error(); // Abort waiting inserts
......
...@@ -362,6 +362,7 @@ void lex_start(THD *thd) ...@@ -362,6 +362,7 @@ void lex_start(THD *thd)
lex->server_options.owner= 0; lex->server_options.owner= 0;
lex->server_options.port= -1; lex->server_options.port= -1;
lex->is_lex_started= TRUE;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2138,7 +2139,7 @@ void Query_tables_list::destroy_query_tables_list() ...@@ -2138,7 +2139,7 @@ void Query_tables_list::destroy_query_tables_list()
st_lex::st_lex() st_lex::st_lex()
:result(0), yacc_yyss(0), yacc_yyvs(0), :result(0), yacc_yyss(0), yacc_yyvs(0),
sql_command(SQLCOM_END), option_type(OPT_DEFAULT) sql_command(SQLCOM_END), option_type(OPT_DEFAULT), is_lex_started(0)
{ {
my_init_dynamic_array2(&plugins, sizeof(plugin_ref), my_init_dynamic_array2(&plugins, sizeof(plugin_ref),
......
...@@ -1703,6 +1703,7 @@ typedef struct st_lex : public Query_tables_list ...@@ -1703,6 +1703,7 @@ typedef struct st_lex : public Query_tables_list
st_alter_tablespace *alter_tablespace_info; st_alter_tablespace *alter_tablespace_info;
bool escape_used; bool escape_used;
bool is_lex_started; /* If lex_start() did run. For debugging. */
st_lex(); st_lex();
......
...@@ -1329,6 +1329,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) ...@@ -1329,6 +1329,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
} }
new_thd->thread_stack= (char*) &tables; new_thd->thread_stack= (char*) &tables;
new_thd->store_globals(); new_thd->store_globals();
lex_start(new_thd);
new_thd->db= my_strdup("mysql", MYF(0)); new_thd->db= my_strdup("mysql", MYF(0));
new_thd->db_length= 5; new_thd->db_length= 5;
bzero((uchar*)&tables, sizeof(tables)); bzero((uchar*)&tables, sizeof(tables));
......
...@@ -140,6 +140,7 @@ bool servers_init(bool dont_read_servers_table) ...@@ -140,6 +140,7 @@ bool servers_init(bool dont_read_servers_table)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
thd->thread_stack= (char*) &thd; thd->thread_stack= (char*) &thd;
thd->store_globals(); thd->store_globals();
lex_start(thd);
/* /*
It is safe to call servers_reload() since servers_* arrays and hashes which It is safe to call servers_reload() since servers_* arrays and hashes which
will be freed there are global static objects and thus are initialized will be freed there are global static objects and thus are initialized
......
...@@ -135,6 +135,7 @@ void udf_init() ...@@ -135,6 +135,7 @@ void udf_init()
initialized = 1; initialized = 1;
new_thd->thread_stack= (char*) &new_thd; new_thd->thread_stack= (char*) &new_thd;
new_thd->store_globals(); new_thd->store_globals();
lex_start(new_thd);
new_thd->set_db(db, sizeof(db)-1); new_thd->set_db(db, sizeof(db)-1);
bzero((uchar*) &tables,sizeof(tables)); bzero((uchar*) &tables,sizeof(tables));
......
...@@ -1608,6 +1608,9 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, ...@@ -1608,6 +1608,9 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str, DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str,
share->table_name.str, (long) outparam)); share->table_name.str, (long) outparam));
/* Parsing of partitioning information from .frm needs thd->lex set up. */
DBUG_ASSERT(thd->lex->is_lex_started);
error= 1; error= 1;
bzero((char*) outparam, sizeof(*outparam)); bzero((char*) outparam, sizeof(*outparam));
outparam->in_use= thd; outparam->in_use= thd;
......
...@@ -1575,6 +1575,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) ...@@ -1575,6 +1575,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
DBUG_RETURN(1); DBUG_RETURN(1);
thd->thread_stack= (char*) &thd; thd->thread_stack= (char*) &thd;
thd->store_globals(); thd->store_globals();
lex_start(thd);
/* Init all memory structures that require explicit destruction */ /* Init all memory structures that require explicit destruction */
if (hash_init(&tz_names, &my_charset_latin1, 20, if (hash_init(&tz_names, &my_charset_latin1, 20,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment