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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
ff4a6e13
Commit
ff4a6e13
authored
Sep 15, 2005
by
dlenev@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/dlenev/src/mysql-5.0-bg12704-2
parents
b4c9c778
2a96aa11
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
414 additions
and
97 deletions
+414
-97
mysql-test/t/trigger.test
mysql-test/t/trigger.test
+113
-3
sql/lock.cc
sql/lock.cc
+18
-3
sql/mysql_priv.h
sql/mysql_priv.h
+5
-2
sql/sp.cc
sql/sp.cc
+61
-6
sql/sp.h
sql/sp.h
+1
-0
sql/sp_head.cc
sql/sp_head.cc
+0
-4
sql/sql_base.cc
sql/sql_base.cc
+104
-33
sql/sql_handler.cc
sql/sql_handler.cc
+2
-1
sql/sql_insert.cc
sql/sql_insert.cc
+3
-1
sql/sql_lex.cc
sql/sql_lex.cc
+6
-0
sql/sql_lex.h
sql/sql_lex.h
+16
-0
sql/sql_prepare.cc
sql/sql_prepare.cc
+21
-12
sql/sql_table.cc
sql/sql_table.cc
+9
-1
sql/sql_trigger.cc
sql/sql_trigger.cc
+19
-0
sql/sql_trigger.h
sql/sql_trigger.h
+2
-0
sql/sql_update.cc
sql/sql_update.cc
+34
-31
No files found.
mysql-test/t/trigger.test
View file @
ff4a6e13
...
...
@@ -10,6 +10,11 @@ drop function if exists f1;
drop
procedure
if
exists
p1
;
--
enable_warnings
# Create additional connections used through test
connect
(
addconroot1
,
localhost
,
root
,,);
connect
(
addconroot2
,
localhost
,
root
,,);
connection
default
;
create
table
t1
(
i
int
);
# let us test some very simple trigger
...
...
@@ -680,12 +685,10 @@ end|
delimiter
;
|
update
t1
set
data
=
1
;
connect
(
addconroot
,
localhost
,
root
,,);
connection
addconroot
;
connection
addconroot1
;
update
t1
set
data
=
2
;
connection
default
;
disconnect
addconroot
;
drop
table
t1
;
#
...
...
@@ -765,3 +768,110 @@ insert into t1 values (3);
select
*
from
t1
;
drop
trigger
t1_bi
;
drop
tables
t1
,
t2
;
# Tests for bug #12704 "Server crashes during trigger execution".
# If we run DML statements and CREATE TRIGGER statements concurrently
# it may happen that trigger will be created while DML statement is
# waiting for table lock. In this case we have to reopen tables and
# recalculate prelocking set.
# Unfortunately these tests rely on the order in which tables are locked
# by statement so they are non determenistic and are disabled.
--
disable_parsing
create
table
t1
(
id
int
);
create
table
t2
(
id
int
);
create
table
t3
(
id
int
);
create
function
f1
()
returns
int
return
(
select
max
(
id
)
+
2
from
t2
);
create
view
v1
as
select
f1
()
as
f
;
# Let us check that we notice trigger at all
connection
addconroot1
;
lock
tables
t2
write
;
connection
default
;
send
insert
into
t1
values
((
select
max
(
id
)
from
t2
)),
(
2
);
--
sleep
1
connection
addconroot2
;
create
trigger
t1_trg
before
insert
on
t1
for
each
row
set
NEW
.
id
:=
1
;
connection
addconroot1
;
unlock
tables
;
connection
default
;
reap
;
select
*
from
t1
;
# Check that we properly calculate new prelocking set
insert
into
t2
values
(
3
);
connection
addconroot1
;
lock
tables
t2
write
;
connection
default
;
send
insert
into
t1
values
((
select
max
(
id
)
from
t2
)),
(
4
);
--
sleep
1
connection
addconroot2
;
drop
trigger
t1_trg
;
create
trigger
t1_trg
before
insert
on
t1
for
each
row
insert
into
t3
values
(
new
.
id
);
connection
addconroot1
;
unlock
tables
;
connection
default
;
reap
;
select
*
from
t1
;
select
*
from
t3
;
# We should be able to do this even if fancy views are involved
connection
addconroot1
;
lock
tables
t2
write
;
connection
default
;
send
insert
into
t1
values
((
select
max
(
f
)
from
v1
)),
(
6
);
--
sleep
1
connection
addconroot2
;
drop
trigger
t1_trg
;
create
trigger
t1_trg
before
insert
on
t1
for
each
row
insert
into
t3
values
(
new
.
id
+
100
);
connection
addconroot1
;
unlock
tables
;
connection
default
;
reap
;
select
*
from
t1
;
select
*
from
t3
;
# This also should work for multi-update
# Let us drop trigger to demonstrate that prelocking set is really
# rebuilt
drop
trigger
t1_trg
;
connection
addconroot1
;
lock
tables
t2
write
;
connection
default
;
send
update
t1
,
t2
set
t1
.
id
=
10
where
t1
.
id
=
t2
.
id
;
--
sleep
1
connection
addconroot2
;
create
trigger
t1_trg
before
update
on
t1
for
each
row
insert
into
t3
values
(
new
.
id
);
connection
addconroot1
;
unlock
tables
;
connection
default
;
reap
;
select
*
from
t1
;
select
*
from
t3
;
# And even for multi-update converted from ordinary update thanks to view
drop
view
v1
;
drop
trigger
t1_trg
;
create
view
v1
as
select
t1
.
id
as
id1
from
t1
,
t2
where
t1
.
id
=
t2
.
id
;
insert
into
t2
values
(
10
);
connection
addconroot1
;
lock
tables
t2
write
;
connection
default
;
send
update
v1
set
id1
=
11
;
--
sleep
1
connection
addconroot2
;
create
trigger
t1_trg
before
update
on
t1
for
each
row
insert
into
t3
values
(
new
.
id
+
100
);
connection
addconroot1
;
unlock
tables
;
connection
default
;
reap
;
select
*
from
t1
;
select
*
from
t3
;
drop
function
f1
;
drop
view
v1
;
drop
table
t1
,
t2
,
t3
;
--
enable_parsing
sql/lock.cc
View file @
ff4a6e13
...
...
@@ -93,23 +93,33 @@ static void print_lock_error(int error, const char *);
flags Options:
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables.
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
or dropped tables by itself,
mysql_lock_tables() should
notify upper level and rely
on caller doing this.
need_reopen Out parameter, TRUE if some tables were altered
or deleted and should be reopened by caller.
RETURN
A lock structure pointer on success.
NULL on error.
NULL on error
or if some tables should be reopen
.
*/
/* Map the return value of thr_lock to an error from errmsg.txt */
static
int
thr_lock_errno_to_mysql
[]
=
{
0
,
1
,
ER_LOCK_WAIT_TIMEOUT
,
ER_LOCK_DEADLOCK
};
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
uint
flags
)
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
tables
,
uint
count
,
uint
flags
,
bool
*
need_reopen
)
{
MYSQL_LOCK
*
sql_lock
;
TABLE
*
write_lock_used
;
int
rc
;
/* Map the return value of thr_lock to an error from errmsg.txt */
DBUG_ENTER
(
"mysql_lock_tables"
);
*
need_reopen
=
FALSE
;
for
(;;)
{
if
(
!
(
sql_lock
=
get_lock_data
(
thd
,
tables
,
count
,
0
,
&
write_lock_used
)))
...
...
@@ -178,6 +188,11 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
thd
->
locked
=
0
;
retry:
sql_lock
=
0
;
if
(
flags
&
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN
)
{
*
need_reopen
=
TRUE
;
break
;
}
if
(
wait_for_tables
(
thd
))
break
;
// Couldn't open tables
}
...
...
sql/mysql_priv.h
View file @
ff4a6e13
...
...
@@ -952,7 +952,7 @@ int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags);
int
simple_open_n_lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
);
bool
open_and_lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
);
bool
open_normal_and_derived_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
flags
);
int
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
counter
);
int
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
counter
,
bool
*
need_reopen
);
TABLE
*
open_temporary_table
(
THD
*
thd
,
const
char
*
path
,
const
char
*
db
,
const
char
*
table_name
,
bool
link_in_list
);
bool
rm_temporary_table
(
enum
db_type
base
,
char
*
path
);
...
...
@@ -960,6 +960,7 @@ void free_io_cache(TABLE *entry);
void
intern_close_table
(
TABLE
*
entry
);
bool
close_thread_table
(
THD
*
thd
,
TABLE
**
table_ptr
);
void
close_temporary_tables
(
THD
*
thd
);
void
close_tables_for_reopen
(
THD
*
thd
,
TABLE_LIST
*
tables
);
TABLE_LIST
*
find_table_in_list
(
TABLE_LIST
*
table
,
uint
offset_to_list
,
const
char
*
db_name
,
...
...
@@ -1238,10 +1239,12 @@ 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
,
uint
flags
);
MYSQL_LOCK
*
mysql_lock_tables
(
THD
*
thd
,
TABLE
**
table
,
uint
count
,
uint
flags
,
bool
*
need_reopen
);
/* mysql_lock_tables() flags bits */
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
#define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004
void
mysql_unlock_tables
(
THD
*
thd
,
MYSQL_LOCK
*
sql_lock
);
void
mysql_unlock_read_tables
(
THD
*
thd
,
MYSQL_LOCK
*
sql_lock
);
...
...
sql/sp.cc
View file @
ff4a6e13
...
...
@@ -107,7 +107,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
{
TABLE_LIST
tables
;
TABLE
*
table
;
bool
refresh
;
bool
not_used
;
DBUG_ENTER
(
"open_proc_table"
);
/*
...
...
@@ -122,7 +122,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
bzero
((
char
*
)
&
tables
,
sizeof
(
tables
));
tables
.
db
=
(
char
*
)
"mysql"
;
tables
.
table_name
=
tables
.
alias
=
(
char
*
)
"proc"
;
if
(
!
(
table
=
open_table
(
thd
,
&
tables
,
thd
->
mem_root
,
&
refresh
,
if
(
!
(
table
=
open_table
(
thd
,
&
tables
,
thd
->
mem_root
,
&
not_used
,
MYSQL_LOCK_IGNORE_FLUSH
)))
{
thd
->
restore_backup_open_tables_state
(
backup
);
...
...
@@ -138,7 +138,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
could lead to a deadlock if we have other tables opened.
*/
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
table
,
1
,
MYSQL_LOCK_IGNORE_FLUSH
)))
MYSQL_LOCK_IGNORE_FLUSH
,
&
not_used
)))
{
close_proc_table
(
thd
,
backup
);
DBUG_RETURN
(
0
);
...
...
@@ -1265,7 +1265,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
/*
Add routine to the set of stored routines used by statement.
Add routine which is explicitly used by statement to the set of stored
routines used by this statement.
SYNOPSIS
sp_add_used_routine()
...
...
@@ -1276,7 +1277,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...)
NOTES
Will also add element to end of 'LEX::sroutines_list' list.
Will also add element to end of 'LEX::sroutines_list' list (and will
take into account that this is explicitly used routine).
To be friendly towards prepared statements one should pass
persistent arena as second argument.
...
...
@@ -1287,6 +1289,37 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena,
{
rt
->
set_routine_type
(
rt_type
);
(
void
)
add_used_routine
(
lex
,
arena
,
&
rt
->
m_sroutines_key
);
lex
->
sroutines_list_own_last
=
lex
->
sroutines_list
.
next
;
lex
->
sroutines_list_own_elements
=
lex
->
sroutines_list
.
elements
;
}
/*
Remove routines which are only indirectly used by statement from
the set of routines used by this statement.
SYNOPSIS
sp_remove_not_own_routines()
lex LEX representing statement
*/
void
sp_remove_not_own_routines
(
LEX
*
lex
)
{
Sroutine_hash_entry
*
not_own_rt
,
*
next_rt
;
for
(
not_own_rt
=
*
(
Sroutine_hash_entry
**
)
lex
->
sroutines_list_own_last
;
not_own_rt
;
not_own_rt
=
next_rt
)
{
/*
It is safe to obtain not_own_rt->next after calling hash_delete() now
but we want to be more future-proof.
*/
next_rt
=
not_own_rt
->
next
;
hash_delete
(
&
lex
->
sroutines
,
(
byte
*
)
not_own_rt
);
}
*
(
Sroutine_hash_entry
**
)
lex
->
sroutines_list_own_last
=
NULL
;
lex
->
sroutines_list
.
next
=
lex
->
sroutines_list_own_last
;
lex
->
sroutines_list
.
elements
=
lex
->
sroutines_list_own_elements
;
}
...
...
@@ -1343,6 +1376,28 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src)
}
/*
Add contents of list representing set of routines to the set of
routines used by statement.
SYNOPSIS
sp_update_stmt_used_routines()
thd Thread context
lex LEX representing statement
src List representing set from which routines will be added
NOTE
It will also add elements to end of 'LEX::sroutines_list' list.
*/
static
void
sp_update_stmt_used_routines
(
THD
*
thd
,
LEX
*
lex
,
SQL_LIST
*
src
)
{
for
(
Sroutine_hash_entry
*
rt
=
(
Sroutine_hash_entry
*
)
src
->
first
;
rt
;
rt
=
rt
->
next
)
(
void
)
add_used_routine
(
lex
,
thd
->
stmt_arena
,
&
rt
->
key
);
}
/*
Cache sub-set of routines used by statement, add tables used by these
routines to statement table list. Do the same for all routines used
...
...
@@ -1463,7 +1518,7 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
{
Sroutine_hash_entry
**
last_cached_routine_ptr
=
(
Sroutine_hash_entry
**
)
lex
->
sroutines_list
.
next
;
sp_update_stmt_used_routines
(
thd
,
lex
,
&
aux_lex
->
sroutines
);
sp_update_stmt_used_routines
(
thd
,
lex
,
&
aux_lex
->
sroutines
_list
);
(
void
)
sp_cache_routines_and_add_tables_aux
(
thd
,
lex
,
*
last_cached_routine_ptr
,
FALSE
);
}
...
...
sql/sp.h
View file @
ff4a6e13
...
...
@@ -84,6 +84,7 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
bool
*
first_no_prelocking
);
void
sp_add_used_routine
(
LEX
*
lex
,
Query_arena
*
arena
,
sp_name
*
rt
,
char
rt_type
);
void
sp_remove_not_own_routines
(
LEX
*
lex
);
void
sp_update_sp_used_routines
(
HASH
*
dst
,
HASH
*
src
);
bool
sp_cache_routines_and_add_tables
(
THD
*
thd
,
LEX
*
lex
,
bool
first_no_prelock
);
...
...
sql/sp_head.cc
View file @
ff4a6e13
...
...
@@ -1909,10 +1909,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
attached it above in this function).
Now we'll save the 'tail', and detach it.
*/
DBUG_ASSERT
(
!
lex_query_tables_own_last
||
lex_query_tables_own_last
==
m_lex
->
query_tables_own_last
&&
prelocking_tables
==
*
(
m_lex
->
query_tables_own_last
));
lex_query_tables_own_last
=
m_lex
->
query_tables_own_last
;
prelocking_tables
=
*
lex_query_tables_own_last
;
*
lex_query_tables_own_last
=
NULL
;
...
...
sql/sql_base.cc
View file @
ff4a6e13
...
...
@@ -1399,7 +1399,6 @@ bool reopen_table(TABLE *table,bool locked)
tmp
.
status
=
table
->
status
;
tmp
.
keys_in_use_for_query
=
tmp
.
s
->
keys_in_use
;
tmp
.
used_keys
=
tmp
.
s
->
keys_for_keyread
;
tmp
.
force_index
=
tmp
.
force_index
;
/* Get state */
tmp
.
s
->
key_length
=
table
->
s
->
key_length
;
...
...
@@ -1430,6 +1429,9 @@ bool reopen_table(TABLE *table,bool locked)
for
(
key
=
0
;
key
<
table
->
s
->
keys
;
key
++
)
for
(
part
=
0
;
part
<
table
->
key_info
[
key
].
usable_key_parts
;
part
++
)
table
->
key_info
[
key
].
key_part
[
part
].
field
->
table
=
table
;
if
(
table
->
triggers
)
table
->
triggers
->
set_table
(
table
);
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
));
error
=
0
;
...
...
@@ -1478,7 +1480,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
TABLE
*
table
,
*
next
,
**
prev
;
TABLE
**
tables
,
**
tables_ptr
;
// For locks
bool
error
=
0
;
bool
error
=
0
,
not_used
;
if
(
get_locks
)
{
/* The ptr is checked later */
...
...
@@ -1519,7 +1521,8 @@ 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
),
0
)))
if
((
lock
=
mysql_lock_tables
(
thd
,
tables
,
(
uint
)
(
tables_ptr
-
tables
),
0
,
&
not_used
)))
{
thd
->
locked_tables
=
mysql_lock_merge
(
thd
->
locked_tables
,
lock
);
}
...
...
@@ -1969,9 +1972,15 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
/*
Ignore placeholders for derived tables. After derived tables
processing, link to created temporary table will be put here.
If this is derived table for view then we still want to process
routines used by this view.
*/
if
(
tables
->
derived
)
{
if
(
tables
->
view
)
goto
process_view_routines
;
continue
;
}
if
(
tables
->
schema_table
)
{
if
(
!
mysql_schema_table
(
thd
,
thd
->
lex
,
tables
))
...
...
@@ -2003,23 +2012,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
if
(
query_tables_last_own
==
&
(
tables
->
next_global
)
&&
tables
->
view
->
query_tables
)
query_tables_last_own
=
tables
->
view
->
query_tables_last
;
/*
Again if needed we have to get cache all routines used by this view
and add tables used by them to table list
.
Let us free memory used by 'sroutines' hash here since we never
call destructor for this LEX
.
*/
if
(
!
thd
->
prelocked_mode
&&
!
thd
->
lex
->
requires_prelocking
()
&&
tables
->
view
->
sroutines
.
records
)
{
/* We have at least one table in TL here */
if
(
!
query_tables_last_own
)
query_tables_last_own
=
thd
->
lex
->
query_tables_last
;
sp_cache_routines_and_add_tables_for_view
(
thd
,
thd
->
lex
,
tables
->
view
);
}
/* Cleanup hashes because destructo for this LEX is never called */
hash_free
(
&
tables
->
view
->
sroutines
);
continue
;
goto
process_view_routines
;
}
if
(
refresh
)
// Refresh in progress
...
...
@@ -2031,11 +2029,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
thd
->
version
=
refresh_version
;
TABLE
**
prev_table
=
&
thd
->
open_tables
;
bool
found
=
0
;
/*
QQ: What we should do if we have started building of table list
for prelocking ??? Probably throw it away ? But before we should
mark all temporary tables as free? How about locked ?
*/
for
(
TABLE_LIST
*
tmp
=
*
start
;
tmp
;
tmp
=
tmp
->
next_global
)
{
/* Close normal (not temporary) changed tables */
...
...
@@ -2059,6 +2052,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
pthread_mutex_unlock
(
&
LOCK_open
);
if
(
found
)
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
));
// Signal to refresh
/*
Let us prepare for recalculation of set of prelocked tables.
First we pretend that we have finished calculation which we
were doing currently. Then we restore list of tables to be
opened and set of used routines to the state in which they were
before first open_tables() call for this statement (i.e. before
we have calculated current set of tables for prelocking).
*/
if
(
query_tables_last_own
)
thd
->
lex
->
mark_as_requiring_prelocking
(
query_tables_last_own
);
thd
->
lex
->
chop_off_not_own_tables
();
sp_remove_not_own_routines
(
thd
->
lex
);
goto
restart
;
}
result
=
-
1
;
// Fatal error
...
...
@@ -2089,6 +2094,21 @@ 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
->
grant
=
tables
->
grant
;
process_view_routines:
/*
Again we may need cache all routines used by this view and add
tables used by them to table list.
*/
if
(
tables
->
view
&&
!
thd
->
prelocked_mode
&&
!
thd
->
lex
->
requires_prelocking
()
&&
tables
->
view
->
sroutines_list
.
elements
)
{
/* We have at least one table in TL here. */
if
(
!
query_tables_last_own
)
query_tables_last_own
=
thd
->
lex
->
query_tables_last
;
sp_cache_routines_and_add_tables_for_view
(
thd
,
thd
->
lex
,
tables
->
view
);
}
}
thd
->
proc_info
=
0
;
free_root
(
&
new_frm_mem
,
MYF
(
0
));
// Free pre-alloced block
...
...
@@ -2193,7 +2213,8 @@ 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
,
0
)))
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
table_list
->
table
,
1
,
0
,
&
refresh
)))
table
=
0
;
}
}
...
...
@@ -2221,11 +2242,20 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
int
simple_open_n_lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
)
{
DBUG_ENTER
(
"simple_open_n_lock_tables"
);
uint
counter
;
if
(
open_tables
(
thd
,
&
tables
,
&
counter
,
0
)
||
lock_tables
(
thd
,
tables
,
counter
))
DBUG_RETURN
(
-
1
);
/* purecov: inspected */
bool
need_reopen
;
DBUG_ENTER
(
"simple_open_n_lock_tables"
);
for
(
;
;
)
{
if
(
open_tables
(
thd
,
&
tables
,
&
counter
,
0
))
DBUG_RETURN
(
-
1
);
if
(
!
lock_tables
(
thd
,
tables
,
counter
,
&
need_reopen
))
break
;
if
(
!
need_reopen
)
DBUG_RETURN
(
-
1
);
close_tables_for_reopen
(
thd
,
tables
);
}
DBUG_RETURN
(
0
);
}
...
...
@@ -2250,10 +2280,20 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
bool
open_and_lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
)
{
uint
counter
;
bool
need_reopen
;
DBUG_ENTER
(
"open_and_lock_tables"
);
if
(
open_tables
(
thd
,
&
tables
,
&
counter
,
0
)
||
lock_tables
(
thd
,
tables
,
counter
)
||
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
for
(
;
;
)
{
if
(
open_tables
(
thd
,
&
tables
,
&
counter
,
0
))
DBUG_RETURN
(
-
1
);
if
(
!
lock_tables
(
thd
,
tables
,
counter
,
&
need_reopen
))
break
;
if
(
!
need_reopen
)
DBUG_RETURN
(
-
1
);
close_tables_for_reopen
(
thd
,
tables
);
}
if
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
(
thd
->
fill_derived_tables
()
&&
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_filling
)))
DBUG_RETURN
(
TRUE
);
/* purecov: inspected */
...
...
@@ -2321,7 +2361,12 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
lock_tables()
thd Thread handler
tables Tables to lock
count umber of opened tables
count Number of opened tables
need_reopen Out parameter which if TRUE indicates that some
tables were dropped or altered during this call
and therefore invoker should reopen tables and
try to lock them once again (in this case
lock_tables() will also return error).
NOTES
You can't call lock_tables twice, as this would break the dead-lock-free
...
...
@@ -2337,7 +2382,7 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
-1 Error
*/
int
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
count
)
int
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
count
,
bool
*
need_reopen
)
{
TABLE_LIST
*
table
;
...
...
@@ -2353,6 +2398,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
*/
DBUG_ASSERT
(
!
thd
->
lex
->
requires_prelocking
()
||
tables
);
*
need_reopen
=
FALSE
;
if
(
!
tables
)
DBUG_RETURN
(
0
);
...
...
@@ -2385,7 +2432,9 @@ 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
),
0
)))
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
start
,
(
uint
)
(
ptr
-
start
),
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN
,
need_reopen
)))
{
if
(
thd
->
lex
->
requires_prelocking
())
{
...
...
@@ -2464,6 +2513,28 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
}
/*
Prepare statement for reopening of tables and recalculation of set of
prelocked tables.
SYNOPSIS
close_tables_for_reopen()
thd Thread context
tables List of tables which we were trying to open and lock
*/
void
close_tables_for_reopen
(
THD
*
thd
,
TABLE_LIST
*
tables
)
{
thd
->
lex
->
chop_off_not_own_tables
();
sp_remove_not_own_routines
(
thd
->
lex
);
for
(
TABLE_LIST
*
tmp
=
tables
;
tmp
;
tmp
=
tmp
->
next_global
)
if
(
tmp
->
table
&&
!
tmp
->
table
->
s
->
tmp_table
)
tmp
->
table
=
0
;
close_thread_tables
(
thd
);
}
/*
Open a single table without table caching and don't set it in open_list
Used by alter_table to open a temporary table and when creating
...
...
sql/sql_handler.cc
View file @
ff4a6e13
...
...
@@ -346,6 +346,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
uint
num_rows
;
byte
*
key
;
uint
key_len
;
bool
not_used
;
DBUG_ENTER
(
"mysql_ha_read"
);
DBUG_PRINT
(
"enter"
,(
"'%s'.'%s' as '%s'"
,
tables
->
db
,
tables
->
table_name
,
tables
->
alias
));
...
...
@@ -431,7 +432,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
,
0
);
lock
=
mysql_lock_tables
(
thd
,
&
tables
->
table
,
1
,
0
,
&
not_used
);
HANDLER_TABLES_HACK
(
thd
);
if
(
!
lock
)
...
...
sql/sql_insert.cc
View file @
ff4a6e13
...
...
@@ -1826,6 +1826,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
if
(
di
->
tables_in_use
&&
!
thd
->
lock
)
{
bool
not_used
;
/*
Request for new delayed insert.
Lock the table, but avoid to be blocked by a global read lock.
...
...
@@ -1837,7 +1838,8 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
inserts are done.
*/
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
&
di
->
table
,
1
,
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
)))
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK
,
&
not_used
)))
{
/* Fatal error */
di
->
dead
=
1
;
...
...
sql/sql_lex.cc
View file @
ff4a6e13
...
...
@@ -179,6 +179,8 @@ void lex_start(THD *thd, uchar *buf,uint length)
if
(
lex
->
sroutines
.
records
)
my_hash_reset
(
&
lex
->
sroutines
);
lex
->
sroutines_list
.
empty
();
lex
->
sroutines_list_own_last
=
lex
->
sroutines_list
.
next
;
lex
->
sroutines_list_own_elements
=
0
;
DBUG_VOID_RETURN
;
}
...
...
@@ -1613,6 +1615,8 @@ st_lex::st_lex()
{
hash_init
(
&
sroutines
,
system_charset_info
,
0
,
0
,
0
,
sp_sroutine_key
,
0
,
0
);
sroutines_list
.
empty
();
sroutines_list_own_last
=
sroutines_list
.
next
;
sroutines_list_own_elements
=
0
;
}
...
...
@@ -2025,6 +2029,8 @@ void st_lex::cleanup_after_one_table_open()
if
(
sroutines
.
records
)
my_hash_reset
(
&
sroutines
);
sroutines_list
.
empty
();
sroutines_list_own_last
=
sroutines_list
.
next
;
sroutines_list_own_elements
=
0
;
}
...
...
sql/sql_lex.h
View file @
ff4a6e13
...
...
@@ -845,8 +845,15 @@ typedef struct st_lex
/*
List linking elements of 'sroutines' set. Allows you to add new elements
to this set as you iterate through the list of existing elements.
'sroutines_list_own_last' is pointer to ::next member of last element of
this list which represents routine which is explicitly used by query.
'sroutines_list_own_elements' number of explicitly used routines.
We use these two members for restoring of 'sroutines_list' to the state
in which it was right after query parsing.
*/
SQL_LIST
sroutines_list
;
byte
**
sroutines_list_own_last
;
uint
sroutines_list_own_elements
;
st_sp_chistics
sp_chistics
;
bool
only_view
;
/* used for SHOW CREATE TABLE/VIEW */
...
...
@@ -962,6 +969,15 @@ typedef struct st_lex
{
return
(
query_tables_own_last
?
*
query_tables_own_last
:
0
);
}
void
chop_off_not_own_tables
()
{
if
(
query_tables_own_last
)
{
*
query_tables_own_last
=
0
;
query_tables_last
=
query_tables_own_last
;
query_tables_own_last
=
0
;
}
}
void
cleanup_after_one_table_open
();
void
push_context
(
Name_resolution_context
*
context
)
...
...
sql/sql_prepare.cc
View file @
ff4a6e13
...
...
@@ -1103,11 +1103,14 @@ static int mysql_test_update(Prepared_statement *stmt,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint
want_privilege
;
#endif
bool
need_reopen
;
DBUG_ENTER
(
"mysql_test_update"
);
if
(
update_precheck
(
thd
,
table_list
))
goto
error
;
for
(
;
;
)
{
if
(
open_tables
(
thd
,
&
table_list
,
&
table_count
,
0
))
goto
error
;
...
...
@@ -1121,12 +1124,18 @@ static int mysql_test_update(Prepared_statement *stmt,
DBUG_RETURN
(
2
);
}
if
(
!
lock_tables
(
thd
,
table_list
,
table_count
,
&
need_reopen
))
break
;
if
(
!
need_reopen
)
goto
error
;
close_tables_for_reopen
(
thd
,
table_list
);
}
/*
thd->fill_derived_tables() is false here for sure (because it is
preparation of PS, so we even do not check it).
*/
if
(
lock_tables
(
thd
,
table_list
,
table_count
)
||
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
))
if
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
))
goto
error
;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
...
...
sql/sql_table.cc
View file @
ff4a6e13
...
...
@@ -1709,6 +1709,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
List_iterator_fast
<
Item
>
it
(
*
items
);
Item
*
item
;
Field
*
tmp_field
;
bool
not_used
;
DBUG_ENTER
(
"create_table_from_items"
);
tmp_table
.
alias
=
0
;
...
...
@@ -1767,8 +1768,15 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN
(
0
);
}
/*
FIXME: What happens if trigger manages to be created while we are
obtaining this lock ? May be it is sensible just to disable
trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH
save us from that ?
*/
table
->
reginfo
.
lock_type
=
TL_WRITE
;
if
(
!
((
*
lock
)
=
mysql_lock_tables
(
thd
,
&
table
,
1
,
MYSQL_LOCK_IGNORE_FLUSH
)))
if
(
!
((
*
lock
)
=
mysql_lock_tables
(
thd
,
&
table
,
1
,
MYSQL_LOCK_IGNORE_FLUSH
,
&
not_used
)))
{
VOID
(
pthread_mutex_lock
(
&
LOCK_open
));
hash_delete
(
&
open_cache
,(
byte
*
)
table
);
...
...
sql/sql_trigger.cc
View file @
ff4a6e13
...
...
@@ -510,6 +510,25 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
}
/*
Adjust Table_triggers_list with new TABLE pointer.
SYNOPSIS
set_table()
new_table - new pointer to TABLE instance
*/
void
Table_triggers_list
::
set_table
(
TABLE
*
new_table
)
{
table
=
new_table
;
for
(
Field
**
field
=
table
->
triggers
->
record1_field
;
*
field
;
field
++
)
{
(
*
field
)
->
table
=
(
*
field
)
->
orig_table
=
new_table
;
(
*
field
)
->
table_name
=
&
new_table
->
alias
;
}
}
/*
Check whenever .TRG file for table exist and load all triggers it contains.
...
...
sql/sql_trigger.h
View file @
ff4a6e13
...
...
@@ -98,6 +98,8 @@ public:
return
test
(
bodies
[
TRG_EVENT_UPDATE
][
TRG_ACTION_BEFORE
]);
}
void
set_table
(
TABLE
*
new_table
);
friend
class
Item_trigger_field
;
friend
void
sp_cache_routines_and_add_tables_for_triggers
(
THD
*
thd
,
LEX
*
lex
,
Table_triggers_list
*
triggers
);
...
...
sql/sql_update.cc
View file @
ff4a6e13
...
...
@@ -134,10 +134,13 @@ int mysql_update(THD *thd,
SQL_SELECT
*
select
;
READ_RECORD
info
;
SELECT_LEX
*
select_lex
=
&
thd
->
lex
->
select_lex
;
bool
need_reopen
;
DBUG_ENTER
(
"mysql_update"
);
LINT_INIT
(
timestamp_query_id
);
for
(
;
;
)
{
if
(
open_tables
(
thd
,
&
table_list
,
&
table_count
,
0
))
DBUG_RETURN
(
1
);
...
...
@@ -148,11 +151,16 @@ int mysql_update(THD *thd,
/* pass counter value */
thd
->
lex
->
table_count
=
table_count
;
/* convert to multiupdate */
return
2
;
DBUG_RETURN
(
2
);
}
if
(
!
lock_tables
(
thd
,
table_list
,
table_count
,
&
need_reopen
))
break
;
if
(
!
need_reopen
)
DBUG_RETURN
(
1
);
close_tables_for_reopen
(
thd
,
table_list
);
}
if
(
lock_tables
(
thd
,
table_list
,
table_count
)
||
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
if
(
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_prepare
)
||
(
thd
->
fill_derived_tables
()
&&
mysql_handle_derived
(
thd
->
lex
,
&
mysql_derived_filling
)))
DBUG_RETURN
(
1
);
...
...
@@ -616,7 +624,6 @@ static table_map get_table_map(List<Item> *items)
bool
mysql_multi_update_prepare
(
THD
*
thd
)
{
LEX
*
lex
=
thd
->
lex
;
ulong
opened_tables
;
TABLE_LIST
*
table_list
=
lex
->
query_tables
;
TABLE_LIST
*
tl
,
*
leaves
;
List
<
Item
>
*
fields
=
&
lex
->
select_lex
.
item_list
;
...
...
@@ -630,13 +637,16 @@ bool mysql_multi_update_prepare(THD *thd)
uint
table_count
=
lex
->
table_count
;
const
bool
using_lock_tables
=
thd
->
locked_tables
!=
0
;
bool
original_multiupdate
=
(
thd
->
lex
->
sql_command
==
SQLCOM_UPDATE_MULTI
);
bool
need_reopen
=
FALSE
;
DBUG_ENTER
(
"mysql_multi_update_prepare"
);
/* following need for prepared statements, to run next time multi-update */
thd
->
lex
->
sql_command
=
SQLCOM_UPDATE_MULTI
;
reopen_tables:
/* open tables and create derived ones, but do not lock and fill them */
if
((
original_multiupdate
&&
if
((
(
original_multiupdate
||
need_reopen
)
&&
open_tables
(
thd
,
&
table_list
,
&
table_count
,
0
))
||
mysql_handle_derived
(
lex
,
&
mysql_derived_prepare
))
DBUG_RETURN
(
TRUE
);
...
...
@@ -742,20 +752,17 @@ bool mysql_multi_update_prepare(THD *thd)
}
}
opened_tables
=
thd
->
status_var
.
opened_tables
;
/* now lock and fill tables */
if
(
lock_tables
(
thd
,
table_list
,
table_count
))
if
(
lock_tables
(
thd
,
table_list
,
table_count
,
&
need_reopen
))
{
if
(
!
need_reopen
)
DBUG_RETURN
(
TRUE
);
/*
we have to re-call fixfields for fixed items, because lock maybe
reopened tables
*/
if
(
opened_tables
!=
thd
->
status_var
.
opened_tables
)
{
/*
Fields items cleanup(). There are only Item_fields in the list, so we
do not do Item tree walking
We have to reopen tables since some of them were altered or dropped
during lock_tables() or something was done with their triggers.
Let us do some cleanups to be able do setup_table() and setup_fields()
once again.
*/
List_iterator_fast
<
Item
>
it
(
*
fields
);
Item
*
item
;
...
...
@@ -766,12 +773,8 @@ bool mysql_multi_update_prepare(THD *thd)
for
(
TABLE_LIST
*
tbl
=
table_list
;
tbl
;
tbl
=
tbl
->
next_global
)
tbl
->
cleanup_items
();
if
(
setup_tables
(
thd
,
&
lex
->
select_lex
.
context
,
&
lex
->
select_lex
.
top_join_list
,
table_list
,
&
lex
->
select_lex
.
where
,
&
lex
->
select_lex
.
leaf_tables
,
FALSE
)
||
setup_fields_with_no_wrap
(
thd
,
0
,
*
fields
,
1
,
0
,
0
))
DBUG_RETURN
(
TRUE
);
close_tables_for_reopen
(
thd
,
table_list
);
goto
reopen_tables
;
}
/*
...
...
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