Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
0a1e38b7
Commit
0a1e38b7
authored
Jun 01, 2005
by
ingo@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
Manual merge from 4.1.
parents
1061c412
effd338f
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
145 additions
and
63 deletions
+145
-63
mysql-test/r/create.result
mysql-test/r/create.result
+18
-0
mysql-test/t/create.test
mysql-test/t/create.test
+30
-0
sql/lock.cc
sql/lock.cc
+21
-49
sql/mysql_priv.h
sql/mysql_priv.h
+5
-2
sql/sql_base.cc
sql/sql_base.cc
+3
-3
sql/sql_handler.cc
sql/sql_handler.cc
+1
-1
sql/sql_insert.cc
sql/sql_insert.cc
+18
-6
sql/sql_parse.cc
sql/sql_parse.cc
+23
-0
sql/sql_table.cc
sql/sql_table.cc
+1
-1
sql/sql_yacc.yy
sql/sql_yacc.yy
+25
-1
No files found.
mysql-test/r/create.result
View file @
0a1e38b7
...
...
@@ -579,3 +579,21 @@ select * from t2;
b
1
drop table t1,t2;
use test;
create table t1 (a int);
create table t1 select * from t1;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
create table t2 union = (t1) select * from t1;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
flush tables with read lock;
unlock tables;
drop table t1;
create table t1(column.name int);
ERROR 42000: Incorrect table name 'column'
create table t1(test.column.name int);
ERROR 42000: Incorrect table name 'column'
create table t1(xyz.t1.name int);
ERROR 42000: Incorrect database name 'xyz'
create table t1(t1.name int);
create table t2(test.t2.name int);
drop table t1,t2;
mysql-test/t/create.test
View file @
0a1e38b7
...
...
@@ -471,3 +471,33 @@ insert into t2 values ();
select
*
from
t1
;
select
*
from
t2
;
drop
table
t1
,
t2
;
#
# Bug#10224 - ANALYZE TABLE crashing with simultaneous
# CREATE ... SELECT statement.
# This tests two additional possible errors and a hang if
# an improper fix is present.
#
connection
default
;
use
test
;
create
table
t1
(
a
int
);
--
error
1093
create
table
t1
select
*
from
t1
;
--
error
1093
create
table
t2
union
=
(
t1
)
select
*
from
t1
;
flush
tables
with
read
lock
;
unlock
tables
;
drop
table
t1
;
#
# Bug#10413: Invalid column name is not rejected
#
--
error
1103
create
table
t1
(
column
.
name
int
);
--
error
1103
create
table
t1
(
test
.
column
.
name
int
);
--
error
1102
create
table
t1
(
xyz
.
t1
.
name
int
);
create
table
t1
(
t1
.
name
int
);
create
table
t2
(
test
.
t2
.
name
int
);
drop
table
t1
,
t2
;
sql/lock.cc
View file @
0a1e38b7
...
...
@@ -82,8 +82,24 @@ static int unlock_external(THD *thd, TABLE **table,uint count);
static
void
print_lock_error
(
int
error
,
const
char
*
);
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
bool
ignore_global_read_lock
)
/*
Lock tables.
SYNOPSIS
mysql_lock_tables()
thd The current thread.
tables An array of pointers to the tables to lock.
count The number of tables to lock.
flags Options:
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables.
RETURN
A lock structure pointer on success.
NULL on error.
*/
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
uint
flags
)
{
MYSQL_LOCK
*
sql_lock
;
TABLE
*
write_lock_used
;
...
...
@@ -94,7 +110,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
if
(
!
(
sql_lock
=
get_lock_data
(
thd
,
tables
,
count
,
0
,
&
write_lock_used
)))
break
;
if
(
global_read_lock
&&
write_lock_used
&&
!
ignore_global_read_lock
)
if
(
global_read_lock
&&
write_lock_used
&&
!
(
flags
&
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
))
{
/*
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
...
...
@@ -128,7 +145,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
thd
->
some_tables_deleted
=
1
;
// Try again
sql_lock
->
lock_count
=
0
;
// Locks are alread freed
}
else
if
(
!
thd
->
some_tables_deleted
)
else
if
(
!
thd
->
some_tables_deleted
||
(
flags
&
MYSQL_LOCK_IGNORE_FLUSH
)
)
{
thd
->
locked
=
0
;
break
;
...
...
@@ -951,48 +968,3 @@ bool make_global_read_lock_block_commit(THD *thd)
}
/*
Set protection against global read lock.
SYNOPSIS
set_protect_against_global_read_lock()
void
RETURN
FALSE OK, no global read lock exists.
TRUE Error, global read lock exists already.
*/
bool
set_protect_against_global_read_lock
(
void
)
{
bool
global_read_lock_exists
;
pthread_mutex_lock
(
&
LOCK_open
);
if
(
!
(
global_read_lock_exists
=
test
(
global_read_lock
)))
protect_against_global_read_lock
++
;
pthread_mutex_unlock
(
&
LOCK_open
);
return
global_read_lock_exists
;
}
/*
Unset protection against global read lock.
SYNOPSIS
unset_protect_against_global_read_lock()
void
RETURN
void
*/
void
unset_protect_against_global_read_lock
(
void
)
{
pthread_mutex_lock
(
&
LOCK_open
);
protect_against_global_read_lock
--
;
pthread_mutex_unlock
(
&
LOCK_open
);
pthread_cond_broadcast
(
&
COND_refresh
);
}
sql/mysql_priv.h
View file @
0a1e38b7
...
...
@@ -1166,8 +1166,11 @@ extern pthread_t signal_thread;
extern
struct
st_VioSSLAcceptorFd
*
ssl_acceptor_fd
;
#endif
/* HAVE_OPENSSL */
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
table
,
uint
count
,
bool
ignore_global_read_lock
=
FALSE
);
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
table
,
uint
count
,
uint
flags
);
/* mysql_lock_tables() flags bits */
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
void
mysql_unlock_tables
(
THD
*
thd
,
MYSQL_LOCK
*
sql_lock
);
void
mysql_unlock_read_tables
(
THD
*
thd
,
MYSQL_LOCK
*
sql_lock
);
void
mysql_unlock_some_tables
(
THD
*
thd
,
TABLE
**
table
,
uint
count
);
...
...
sql/sql_base.cc
View file @
0a1e38b7
...
...
@@ -1384,7 +1384,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
MYSQL_LOCK
*
lock
;
/* We should always get these locks */
thd
->
some_tables_deleted
=
0
;
if
((
lock
=
mysql_lock_tables
(
thd
,
tables
,(
uint
)
(
tables_ptr
-
tables
)
)))
if
((
lock
=
mysql_lock_tables
(
thd
,
tables
,
(
uint
)
(
tables_ptr
-
tables
),
0
)))
{
thd
->
locked_tables
=
mysql_lock_merge
(
thd
->
locked_tables
,
lock
);
}
...
...
@@ -2022,7 +2022,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
{
DBUG_ASSERT
(
thd
->
lock
==
0
);
// You must lock everything at once
if
((
table
->
reginfo
.
lock_type
=
lock_type
)
!=
TL_UNLOCK
)
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
table_list
->
table
,
1
)))
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
table_list
->
table
,
1
,
0
)))
table
=
0
;
}
}
...
...
@@ -2237,7 +2237,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
thd
->
options
|=
OPTION_TABLE_LOCK
;
}
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
start
,
(
uint
)
(
ptr
-
start
)
)))
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
start
,
(
uint
)
(
ptr
-
start
),
0
)))
{
if
(
thd
->
lex
->
requires_prelocking
())
{
...
...
sql/sql_handler.cc
View file @
0a1e38b7
...
...
@@ -433,7 +433,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
protocol
->
send_fields
(
&
list
,
Protocol
::
SEND_NUM_ROWS
|
Protocol
::
SEND_EOF
);
HANDLER_TABLES_HACK
(
thd
);
lock
=
mysql_lock_tables
(
thd
,
&
tables
->
table
,
1
);
lock
=
mysql_lock_tables
(
thd
,
&
tables
->
table
,
1
,
0
);
HANDLER_TABLES_HACK
(
thd
);
if
(
!
lock
)
...
...
sql/sql_insert.cc
View file @
0a1e38b7
...
...
@@ -1211,10 +1211,13 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
Avoid that a global read lock steps in while we are creating the
new thread. It would block trying to open the table. Hence, the
DI thread and this thread would wait until after the global
readlock is gone. If the read lock exists already, we leave with
no table and then switch to non-delayed insert.
readlock is gone. Since the insert thread needs to wait for a
global read lock anyway, we do it right now. Note that
wait_if_global_read_lock() sets a protection against a new
global read lock when it succeeds. This needs to be released by
start_waiting_global_read_lock().
*/
if
(
set_protect_against_global_read_lock
(
))
if
(
wait_if_global_read_lock
(
thd
,
0
,
1
))
goto
err
;
if
(
!
(
tmp
=
new
delayed_insert
()))
{
...
...
@@ -1256,7 +1259,11 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
pthread_cond_wait
(
&
tmp
->
cond_client
,
&
tmp
->
mutex
);
}
pthread_mutex_unlock
(
&
tmp
->
mutex
);
unset_protect_against_global_read_lock
();
/*
Release the protection against the global read lock and wake
everyone, who might want to set a global read lock.
*/
start_waiting_global_read_lock
(
thd
);
thd
->
proc_info
=
"got old table"
;
if
(
tmp
->
thd
.
killed
)
{
...
...
@@ -1292,7 +1299,11 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
err1:
thd
->
fatal_error
();
unset_protect_against_global_read_lock
();
/*
Release the protection against the global read lock and wake
everyone, who might want to set a global read lock.
*/
start_waiting_global_read_lock
(
thd
);
err:
pthread_mutex_unlock
(
&
LOCK_delayed_create
);
DBUG_RETURN
(
0
);
// Continue with normal insert
...
...
@@ -1650,7 +1661,8 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
handler will close the table and finish when the outstanding
inserts are done.
*/
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
di
->
table
,
1
,
TRUE
)))
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
di
->
table
,
1
,
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
)))
{
/* Fatal error */
di
->
dead
=
1
;
...
...
sql/sql_parse.cc
View file @
0a1e38b7
...
...
@@ -2773,6 +2773,24 @@ mysql_execute_command(THD *thd)
lex
->
create_info
.
default_table_charset
=
lex
->
create_info
.
table_charset
;
lex
->
create_info
.
table_charset
=
0
;
}
/*
The create-select command will open and read-lock the select table
and then create, open and write-lock the new table. If a global
read lock steps in, we get a deadlock. The write lock waits for
the global read lock, while the global read lock waits for the
select table to be closed. So we wait until the global readlock is
gone before starting both steps. Note that
wait_if_global_read_lock() sets a protection against a new global
read lock when it succeeds. This needs to be released by
start_waiting_global_read_lock(). We protect the normal CREATE
TABLE in the same way. That way we avoid that a new table is
created during a gobal read lock.
*/
if
(
wait_if_global_read_lock
(
thd
,
0
,
1
))
{
res
=
-
1
;
goto
unsent_create_error
;
}
if
(
select_lex
->
item_list
.
elements
)
// With select
{
select_result
*
result
;
...
...
@@ -2846,6 +2864,11 @@ mysql_execute_command(THD *thd)
if
(
!
res
)
send_ok
(
thd
);
}
/*
Release the protection against the global read lock and wake
everyone, who might want to set a global read lock.
*/
start_waiting_global_read_lock
(
thd
);
lex
->
link_first_table_back
(
create_table
,
link_to_local
);
break
;
...
...
sql/sql_table.cc
View file @
0a1e38b7
...
...
@@ -1756,7 +1756,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
}
table
->
reginfo
.
lock_type
=
TL_WRITE
;
if
(
!
((
*
lock
)
=
mysql_lock_tables
(
thd
,
&
table
,
1
)))
if
(
!
((
*
lock
)
=
mysql_lock_tables
(
thd
,
&
table
,
1
,
MYSQL_LOCK_IGNORE_FLUSH
)))
{
VOID
(
pthread_mutex_lock
(
&
LOCK_open
));
hash_delete
(
&
open_cache
,(
byte
*
)
table
);
...
...
sql/sql_yacc.yy
View file @
0a1e38b7
...
...
@@ -7078,7 +7078,31 @@ simple_ident_q:
field_ident:
ident { $$=$1;}
| ident '.' ident { $$=$3;} /* Skip schema name in create*/
| ident '.' ident '.' ident
{
TABLE_LIST *table= (TABLE_LIST*) Select->table_list.first;
if (my_strcasecmp(table_alias_charset, $1.str, table->db))
{
net_printf(YYTHD, ER_WRONG_DB_NAME, $1.str);
YYABORT;
}
if (my_strcasecmp(table_alias_charset, $3.str, table->real_name))
{
net_printf(YYTHD, ER_WRONG_TABLE_NAME, $3.str);
YYABORT;
}
$$=$5;
}
| ident '.' ident
{
TABLE_LIST *table= (TABLE_LIST*) Select->table_list.first;
if (my_strcasecmp(table_alias_charset, $1.str, table->alias))
{
net_printf(YYTHD, ER_WRONG_TABLE_NAME, $1.str);
YYABORT;
}
$$=$3;
}
| '.' ident { $$=$2;} /* For Delphi */;
table_ident:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment