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
f10effe4
Commit
f10effe4
authored
May 16, 2007
by
kostja@vajra.(none)
Browse files
Options
Browse Files
Download
Plain Diff
Merge bk-internal.mysql.com:/home/bk/mysql-5.0-runtime
into vajra.(none):/opt/local/work/mysql-5.0-21483
parents
35616ba5
747842e1
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
436 additions
and
77 deletions
+436
-77
mysql-test/r/insert.result
mysql-test/r/insert.result
+116
-0
mysql-test/t/insert.test
mysql-test/t/insert.test
+139
-0
sql/sp_head.cc
sql/sp_head.cc
+8
-0
sql/sql_base.cc
sql/sql_base.cc
+2
-2
sql/sql_insert.cc
sql/sql_insert.cc
+165
-75
sql/sql_lex.h
sql/sql_lex.h
+6
-0
No files found.
mysql-test/r/insert.result
View file @
f10effe4
...
@@ -346,3 +346,119 @@ f1 f2
...
@@ -346,3 +346,119 @@ f1 f2
12 NULL
12 NULL
drop view v1;
drop view v1;
drop table t1,t2;
drop table t1,t2;
DROP TABLE IF EXISTS t1;
DROP FUNCTION IF EXISTS f1;
DROP FUNCTION IF EXISTS f2;
CREATE TABLE t1 (i INT);
CREATE FUNCTION f1() RETURNS INT
BEGIN
INSERT INTO t1 VALUES (1);
RETURN 1;
END |
CREATE FUNCTION f2() RETURNS INT
BEGIN
INSERT DELAYED INTO t1 VALUES (2);
RETURN 1;
END |
SELECT f1();
f1()
1
SELECT f2();
f2()
1
INSERT INTO t1 VALUES (3);
INSERT DELAYED INTO t1 VALUES (4);
INSERT INTO t1 VALUES (f1());
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
INSERT DELAYED INTO t1 VALUES (f1());
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
INSERT INTO t1 VALUES (f2());
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
INSERT DELAYED INTO t1 VALUES (f2());
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
INSERT INTO t1 VALUES (NEW.i);
INSERT INTO t1 VALUES (1);
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
INSERT DELAYED INTO t1 VALUES (1);
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
SELECT * FROM t1;
i
1
2
3
4
DROP FUNCTION f2;
DROP FUNCTION f1;
DROP TABLE t1;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (i INT);
CREATE TABLE t2 (i INT);
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
INSERT DELAYED INTO t2 VALUES (NEW.i);
CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW
INSERT DELAYED INTO t2 VALUES (NEW.i);
CREATE TRIGGER t1_bd BEFORE DELETE ON t1 FOR EACH ROW
INSERT DELAYED INTO t2 VALUES (OLD.i);
INSERT INTO t1 VALUES (1);
INSERT DELAYED INTO t1 VALUES (2);
SELECT * FROM t1;
i
1
2
UPDATE t1 SET i = 3 WHERE i = 1;
SELECT * FROM t1;
i
3
2
DELETE FROM t1 WHERE i = 3;
SELECT * FROM t1;
i
2
SELECT * FROM t2;
i
1
2
3
3
DROP TABLE t1, t2;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (i INT);
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
SET @a= NEW.i;
SET @a= 0;
INSERT DELAYED INTO t1 VALUES (1);
SELECT @a;
@a
1
INSERT DELAYED INTO t1 VALUES (2);
SELECT @a;
@a
2
DROP TABLE t1;
CREATE TABLE t1 (i INT);
CREATE TABLE t2 (i INT);
CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW
INSERT INTO t2 VALUES (NEW.i);
CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW
INSERT DELAYED INTO t2 VALUES (NEW.i);
CREATE TRIGGER t1_ad AFTER DELETE ON t1 FOR EACH ROW
INSERT DELAYED INTO t2 VALUES (OLD.i);
INSERT DELAYED INTO t1 VALUES (1);
SELECT * FROM t1;
i
1
UPDATE t1 SET i = 2 WHERE i = 1;
SELECT * FROM t1;
i
2
DELETE FROM t1 WHERE i = 2;
SELECT * FROM t1;
i
SELECT * FROM t2;
i
1
2
2
DROP TABLE t1, t2;
End of 5.0 tests.
mysql-test/t/insert.test
View file @
f10effe4
...
@@ -216,3 +216,142 @@ select * from t1;
...
@@ -216,3 +216,142 @@ select * from t1;
drop
view
v1
;
drop
view
v1
;
drop
table
t1
,
t2
;
drop
table
t1
,
t2
;
#
# BUG#21483: Server abort or deadlock on INSERT DELAYED with another
# implicit insert
#
# The solution is to downgrade INSERT DELAYED to normal INSERT if the
# statement uses functions and access tables or triggers, or is called
# from a function or a trigger.
#
--
disable_warnings
DROP
TABLE
IF
EXISTS
t1
;
DROP
FUNCTION
IF
EXISTS
f1
;
DROP
FUNCTION
IF
EXISTS
f2
;
--
enable_warnings
CREATE
TABLE
t1
(
i
INT
);
delimiter
|
;
CREATE
FUNCTION
f1
()
RETURNS
INT
BEGIN
INSERT
INTO
t1
VALUES
(
1
);
RETURN
1
;
END
|
CREATE
FUNCTION
f2
()
RETURNS
INT
BEGIN
INSERT
DELAYED
INTO
t1
VALUES
(
2
);
RETURN
1
;
END
|
delimiter
;
|
SELECT
f1
();
SELECT
f2
();
INSERT
INTO
t1
VALUES
(
3
);
INSERT
DELAYED
INTO
t1
VALUES
(
4
);
--
error
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
INSERT
INTO
t1
VALUES
(
f1
());
--
error
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
INSERT
DELAYED
INTO
t1
VALUES
(
f1
());
--
error
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
INSERT
INTO
t1
VALUES
(
f2
());
--
error
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
INSERT
DELAYED
INTO
t1
VALUES
(
f2
());
CREATE
TRIGGER
t1_bi
BEFORE
INSERT
ON
t1
FOR
EACH
ROW
INSERT
INTO
t1
VALUES
(
NEW
.
i
);
--
error
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
INSERT
INTO
t1
VALUES
(
1
);
--
error
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
INSERT
DELAYED
INTO
t1
VALUES
(
1
);
SELECT
*
FROM
t1
;
DROP
FUNCTION
f2
;
DROP
FUNCTION
f1
;
DROP
TABLE
t1
;
#
# BUG#20497: Trigger with INSERT DELAYED causes Error 1165
#
# Fixed by the patch for Bug#21483
#
--
disable_warnings
DROP
TABLE
IF
EXISTS
t1
,
t2
;
--
enable_warnings
CREATE
TABLE
t1
(
i
INT
);
CREATE
TABLE
t2
(
i
INT
);
CREATE
TRIGGER
t1_bi
BEFORE
INSERT
ON
t1
FOR
EACH
ROW
INSERT
DELAYED
INTO
t2
VALUES
(
NEW
.
i
);
CREATE
TRIGGER
t1_bu
BEFORE
UPDATE
ON
t1
FOR
EACH
ROW
INSERT
DELAYED
INTO
t2
VALUES
(
NEW
.
i
);
CREATE
TRIGGER
t1_bd
BEFORE
DELETE
ON
t1
FOR
EACH
ROW
INSERT
DELAYED
INTO
t2
VALUES
(
OLD
.
i
);
INSERT
INTO
t1
VALUES
(
1
);
INSERT
DELAYED
INTO
t1
VALUES
(
2
);
SELECT
*
FROM
t1
;
UPDATE
t1
SET
i
=
3
WHERE
i
=
1
;
SELECT
*
FROM
t1
;
DELETE
FROM
t1
WHERE
i
=
3
;
SELECT
*
FROM
t1
;
SELECT
*
FROM
t2
;
DROP
TABLE
t1
,
t2
;
#
# BUG#21714: Wrong NEW.value and server abort on INSERT DELAYED to a
# table with a trigger
#
# Fixed by the patch for Bug#21483
#
--
disable_warnings
DROP
TABLE
IF
EXISTS
t1
,
t2
;
--
enable_warnings
CREATE
TABLE
t1
(
i
INT
);
CREATE
TRIGGER
t1_bi
BEFORE
INSERT
ON
t1
FOR
EACH
ROW
SET
@
a
=
NEW
.
i
;
SET
@
a
=
0
;
INSERT
DELAYED
INTO
t1
VALUES
(
1
);
SELECT
@
a
;
INSERT
DELAYED
INTO
t1
VALUES
(
2
);
SELECT
@
a
;
DROP
TABLE
t1
;
CREATE
TABLE
t1
(
i
INT
);
CREATE
TABLE
t2
(
i
INT
);
CREATE
TRIGGER
t1_ai
AFTER
INSERT
ON
t1
FOR
EACH
ROW
INSERT
INTO
t2
VALUES
(
NEW
.
i
);
CREATE
TRIGGER
t1_au
AFTER
UPDATE
ON
t1
FOR
EACH
ROW
INSERT
DELAYED
INTO
t2
VALUES
(
NEW
.
i
);
CREATE
TRIGGER
t1_ad
AFTER
DELETE
ON
t1
FOR
EACH
ROW
INSERT
DELAYED
INTO
t2
VALUES
(
OLD
.
i
);
INSERT
DELAYED
INTO
t1
VALUES
(
1
);
SELECT
*
FROM
t1
;
UPDATE
t1
SET
i
=
2
WHERE
i
=
1
;
SELECT
*
FROM
t1
;
DELETE
FROM
t1
WHERE
i
=
2
;
SELECT
*
FROM
t1
;
SELECT
*
FROM
t2
;
DROP
TABLE
t1
,
t2
;
--
echo
End
of
5.0
tests
.
sql/sp_head.cc
View file @
f10effe4
...
@@ -3489,6 +3489,14 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
...
@@ -3489,6 +3489,14 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
tlen
+=
alen
;
tlen
+=
alen
;
tname
[
tlen
]
=
'\0'
;
tname
[
tlen
]
=
'\0'
;
/*
Upgrade the lock type because this table list will be used
only in pre-locked mode, in which DELAYED inserts are always
converted to normal inserts.
*/
if
(
table
->
lock_type
==
TL_WRITE_DELAYED
)
table
->
lock_type
=
TL_WRITE
;
/*
/*
We ignore alias when we check if table was already marked as temporary
We ignore alias when we check if table was already marked as temporary
(and therefore should not be prelocked). Otherwise we will erroneously
(and therefore should not be prelocked). Otherwise we will erroneously
...
...
sql/sql_base.cc
View file @
f10effe4
...
@@ -2633,7 +2633,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
...
@@ -2633,7 +2633,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
*/
*/
if
(
!
thd
->
prelocked_mode
&&
!
thd
->
lex
->
requires_prelocking
()
&&
if
(
!
thd
->
prelocked_mode
&&
!
thd
->
lex
->
requires_prelocking
()
&&
thd
->
lex
->
sroutines_list
.
elements
)
thd
->
lex
->
uses_stored_routines
()
)
{
{
bool
first_no_prelocking
,
need_prelocking
,
tabs_changed
;
bool
first_no_prelocking
,
need_prelocking
,
tabs_changed
;
TABLE_LIST
**
save_query_tables_last
=
thd
->
lex
->
query_tables_last
;
TABLE_LIST
**
save_query_tables_last
=
thd
->
lex
->
query_tables_last
;
...
@@ -2821,7 +2821,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
...
@@ -2821,7 +2821,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
*/
*/
if
(
tables
->
view
&&
!
thd
->
prelocked_mode
&&
if
(
tables
->
view
&&
!
thd
->
prelocked_mode
&&
!
thd
->
lex
->
requires_prelocking
()
&&
!
thd
->
lex
->
requires_prelocking
()
&&
tables
->
view
->
sroutines_list
.
elements
)
tables
->
view
->
uses_stored_routines
()
)
{
{
/* We have at least one table in TL here. */
/* We have at least one table in TL here. */
if
(
!
query_tables_last_own
)
if
(
!
query_tables_last_own
)
...
...
sql/sql_insert.cc
View file @
f10effe4
...
@@ -61,7 +61,7 @@
...
@@ -61,7 +61,7 @@
#include "slave.h"
#include "slave.h"
#ifndef EMBEDDED_LIBRARY
#ifndef EMBEDDED_LIBRARY
static
TABLE
*
delayed_get_table
(
THD
*
thd
,
TABLE_LIST
*
table_list
);
static
bool
delayed_get_table
(
THD
*
thd
,
TABLE_LIST
*
table_list
);
static
int
write_delayed
(
THD
*
thd
,
TABLE
*
table
,
enum_duplicates
dup
,
bool
ignore
,
static
int
write_delayed
(
THD
*
thd
,
TABLE
*
table
,
enum_duplicates
dup
,
bool
ignore
,
char
*
query
,
uint
query_length
,
bool
log_on
);
char
*
query
,
uint
query_length
,
bool
log_on
);
static
void
end_delayed_insert
(
THD
*
thd
);
static
void
end_delayed_insert
(
THD
*
thd
);
...
@@ -409,6 +409,7 @@ void mark_fields_used_by_triggers_for_insert_stmt(THD *thd, TABLE *table,
...
@@ -409,6 +409,7 @@ void mark_fields_used_by_triggers_for_insert_stmt(THD *thd, TABLE *table,
downgrade the lock in handler::store_lock() method.
downgrade the lock in handler::store_lock() method.
*/
*/
static
void
upgrade_lock_type
(
THD
*
thd
,
thr_lock_type
*
lock_type
,
void
upgrade_lock_type
(
THD
*
thd
,
thr_lock_type
*
lock_type
,
enum_duplicates
duplic
,
enum_duplicates
duplic
,
bool
is_multi_insert
)
bool
is_multi_insert
)
...
@@ -422,29 +423,37 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
...
@@ -422,29 +423,37 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
if
(
*
lock_type
==
TL_WRITE_DELAYED
)
if
(
*
lock_type
==
TL_WRITE_DELAYED
)
{
{
#ifdef EMBEDDED_LIBRARY
/* No auxiliary threads in the embedded server. */
*
lock_type
=
TL_WRITE
;
return
;
#else
/*
/*
We do not use delayed threads if:
We do not use delayed threads if:
- we're running in the safe mode or skip-new
- the featur
e
- we're running in the safe mode or skip-new
mode -- th
e
is disabled in these modes
feature
is disabled in these modes
- we're
running this query in statement level replication,
- we're
executing this statement on a replication slave --
on a replication slave - because we must ensure serial
we need to ensure serial execution of queries on the
execution of queries on the
slave
slave
- it is INSERT .. ON DUPLICATE KEY UPDATE - in this case the
- it is INSERT .. ON DUPLICATE KEY UPDATE - in this case the
insert cannot be concurrent
insert cannot be concurrent
- this statement is directly or indirectly invoked from
a stored function or trigger (under pre-locking) - to
avoid deadlocks, since INSERT DELAYED involves a lock
upgrade (TL_WRITE_DELAYED -> TL_WRITE) which we should not
attempt while keeping other table level locks.
- this statement itself may require pre-locking.
We should upgrade the lock even though in most cases
delayed functionality may work. Unfortunately, we can't
easily identify whether the subject table is not used in
the statement indirectly via a stored function or trigger:
if it is used, that will lead to a deadlock between the
client connection and the delayed thread.
*/
*/
if
(
specialflag
&
(
SPECIAL_NO_NEW_FUNC
|
SPECIAL_SAFE_MODE
)
||
if
(
specialflag
&
(
SPECIAL_NO_NEW_FUNC
|
SPECIAL_SAFE_MODE
)
||
thd
->
slave_thread
||
thd
->
slave_thread
||
thd
->
variables
.
max_insert_delayed_threads
==
0
)
thd
->
variables
.
max_insert_delayed_threads
==
0
||
thd
->
prelocked_mode
||
thd
->
lex
->
uses_stored_routines
())
{
{
*
lock_type
=
TL_WRITE
;
*
lock_type
=
TL_WRITE
;
return
;
return
;
}
}
#endif
bool
log_on
=
(
thd
->
options
&
OPTION_BIN_LOG
||
bool
log_on
=
(
thd
->
options
&
OPTION_BIN_LOG
||
!
(
thd
->
security_ctx
->
master_access
&
SUPER_ACL
));
!
(
thd
->
security_ctx
->
master_access
&
SUPER_ACL
));
if
(
log_on
&&
mysql_bin_log
.
is_open
()
&&
is_multi_insert
)
if
(
log_on
&&
mysql_bin_log
.
is_open
()
&&
is_multi_insert
)
...
@@ -470,6 +479,72 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
...
@@ -470,6 +479,72 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
}
}
/**
Find or create a delayed insert thread for the first table in
the table list, then open and lock the remaining tables.
If a table can not be used with insert delayed, upgrade the lock
and open and lock all tables using the standard mechanism.
@param thd thread context
@param table_list list of "descriptors" for tables referenced
directly in statement SQL text.
The first element in the list corresponds to
the destination table for inserts, remaining
tables, if any, are usually tables referenced
by sub-queries in the right part of the
INSERT.
@return Status of the operation. In case of success 'table'
member of every table_list element points to an instance of
class TABLE.
@sa open_and_lock_tables for more information about MySQL table
level locking
*/
static
bool
open_and_lock_for_insert_delayed
(
THD
*
thd
,
TABLE_LIST
*
table_list
)
{
DBUG_ENTER
(
"open_and_lock_for_insert_delayed"
);
#ifndef EMBEDDED_LIBRARY
if
(
delayed_get_table
(
thd
,
table_list
))
DBUG_RETURN
(
TRUE
);
if
(
table_list
->
table
)
{
/*
Open tables used for sub-selects or in stored functions, will also
cache these functions.
*/
if
(
open_and_lock_tables
(
thd
,
table_list
->
next_global
))
{
end_delayed_insert
(
thd
);
DBUG_RETURN
(
TRUE
);
}
/*
First table was not processed by open_and_lock_tables(),
we need to set updatability flag "by hand".
*/
if
(
!
table_list
->
derived
&&
!
table_list
->
view
)
table_list
->
updatable
=
1
;
// usual table
DBUG_RETURN
(
FALSE
);
}
#endif
/*
* This is embedded library and we don't have auxiliary
threads OR
* a lock upgrade was requested inside delayed_get_table
because
- there are too many delayed insert threads OR
- the table has triggers.
Use a normal insert.
*/
table_list
->
lock_type
=
TL_WRITE
;
DBUG_RETURN
(
open_and_lock_tables
(
thd
,
table_list
));
}
/**
/**
INSERT statement implementation
INSERT statement implementation
*/
*/
...
@@ -514,7 +589,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
...
@@ -514,7 +589,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
*/
*/
upgrade_lock_type
(
thd
,
&
table_list
->
lock_type
,
duplic
,
upgrade_lock_type
(
thd
,
&
table_list
->
lock_type
,
duplic
,
values_list
.
elements
>
1
);
values_list
.
elements
>
1
);
lock_type
=
table_list
->
lock_type
;
/*
/*
We can't write-delayed into a table locked with LOCK TABLES:
We can't write-delayed into a table locked with LOCK TABLES:
...
@@ -522,7 +596,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
...
@@ -522,7 +596,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
never be able to get a lock on the table. QQQ: why not
never be able to get a lock on the table. QQQ: why not
upgrade the lock here instead?
upgrade the lock here instead?
*/
*/
if
(
lock_type
==
TL_WRITE_DELAYED
&&
thd
->
locked_tables
&&
if
(
table_list
->
lock_type
==
TL_WRITE_DELAYED
&&
thd
->
locked_tables
&&
find_locked_table
(
thd
,
table_list
->
db
,
table_list
->
table_name
))
find_locked_table
(
thd
,
table_list
->
db
,
table_list
->
table_name
))
{
{
my_error
(
ER_DELAYED_INSERT_TABLE_LOCKED
,
MYF
(
0
),
my_error
(
ER_DELAYED_INSERT_TABLE_LOCKED
,
MYF
(
0
),
...
@@ -530,36 +604,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
...
@@ -530,36 +604,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
TRUE
);
}
}
#ifndef EMBEDDED_LIBRARY
if
(
table_list
->
lock_type
==
TL_WRITE_DELAYED
)
if
(
lock_type
==
TL_WRITE_DELAYED
)
{
{
res
=
1
;
if
(
open_and_lock_for_insert_delayed
(
thd
,
table_list
))
if
((
table
=
delayed_get_table
(
thd
,
table_list
))
&&
!
thd
->
is_fatal_error
)
DBUG_RETURN
(
TRUE
);
{
/*
Open tables used for sub-selects or in stored functions, will also
cache these functions.
*/
res
=
open_and_lock_tables
(
thd
,
table_list
->
next_global
);
/*
First is not processed by open_and_lock_tables() => we need set
updateability flags "by hands".
*/
if
(
!
table_list
->
derived
&&
!
table_list
->
view
)
table_list
->
updatable
=
1
;
// usual table
}
else
if
(
thd
->
net
.
last_errno
!=
ER_WRONG_OBJECT
)
{
/* Too many delayed insert threads; Use a normal insert */
table_list
->
lock_type
=
lock_type
=
TL_WRITE
;
res
=
open_and_lock_tables
(
thd
,
table_list
);
}
}
}
else
else
#endif
/* EMBEDDED_LIBRARY */
{
res
=
open_and_lock_tables
(
thd
,
table_list
);
if
(
open_and_lock_tables
(
thd
,
table_list
))
if
(
res
||
thd
->
is_fatal_error
)
DBUG_RETURN
(
TRUE
);
DBUG_RETURN
(
TRUE
);
}
thd
->
proc_info
=
"init"
;
thd
->
proc_info
=
"init"
;
thd
->
used_tables
=
0
;
thd
->
used_tables
=
0
;
...
@@ -577,6 +631,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
...
@@ -577,6 +631,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
/* mysql_prepare_insert set table_list->table if it was not set */
/* mysql_prepare_insert set table_list->table if it was not set */
table
=
table_list
->
table
;
table
=
table_list
->
table
;
lock_type
=
table_list
->
lock_type
;
context
=
&
thd
->
lex
->
select_lex
.
context
;
context
=
&
thd
->
lex
->
select_lex
.
context
;
/*
/*
...
@@ -1634,19 +1689,32 @@ Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
...
@@ -1634,19 +1689,32 @@ Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
Attempt to find or create a delayed insert thread to handle inserts
Attempt to find or create a delayed insert thread to handle inserts
into this table.
into this table.
@return Return a local copy of the table in the delayed thread
@return In case of success, table_list->table points to a local copy
@retval NULL too many delayed threads OR
of the delayed table or is set to NULL, which indicates a
this thread ran out of resources OR
request for lock upgrade. In case of failure, value of
a newly created delayed insert thread ran out of resources OR
table_list->table is undefined.
the delayed insert thread failed to open the table.
@retval TRUE - this thread ran out of resources OR
In the last three cases an error is set in THD.
- a newly created delayed insert thread ran out of
resources OR
- the created thread failed to open and lock the table
(e.g. because it does not exist) OR
- the table opened in the created thread turned out to
be a view
@retval FALSE - table successfully opened OR
- too many delayed insert threads OR
- the table has triggers and we have to fall back to
a normal INSERT
Two latter cases indicate a request for lock upgrade.
XXX: why do we regard INSERT DELAYED into a view as an error and
do not simply a lock upgrade?
*/
*/
static
TABLE
*
delayed_get_table
(
THD
*
thd
,
TABLE_LIST
*
table_list
)
static
bool
delayed_get_table
(
THD
*
thd
,
TABLE_LIST
*
table_list
)
{
{
int
error
;
int
error
;
Delayed_insert
*
tmp
;
Delayed_insert
*
tmp
;
TABLE
*
table
;
DBUG_ENTER
(
"delayed_get_table"
);
DBUG_ENTER
(
"delayed_get_table"
);
/* Must be set in the parser */
/* Must be set in the parser */
...
@@ -1672,7 +1740,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
...
@@ -1672,7 +1740,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
if
(
!
(
tmp
=
new
Delayed_insert
()))
if
(
!
(
tmp
=
new
Delayed_insert
()))
{
{
my_error
(
ER_OUTOFMEMORY
,
MYF
(
0
),
sizeof
(
Delayed_insert
));
my_error
(
ER_OUTOFMEMORY
,
MYF
(
0
),
sizeof
(
Delayed_insert
));
goto
err1
;
thd
->
fatal_error
();
goto
end_create
;
}
}
pthread_mutex_lock
(
&
LOCK_thread_count
);
pthread_mutex_lock
(
&
LOCK_thread_count
);
thread_count
++
;
thread_count
++
;
...
@@ -1681,9 +1750,10 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
...
@@ -1681,9 +1750,10 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
tmp
->
thd
.
query
=
my_strdup
(
table_list
->
table_name
,
MYF
(
MY_WME
));
tmp
->
thd
.
query
=
my_strdup
(
table_list
->
table_name
,
MYF
(
MY_WME
));
if
(
tmp
->
thd
.
db
==
NULL
||
tmp
->
thd
.
query
==
NULL
)
if
(
tmp
->
thd
.
db
==
NULL
||
tmp
->
thd
.
query
==
NULL
)
{
{
/* The error is reported */
delete
tmp
;
delete
tmp
;
my_message
(
ER_OUT_OF_RESOURCES
,
ER
(
ER_OUT_OF_RESOURCES
),
MYF
(
0
)
);
thd
->
fatal_error
(
);
goto
err1
;
goto
end_create
;
}
}
tmp
->
table_list
=
*
table_list
;
// Needed to open table
tmp
->
table_list
=
*
table_list
;
// Needed to open table
tmp
->
table_list
.
alias
=
tmp
->
table_list
.
table_name
=
tmp
->
thd
.
query
;
tmp
->
table_list
.
alias
=
tmp
->
table_list
.
table_name
=
tmp
->
thd
.
query
;
...
@@ -1699,7 +1769,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
...
@@ -1699,7 +1769,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
tmp
->
unlock
();
tmp
->
unlock
();
delete
tmp
;
delete
tmp
;
my_error
(
ER_CANT_CREATE_THREAD
,
MYF
(
0
),
error
);
my_error
(
ER_CANT_CREATE_THREAD
,
MYF
(
0
),
error
);
goto
err1
;
thd
->
fatal_error
();
goto
end_create
;
}
}
/* Wait until table is open */
/* Wait until table is open */
...
@@ -1712,41 +1783,44 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
...
@@ -1712,41 +1783,44 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
thd
->
proc_info
=
"got old table"
;
thd
->
proc_info
=
"got old table"
;
if
(
tmp
->
thd
.
killed
)
if
(
tmp
->
thd
.
killed
)
{
{
if
(
tmp
->
thd
.
is_fatal
_error
)
if
(
tmp
->
thd
.
net
.
report
_error
)
{
{
/* Copy error message and abort */
/*
thd
->
fatal_error
();
Copy the error message. Note that we don't treat fatal
strmov
(
thd
->
net
.
last_error
,
tmp
->
thd
.
net
.
last_error
);
errors in the delayed thread as fatal errors in the
thd
->
net
.
last_errno
=
tmp
->
thd
.
net
.
last_errno
;
main thread. Use of my_message will enable stored
procedures continue handlers.
*/
my_message
(
tmp
->
thd
.
net
.
last_errno
,
tmp
->
thd
.
net
.
last_error
,
MYF
(
0
));
}
}
tmp
->
unlock
();
tmp
->
unlock
();
goto
err
;
goto
end_create
;
}
}
if
(
thd
->
killed
)
if
(
thd
->
killed
)
{
{
tmp
->
unlock
();
tmp
->
unlock
();
goto
err
;
goto
end_create
;
}
}
}
}
pthread_mutex_unlock
(
&
LOCK_delayed_create
);
pthread_mutex_unlock
(
&
LOCK_delayed_create
);
}
}
pthread_mutex_lock
(
&
tmp
->
mutex
);
pthread_mutex_lock
(
&
tmp
->
mutex
);
table
=
tmp
->
get_local_table
(
thd
);
table
_list
->
table
=
tmp
->
get_local_table
(
thd
);
pthread_mutex_unlock
(
&
tmp
->
mutex
);
pthread_mutex_unlock
(
&
tmp
->
mutex
);
if
(
table
)
if
(
table_list
->
table
)
{
DBUG_ASSERT
(
tmp
->
thd
.
net
.
report_error
==
0
&&
thd
->
net
.
report_error
==
0
);
thd
->
di
=
tmp
;
thd
->
di
=
tmp
;
else
if
(
tmp
->
thd
.
is_fatal_error
)
}
thd
->
fatal_error
();
/* Unlock the delayed insert object after its last access. */
/* Unlock the delayed insert object after its last access. */
tmp
->
unlock
();
tmp
->
unlock
();
DBUG_RETURN
(
(
table_list
->
table
=
table
)
);
DBUG_RETURN
(
table_list
->
table
==
NULL
);
err1:
end_create:
thd
->
fatal_error
();
err:
pthread_mutex_unlock
(
&
LOCK_delayed_create
);
pthread_mutex_unlock
(
&
LOCK_delayed_create
);
DBUG_RETURN
(
0
);
// Continue with normal insert
DBUG_RETURN
(
thd
->
net
.
report_error
);
}
}
...
@@ -1761,6 +1835,9 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
...
@@ -1761,6 +1835,9 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
@pre This function is called from the client thread. Delayed
@pre This function is called from the client thread. Delayed
insert thread mutex must be acquired before invoking this
insert thread mutex must be acquired before invoking this
function.
function.
@return Not-NULL table object on success. NULL in case of an error,
which is set in client_thd.
*/
*/
TABLE
*
Delayed_insert
::
get_local_table
(
THD
*
client_thd
)
TABLE
*
Delayed_insert
::
get_local_table
(
THD
*
client_thd
)
...
@@ -1786,8 +1863,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
...
@@ -1786,8 +1863,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
goto
error
;
goto
error
;
if
(
dead
)
if
(
dead
)
{
{
strmov
(
client_thd
->
net
.
last_error
,
thd
.
net
.
last_error
);
my_message
(
thd
.
net
.
last_errno
,
thd
.
net
.
last_error
,
MYF
(
0
));
client_thd
->
net
.
last_errno
=
thd
.
net
.
last_errno
;
goto
error
;
goto
error
;
}
}
}
}
...
@@ -1832,7 +1908,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
...
@@ -1832,7 +1908,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
for
(
org_field
=
table
->
field
;
*
org_field
;
org_field
++
,
field
++
)
for
(
org_field
=
table
->
field
;
*
org_field
;
org_field
++
,
field
++
)
{
{
if
(
!
(
*
field
=
(
*
org_field
)
->
new_field
(
client_thd
->
mem_root
,
copy
,
1
)))
if
(
!
(
*
field
=
(
*
org_field
)
->
new_field
(
client_thd
->
mem_root
,
copy
,
1
)))
DBUG_RETURN
(
0
)
;
goto
error
;
(
*
field
)
->
orig_table
=
copy
;
// Remove connection
(
*
field
)
->
orig_table
=
copy
;
// Remove connection
(
*
field
)
->
move_field
(
adjust_ptrs
);
// Point at copy->record[0]
(
*
field
)
->
move_field
(
adjust_ptrs
);
// Point at copy->record[0]
if
(
*
org_field
==
found_next_number_field
)
if
(
*
org_field
==
found_next_number_field
)
...
@@ -1872,8 +1948,9 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
...
@@ -1872,8 +1948,9 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
/* Put a question in queue */
/* Put a question in queue */
static
int
write_delayed
(
THD
*
thd
,
TABLE
*
table
,
enum_duplicates
duplic
,
bool
ignore
,
static
char
*
query
,
uint
query_length
,
bool
log_on
)
int
write_delayed
(
THD
*
thd
,
TABLE
*
table
,
enum_duplicates
duplic
,
bool
ignore
,
char
*
query
,
uint
query_length
,
bool
log_on
)
{
{
delayed_row
*
row
=
0
;
delayed_row
*
row
=
0
;
Delayed_insert
*
di
=
thd
->
di
;
Delayed_insert
*
di
=
thd
->
di
;
...
@@ -1940,6 +2017,10 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool igno
...
@@ -1940,6 +2017,10 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool igno
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
}
}
/**
Signal the delayed insert thread that this user connection
is finished using it for this statement.
*/
static
void
end_delayed_insert
(
THD
*
thd
)
static
void
end_delayed_insert
(
THD
*
thd
)
{
{
...
@@ -2052,6 +2133,15 @@ pthread_handler_t handle_delayed_insert(void *arg)
...
@@ -2052,6 +2133,15 @@ pthread_handler_t handle_delayed_insert(void *arg)
my_error
(
ER_ILLEGAL_HA
,
MYF
(
0
),
di
->
table_list
.
table_name
);
my_error
(
ER_ILLEGAL_HA
,
MYF
(
0
),
di
->
table_list
.
table_name
);
goto
end
;
goto
end
;
}
}
if
(
di
->
table
->
triggers
)
{
/*
Table has triggers. This is not an error, but we do
not support triggers with delayed insert. Terminate the delayed
thread without an error and thus request lock upgrade.
*/
goto
end
;
}
di
->
table
->
copy_blobs
=
1
;
di
->
table
->
copy_blobs
=
1
;
/* One can now use this */
/* One can now use this */
...
...
sql/sql_lex.h
View file @
f10effe4
...
@@ -886,6 +886,12 @@ class Query_tables_list
...
@@ -886,6 +886,12 @@ class Query_tables_list
query_tables_own_last
=
0
;
query_tables_own_last
=
0
;
}
}
}
}
/**
true if the parsed tree contains references to stored procedures
or functions, false otherwise
*/
bool
uses_stored_routines
()
const
{
return
sroutines_list
.
elements
!=
0
;
}
};
};
...
...
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