Commit 966e3df3 authored by unknown's avatar unknown

Merge ramayana.hindu.god:/home/tsmith/m/bk/50

into  ramayana.hindu.god:/home/tsmith/m/bk/maint/50

parents 89cca4b3 fb9a562b
...@@ -72,10 +72,7 @@ int hp_rb_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, ...@@ -72,10 +72,7 @@ int hp_rb_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
int res; int res;
if (flag) if (flag)
{
info->last_pos= NULL; /* For heap_rnext/heap_rprev */ info->last_pos= NULL; /* For heap_rnext/heap_rprev */
info->lastkey_len= 0;
}
custom_arg.keyseg= keyinfo->seg; custom_arg.keyseg= keyinfo->seg;
custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos); custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
......
...@@ -35,6 +35,17 @@ int heap_rfirst(HP_INFO *info, byte *record, int inx) ...@@ -35,6 +35,17 @@ int heap_rfirst(HP_INFO *info, byte *record, int inx)
sizeof(byte*)); sizeof(byte*));
info->current_ptr = pos; info->current_ptr = pos;
memcpy(record, pos, (size_t)share->reclength); memcpy(record, pos, (size_t)share->reclength);
/*
If we're performing index_first on a table that was taken from
table cache, info->lastkey_len is initialized to previous query.
Thus we set info->lastkey_len to proper value for subsequent
heap_rnext() calls.
This is needed for DELETE queries only, otherwise this variable is
not used.
Note that the same workaround may be needed for heap_rlast(), but
for now heap_rlast() is never used for DELETE queries.
*/
info->lastkey_len= 0;
info->update = HA_STATE_AKTIV; info->update = HA_STATE_AKTIV;
} }
else else
......
...@@ -33,11 +33,40 @@ int heap_rnext(HP_INFO *info, byte *record) ...@@ -33,11 +33,40 @@ int heap_rnext(HP_INFO *info, byte *record)
heap_rb_param custom_arg; heap_rb_param custom_arg;
if (info->last_pos) if (info->last_pos)
{
/*
We enter this branch for non-DELETE queries after heap_rkey()
or heap_rfirst(). As last key position (info->last_pos) is available,
we only need to climb the tree using tree_search_next().
*/
pos = tree_search_next(&keyinfo->rb_tree, &info->last_pos, pos = tree_search_next(&keyinfo->rb_tree, &info->last_pos,
offsetof(TREE_ELEMENT, left), offsetof(TREE_ELEMENT, left),
offsetof(TREE_ELEMENT, right)); offsetof(TREE_ELEMENT, right));
}
else if (!info->lastkey_len)
{
/*
We enter this branch only for DELETE queries after heap_rfirst(). E.g.
DELETE FROM t1 WHERE a<10. As last key position is not available
(last key is removed by heap_delete()), we must restart search as it
is done in heap_rfirst().
It should be safe to handle this situation without this branch. That is
branch below should find smallest element in a tree as lastkey_len is
zero. tree_search_edge() is a kind of optimisation here as it should be
faster than tree_search_key().
*/
pos= tree_search_edge(&keyinfo->rb_tree, info->parents,
&info->last_pos, offsetof(TREE_ELEMENT, left));
}
else else
{ {
/*
We enter this branch only for DELETE queries after heap_rkey(). E.g.
DELETE FROM t1 WHERE a=10. As last key position is not available
(last key is removed by heap_delete()), we must restart search as it
is done in heap_rkey().
*/
custom_arg.keyseg = keyinfo->seg; custom_arg.keyseg = keyinfo->seg;
custom_arg.key_length = info->lastkey_len; custom_arg.key_length = info->lastkey_len;
custom_arg.search_flag = SEARCH_SAME | SEARCH_FIND; custom_arg.search_flag = SEARCH_SAME | SEARCH_FIND;
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
/* We have to do this define before including windows.h to get the AWE API /* We have to do this define before including windows.h to get the AWE API
functions */ functions */
#define _WIN32_WINNT 0x0500 #define _WIN32_WINNT 0x0500
#else
/* Get NT 4.0 functions */
#define _WIN32_WINNT 0x0400
#endif #endif
#if defined(_MSC_VER) && _MSC_VER >= 1400 #if defined(_MSC_VER) && _MSC_VER >= 1400
......
...@@ -116,6 +116,7 @@ struct timespec { ...@@ -116,6 +116,7 @@ struct timespec {
void win_pthread_init(void); void win_pthread_init(void);
int win_pthread_setspecific(void *A,void *B,uint length); int win_pthread_setspecific(void *A,void *B,uint length);
int win_pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *); int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *);
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
...@@ -176,7 +177,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *); ...@@ -176,7 +177,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *);
#else #else
#define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) #define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0)
#define pthread_mutex_lock(A) (EnterCriticalSection(A),0) #define pthread_mutex_lock(A) (EnterCriticalSection(A),0)
#define pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT) #define pthread_mutex_trylock(A) win_pthread_mutex_trylock((A))
#define pthread_mutex_unlock(A) LeaveCriticalSection(A) #define pthread_mutex_unlock(A) LeaveCriticalSection(A)
#define pthread_mutex_destroy(A) DeleteCriticalSection(A) #define pthread_mutex_destroy(A) DeleteCriticalSection(A)
#define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B)) #define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B))
...@@ -574,7 +575,7 @@ typedef struct st_safe_mutex_info_t ...@@ -574,7 +575,7 @@ typedef struct st_safe_mutex_info_t
int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr,
const char *file, uint line); const char *file, uint line);
int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line); int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line);
int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line);
int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line);
int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file,
...@@ -597,12 +598,12 @@ void safe_mutex_end(FILE *file); ...@@ -597,12 +598,12 @@ void safe_mutex_end(FILE *file);
#undef pthread_cond_timedwait #undef pthread_cond_timedwait
#undef pthread_mutex_trylock #undef pthread_mutex_trylock
#define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__) #define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__)
#define pthread_mutex_lock(A) safe_mutex_lock((A),__FILE__,__LINE__) #define pthread_mutex_lock(A) safe_mutex_lock((A), FALSE, __FILE__, __LINE__)
#define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__) #define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__)
#define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__) #define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__)
#define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__) #define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__)
#define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) #define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__)
#define pthread_mutex_trylock(A) pthread_mutex_lock(A) #define pthread_mutex_trylock(A) safe_mutex_lock((A), TRUE, __FILE__, __LINE__)
#define pthread_mutex_t safe_mutex_t #define pthread_mutex_t safe_mutex_t
#define safe_mutex_assert_owner(mp) \ #define safe_mutex_assert_owner(mp) \
DBUG_ASSERT((mp)->count > 0 && \ DBUG_ASSERT((mp)->count > 0 && \
......
...@@ -307,6 +307,13 @@ UNIQUE USING BTREE(c1) ...@@ -307,6 +307,13 @@ UNIQUE USING BTREE(c1)
) ENGINE= MEMORY DEFAULT CHARSET= utf8; ) ENGINE= MEMORY DEFAULT CHARSET= utf8;
INSERT INTO t1 VALUES('1'), ('2'); INSERT INTO t1 VALUES('1'), ('2');
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (a INT, KEY USING BTREE(a)) ENGINE=MEMORY;
INSERT INTO t1 VALUES(1),(2),(2);
DELETE FROM t1 WHERE a=2;
SELECT * FROM t1;
a
1
DROP TABLE t1;
End of 4.1 tests End of 4.1 tests
CREATE TABLE t1(val INT, KEY USING BTREE(val)) ENGINE=memory; CREATE TABLE t1(val INT, KEY USING BTREE(val)) ENGINE=memory;
INSERT INTO t1 VALUES(0); INSERT INTO t1 VALUES(0);
......
...@@ -876,4 +876,9 @@ CHECK TABLE tm1; ...@@ -876,4 +876,9 @@ CHECK TABLE tm1;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.tm1 check status OK test.tm1 check status OK
DROP TABLE tm1, t1, t2; DROP TABLE tm1, t1, t2;
CREATE TABLE t1(c1 INT);
CREATE TABLE t2 (c1 INT) ENGINE=MERGE UNION=(t1) INSERT_METHOD=FIRST;
CREATE TABLE IF NOT EXISTS t1 SELECT * FROM t2;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
DROP TABLE t1, t2;
End of 5.0 tests End of 5.0 tests
...@@ -1211,7 +1211,7 @@ ERROR 42S02: Unknown table 'c' in field list ...@@ -1211,7 +1211,7 @@ ERROR 42S02: Unknown table 'c' in field list
drop procedure bug15091; drop procedure bug15091;
drop function if exists bug16896; drop function if exists bug16896;
create aggregate function bug16896() returns int return 1; create aggregate function bug16896() returns int return 1;
ERROR 42000: AGGREGATE is not supported for stored functions ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '() returns int return 1' at line 1
DROP PROCEDURE IF EXISTS bug14702; DROP PROCEDURE IF EXISTS bug14702;
CREATE IF NOT EXISTS PROCEDURE bug14702() CREATE IF NOT EXISTS PROCEDURE bug14702()
BEGIN BEGIN
...@@ -1452,3 +1452,16 @@ end ...@@ -1452,3 +1452,16 @@ end
until true end repeat retry; until true end repeat retry;
end// end//
ERROR 42000: LEAVE with no matching label: retry ERROR 42000: LEAVE with no matching label: retry
DROP DATABASE IF EXISTS mysqltest;
CREATE DATABASE mysqltest;
USE mysqltest;
DROP DATABASE mysqltest;
SELECT inexistent(), 1 + ,;
ERROR 42000: FUNCTION inexistent does not exist
SELECT inexistent();
ERROR 42000: FUNCTION inexistent does not exist
SELECT .inexistent();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '()' at line 1
SELECT ..inexistent();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.inexistent()' at line 1
USE test;
...@@ -5667,7 +5667,6 @@ t3_id_1 t3_id_2 t4_id ...@@ -5667,7 +5667,6 @@ t3_id_1 t3_id_2 t4_id
DROP PROCEDURE p1| DROP PROCEDURE p1|
DROP VIEW v1, v2| DROP VIEW v1, v2|
DROP TABLE t3, t4| DROP TABLE t3, t4|
End of 5.0 tests
DROP TABLE IF EXISTS bug23760| DROP TABLE IF EXISTS bug23760|
DROP TABLE IF EXISTS bug23760_log| DROP TABLE IF EXISTS bug23760_log|
DROP PROCEDURE IF EXISTS bug23760_update_log| DROP PROCEDURE IF EXISTS bug23760_update_log|
...@@ -6145,7 +6144,6 @@ Procedure sql_mode Create Procedure ...@@ -6145,7 +6144,6 @@ Procedure sql_mode Create Procedure
proc_21513 CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_21513`() proc_21513 CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_21513`()
`my_label`:BEGIN END `my_label`:BEGIN END
drop procedure proc_21513| drop procedure proc_21513|
End of 5.0 tests.
drop table t1,t2; drop table t1,t2;
CREATE TABLE t1 (a int auto_increment primary key) engine=MyISAM; CREATE TABLE t1 (a int auto_increment primary key) engine=MyISAM;
CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb; CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb;
...@@ -6389,4 +6387,197 @@ DROP TABLE t1; ...@@ -6389,4 +6387,197 @@ DROP TABLE t1;
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP PROCEDURE p2; DROP PROCEDURE p2;
End of 5.0 tests
#
# Bug#31035.
#
#
# - Prepare.
#
DROP TABLE IF EXISTS t1;
DROP FUNCTION IF EXISTS f1;
DROP FUNCTION IF EXISTS f2;
DROP FUNCTION IF EXISTS f3;
DROP FUNCTION IF EXISTS f4;
#
# - Create required objects.
#
CREATE TABLE t1(c1 INT);
INSERT INTO t1 VALUES (1), (2), (3);
CREATE FUNCTION f1()
RETURNS INT
NOT DETERMINISTIC
RETURN 1;
CREATE FUNCTION f2(p INT)
RETURNS INT
NOT DETERMINISTIC
RETURN 1;
CREATE FUNCTION f3()
RETURNS INT
DETERMINISTIC
RETURN 1;
CREATE FUNCTION f4(p INT)
RETURNS INT
DETERMINISTIC
RETURN 1;
#
# - Check.
#
SELECT f1() AS a FROM t1 GROUP BY a;
a
1
SELECT f2(@a) AS a FROM t1 GROUP BY a;
a
1
SELECT f3() AS a FROM t1 GROUP BY a;
a
1
SELECT f4(0) AS a FROM t1 GROUP BY a;
a
1
SELECT f4(@a) AS a FROM t1 GROUP BY a;
a
1
#
# - Cleanup.
#
DROP TABLE t1;
DROP FUNCTION f1;
DROP FUNCTION f2;
DROP FUNCTION f3;
DROP FUNCTION f4;
#
# Bug#31191.
#
#
# - Prepare.
#
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
DROP FUNCTION IF EXISTS f1;
#
# - Create required objects.
#
CREATE TABLE t1 (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
barcode INT(8) UNSIGNED ZEROFILL nOT NULL,
PRIMARY KEY (id),
UNIQUE KEY barcode (barcode)
);
INSERT INTO t1 (id, barcode) VALUES (1, 12345678);
INSERT INTO t1 (id, barcode) VALUES (2, 12345679);
CREATE TABLE test.t2 (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
barcode BIGINT(11) UNSIGNED ZEROFILL NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO test.t2 (id, barcode) VALUES (1, 12345106708);
INSERT INTO test.t2 (id, barcode) VALUES (2, 12345106709);
CREATE FUNCTION f1(p INT(8))
RETURNS BIGINT(11) UNSIGNED
READS SQL DATA
RETURN FLOOR(p/1000)*1000000 + 100000 + FLOOR((p MOD 1000)/10)*100 + (p MOD 10);
#
# - Check.
#
SELECT DISTINCT t1.barcode, f1(t1.barcode)
FROM t1
INNER JOIN t2
ON f1(t1.barcode) = t2.barcode
WHERE t1.barcode=12345678;
barcode f1(t1.barcode)
12345678 12345106708
#
# - Cleanup.
#
DROP TABLE t1;
DROP TABLE t2;
DROP FUNCTION f1;
#
# Bug#31226.
#
#
# - Prepare.
#
DROP TABLE IF EXISTS t1;
DROP FUNCTION IF EXISTS f1;
#
# - Create required objects.
#
CREATE TABLE t1(id INT);
INSERT INTO t1 VALUES (1), (2), (3);
CREATE FUNCTION f1()
RETURNS DATETIME
NOT DETERMINISTIC NO SQL
RETURN NOW();
#
# - Check.
#
SELECT f1() FROM t1 GROUP BY 1;
f1()
<timestamp>
#
# - Cleanup.
#
DROP TABLE t1;
DROP FUNCTION f1;
DROP PROCEDURE IF EXISTS db28318_a.t1;
DROP PROCEDURE IF EXISTS db28318_b.t2;
DROP DATABASE IF EXISTS db28318_a;
DROP DATABASE IF EXISTS db28318_b;
CREATE DATABASE db28318_a;
CREATE DATABASE db28318_b;
CREATE PROCEDURE db28318_a.t1() SELECT "db28318_a.t1";
CREATE PROCEDURE db28318_b.t2() CALL t1();
use db28318_a;
CALL db28318_b.t2();
ERROR 42000: PROCEDURE db28318_b.t1 does not exist
DROP PROCEDURE db28318_a.t1;
DROP PROCEDURE db28318_b.t2;
DROP DATABASE db28318_a;
DROP DATABASE db28318_b;
# ------------------------------------------------------------------
# -- End of 5.0 tests
# ------------------------------------------------------------------
...@@ -95,10 +95,10 @@ FR ...@@ -95,10 +95,10 @@ FR
DROP TABLE bug19904; DROP TABLE bug19904;
CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse
RETURNS STRING SONAME "should_not_parse.so"; RETURNS STRING SONAME "should_not_parse.so";
ERROR HY000: Incorrect usage of SONAME and DEFINER ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNS STRING SONAME "should_not_parse.so"' at line 2
CREATE DEFINER=someone@somewhere FUNCTION should_not_parse CREATE DEFINER=someone@somewhere FUNCTION should_not_parse
RETURNS STRING SONAME "should_not_parse.so"; RETURNS STRING SONAME "should_not_parse.so";
ERROR HY000: Incorrect usage of SONAME and DEFINER ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNS STRING SONAME "should_not_parse.so"' at line 2
create table t1(f1 int); create table t1(f1 int);
insert into t1 values(1),(2); insert into t1 values(1),(2);
explain select myfunc_int(f1) from t1 order by 1; explain select myfunc_int(f1) from t1 order by 1;
...@@ -296,6 +296,13 @@ Qcache_queries_in_cache 0 ...@@ -296,6 +296,13 @@ Qcache_queries_in_cache 0
drop table t1; drop table t1;
drop function metaphon; drop function metaphon;
set GLOBAL query_cache_size=default; set GLOBAL query_cache_size=default;
DROP DATABASE IF EXISTS mysqltest;
CREATE DATABASE mysqltest;
USE mysqltest;
DROP DATABASE mysqltest;
CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
DROP FUNCTION metaphon;
USE test;
CREATE TABLE const_len_bug ( CREATE TABLE const_len_bug (
str_const varchar(4000), str_const varchar(4000),
result1 varchar(4000), result1 varchar(4000),
......
...@@ -213,6 +213,15 @@ CREATE TABLE t1 ( ...@@ -213,6 +213,15 @@ CREATE TABLE t1 (
INSERT INTO t1 VALUES('1'), ('2'); INSERT INTO t1 VALUES('1'), ('2');
DROP TABLE t1; DROP TABLE t1;
#
# BUG#30590 - delete from memory table with composite btree primary key
#
CREATE TABLE t1 (a INT, KEY USING BTREE(a)) ENGINE=MEMORY;
INSERT INTO t1 VALUES(1),(2),(2);
DELETE FROM t1 WHERE a=2;
SELECT * FROM t1;
DROP TABLE t1;
--echo End of 4.1 tests --echo End of 4.1 tests
# #
......
...@@ -507,4 +507,18 @@ SELECT * FROM tm1; ...@@ -507,4 +507,18 @@ SELECT * FROM tm1;
CHECK TABLE tm1; CHECK TABLE tm1;
DROP TABLE tm1, t1, t2; DROP TABLE tm1, t1, t2;
#
# Bug#15522 - create ... select and with merge tables
#
# This was fixed together with Bug#20662 (Infinite loop in CREATE TABLE
# IF NOT EXISTS ... SELECT with locked tables).
# The new behavior for MERGE tables is consistent with the
# CREATE TABLE SELECT behavior for ordinary tables.
#
CREATE TABLE t1(c1 INT);
CREATE TABLE t2 (c1 INT) ENGINE=MERGE UNION=(t1) INSERT_METHOD=FIRST;
--error ER_UPDATE_TABLE_USED
CREATE TABLE IF NOT EXISTS t1 SELECT * FROM t2;
DROP TABLE t1, t2;
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -1744,7 +1744,7 @@ drop procedure bug15091; ...@@ -1744,7 +1744,7 @@ drop procedure bug15091;
drop function if exists bug16896; drop function if exists bug16896;
--enable_warnings --enable_warnings
--error ER_SP_NO_AGGREGATE --error ER_PARSE_ERROR
create aggregate function bug16896() returns int return 1; create aggregate function bug16896() returns int return 1;
...@@ -2089,6 +2089,29 @@ end// ...@@ -2089,6 +2089,29 @@ end//
delimiter ;// delimiter ;//
#
# Bug#29816 Syntactically wrong query fails with misleading error message
#
--disable_warnings
DROP DATABASE IF EXISTS mysqltest;
--enable_warnings
CREATE DATABASE mysqltest;
USE mysqltest;
DROP DATABASE mysqltest;
# Both ER_SP_DOES_NOT_EXIST and ER_PARSE_ERROR are valid here,
# the result is implementation dependent:
# See Bug#29816 for details
--error ER_SP_DOES_NOT_EXIST
SELECT inexistent(), 1 + ,;
--error ER_SP_DOES_NOT_EXIST
SELECT inexistent();
--error ER_PARSE_ERROR
SELECT .inexistent();
--error ER_PARSE_ERROR
SELECT ..inexistent();
USE test;
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
......
...@@ -6642,9 +6642,6 @@ DROP VIEW v1, v2| ...@@ -6642,9 +6642,6 @@ DROP VIEW v1, v2|
DROP TABLE t3, t4| DROP TABLE t3, t4|
--echo End of 5.0 tests
# #
# BUG#23760: ROW_COUNT() and store procedure not owrking together # BUG#23760: ROW_COUNT() and store procedure not owrking together
# #
...@@ -7076,9 +7073,6 @@ show create procedure proc_21513| ...@@ -7076,9 +7073,6 @@ show create procedure proc_21513|
drop procedure proc_21513| drop procedure proc_21513|
###
--echo End of 5.0 tests.
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
...@@ -7387,4 +7381,325 @@ DROP TABLE t1; ...@@ -7387,4 +7381,325 @@ DROP TABLE t1;
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP PROCEDURE p2; DROP PROCEDURE p2;
--echo End of 5.0 tests ###########################################################################
#
# Bug#31035: select from function, group by result crasher.
#
###########################################################################
--echo
--echo #
--echo # Bug#31035.
--echo #
--echo
--echo #
--echo # - Prepare.
--echo #
--echo
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP FUNCTION IF EXISTS f1;
DROP FUNCTION IF EXISTS f2;
DROP FUNCTION IF EXISTS f3;
DROP FUNCTION IF EXISTS f4;
--enable_warnings
--echo
--echo #
--echo # - Create required objects.
--echo #
--echo
CREATE TABLE t1(c1 INT);
--echo
INSERT INTO t1 VALUES (1), (2), (3);
--echo
CREATE FUNCTION f1()
RETURNS INT
NOT DETERMINISTIC
RETURN 1;
--echo
CREATE FUNCTION f2(p INT)
RETURNS INT
NOT DETERMINISTIC
RETURN 1;
--echo
CREATE FUNCTION f3()
RETURNS INT
DETERMINISTIC
RETURN 1;
--echo
CREATE FUNCTION f4(p INT)
RETURNS INT
DETERMINISTIC
RETURN 1;
--echo
--echo #
--echo # - Check.
--echo #
--echo
# Not deterministic function, no arguments.
SELECT f1() AS a FROM t1 GROUP BY a;
--echo
# Not deterministic function, non-constant argument.
SELECT f2(@a) AS a FROM t1 GROUP BY a;
--echo
# Deterministic function, no arguments.
SELECT f3() AS a FROM t1 GROUP BY a;
--echo
# Deterministic function, constant argument.
SELECT f4(0) AS a FROM t1 GROUP BY a;
--echo
# Deterministic function, non-constant argument.
SELECT f4(@a) AS a FROM t1 GROUP BY a;
--echo
--echo #
--echo # - Cleanup.
--echo #
--echo
DROP TABLE t1;
DROP FUNCTION f1;
DROP FUNCTION f2;
DROP FUNCTION f3;
DROP FUNCTION f4;
--echo
###########################################################################
#
# Bug#31191: JOIN in combination with stored function crashes the server.
#
###########################################################################
--echo #
--echo # Bug#31191.
--echo #
--echo
--echo #
--echo # - Prepare.
--echo #
--echo
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
DROP FUNCTION IF EXISTS f1;
--enable_warnings
--echo
--echo #
--echo # - Create required objects.
--echo #
--echo
CREATE TABLE t1 (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
barcode INT(8) UNSIGNED ZEROFILL nOT NULL,
PRIMARY KEY (id),
UNIQUE KEY barcode (barcode)
);
--echo
INSERT INTO t1 (id, barcode) VALUES (1, 12345678);
INSERT INTO t1 (id, barcode) VALUES (2, 12345679);
--echo
CREATE TABLE test.t2 (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
barcode BIGINT(11) UNSIGNED ZEROFILL NOT NULL,
PRIMARY KEY (id)
);
--echo
INSERT INTO test.t2 (id, barcode) VALUES (1, 12345106708);
INSERT INTO test.t2 (id, barcode) VALUES (2, 12345106709);
--echo
CREATE FUNCTION f1(p INT(8))
RETURNS BIGINT(11) UNSIGNED
READS SQL DATA
RETURN FLOOR(p/1000)*1000000 + 100000 + FLOOR((p MOD 1000)/10)*100 + (p MOD 10);
--echo
--echo #
--echo # - Check.
--echo #
--echo
SELECT DISTINCT t1.barcode, f1(t1.barcode)
FROM t1
INNER JOIN t2
ON f1(t1.barcode) = t2.barcode
WHERE t1.barcode=12345678;
--echo
--echo #
--echo # - Cleanup.
--echo #
--echo
DROP TABLE t1;
DROP TABLE t2;
DROP FUNCTION f1;
--echo
###########################################################################
#
# Bug#31226: Group by function crashes mysql.
#
###########################################################################
--echo #
--echo # Bug#31226.
--echo #
--echo
--echo #
--echo # - Prepare.
--echo #
--echo
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP FUNCTION IF EXISTS f1;
--enable_warnings
--echo
--echo #
--echo # - Create required objects.
--echo #
--echo
CREATE TABLE t1(id INT);
--echo
INSERT INTO t1 VALUES (1), (2), (3);
--echo
CREATE FUNCTION f1()
RETURNS DATETIME
NOT DETERMINISTIC NO SQL
RETURN NOW();
--echo
--echo #
--echo # - Check.
--echo #
--echo
--replace_column 1 <timestamp>
SELECT f1() FROM t1 GROUP BY 1;
--echo
--echo #
--echo # - Cleanup.
--echo #
--echo
DROP TABLE t1;
DROP FUNCTION f1;
--echo
###########################################################################
#
# Bug#28318 (CREATE FUNCTION (UDF) requires a schema)
#
--disable_warnings
DROP PROCEDURE IF EXISTS db28318_a.t1;
DROP PROCEDURE IF EXISTS db28318_b.t2;
DROP DATABASE IF EXISTS db28318_a;
DROP DATABASE IF EXISTS db28318_b;
--enable_warnings
CREATE DATABASE db28318_a;
CREATE DATABASE db28318_b;
CREATE PROCEDURE db28318_a.t1() SELECT "db28318_a.t1";
CREATE PROCEDURE db28318_b.t2() CALL t1();
use db28318_a;
# In db28318_b.t2, t1 refers to db28318_b.t1
--error ER_SP_DOES_NOT_EXIST
CALL db28318_b.t2();
DROP PROCEDURE db28318_a.t1;
DROP PROCEDURE db28318_b.t2;
DROP DATABASE db28318_a;
DROP DATABASE db28318_b;
--echo # ------------------------------------------------------------------
--echo # -- End of 5.0 tests
--echo # ------------------------------------------------------------------
...@@ -113,11 +113,11 @@ DROP TABLE bug19904; ...@@ -113,11 +113,11 @@ DROP TABLE bug19904;
# Bug#21269: DEFINER-clause is allowed for UDF-functions # Bug#21269: DEFINER-clause is allowed for UDF-functions
# #
--error ER_WRONG_USAGE --error ER_PARSE_ERROR
CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse
RETURNS STRING SONAME "should_not_parse.so"; RETURNS STRING SONAME "should_not_parse.so";
--error ER_WRONG_USAGE --error ER_PARSE_ERROR
CREATE DEFINER=someone@somewhere FUNCTION should_not_parse CREATE DEFINER=someone@somewhere FUNCTION should_not_parse
RETURNS STRING SONAME "should_not_parse.so"; RETURNS STRING SONAME "should_not_parse.so";
# #
...@@ -311,6 +311,20 @@ drop table t1; ...@@ -311,6 +311,20 @@ drop table t1;
drop function metaphon; drop function metaphon;
set GLOBAL query_cache_size=default; set GLOBAL query_cache_size=default;
#
# Bug#28318 CREATE FUNCTION (UDF) requires a schema
#
--disable_warnings
DROP DATABASE IF EXISTS mysqltest;
--enable_warnings
CREATE DATABASE mysqltest;
USE mysqltest;
DROP DATABASE mysqltest;
--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB";
DROP FUNCTION metaphon;
USE test;
# #
# Bug #29804 UDF parameters don't contain correct string length # Bug #29804 UDF parameters don't contain correct string length
......
...@@ -40,6 +40,29 @@ void win_pthread_init(void) ...@@ -40,6 +40,29 @@ void win_pthread_init(void)
pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST); pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST);
} }
/**
Adapter to @c pthread_mutex_trylock()
@retval 0 Mutex was acquired
@retval EBUSY Mutex was already locked by a thread
*/
int
win_pthread_mutex_trylock(pthread_mutex_t *mutex)
{
if (TryEnterCriticalSection(mutex))
{
/* Don't allow recursive lock */
if (mutex->RecursionCount > 1){
LeaveCriticalSection(mutex);
return EBUSY;
}
return 0;
}
return EBUSY;
}
/* /*
** We have tried to use '_beginthreadex' instead of '_beginthread' here ** We have tried to use '_beginthreadex' instead of '_beginthread' here
** but in this case the program leaks about 512 characters for each ** but in this case the program leaks about 512 characters for each
......
...@@ -91,7 +91,7 @@ int safe_mutex_init(safe_mutex_t *mp, ...@@ -91,7 +91,7 @@ int safe_mutex_init(safe_mutex_t *mp,
} }
int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line) int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line)
{ {
int error; int error;
if (!mp->file) if (!mp->file)
...@@ -104,15 +104,50 @@ int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line) ...@@ -104,15 +104,50 @@ int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
} }
pthread_mutex_lock(&mp->global); pthread_mutex_lock(&mp->global);
if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread)) if (mp->count > 0)
{ {
fprintf(stderr,"safe_mutex: Trying to lock mutex at %s, line %d, when the mutex was already locked at %s, line %d in thread %s\n", if (try_lock)
{
pthread_mutex_unlock(&mp->global);
return EBUSY;
}
else if (pthread_equal(pthread_self(),mp->thread))
{
fprintf(stderr,
"safe_mutex: Trying to lock mutex at %s, line %d, when the"
" mutex was already locked at %s, line %d in thread %s\n",
file,line,mp->file, mp->line, my_thread_name()); file,line,mp->file, mp->line, my_thread_name());
fflush(stderr); fflush(stderr);
abort(); abort();
} }
}
pthread_mutex_unlock(&mp->global); pthread_mutex_unlock(&mp->global);
error=pthread_mutex_lock(&mp->mutex);
/*
If we are imitating trylock(), we need to take special
precautions.
- We cannot use pthread_mutex_lock() only since another thread can
overtake this thread and take the lock before this thread
causing pthread_mutex_trylock() to hang. In this case, we should
just return EBUSY. Hence, we use pthread_mutex_trylock() to be
able to return immediately.
- We cannot just use trylock() and continue execution below, since
this would generate an error and abort execution if the thread
was overtaken and trylock() returned EBUSY . In this case, we
instead just return EBUSY, since this is the expected behaviour
of trylock().
*/
if (try_lock)
{
error= pthread_mutex_trylock(&mp->mutex);
if (error == EBUSY)
return error;
}
else
error= pthread_mutex_lock(&mp->mutex);
if (error || (error=pthread_mutex_lock(&mp->global))) if (error || (error=pthread_mutex_lock(&mp->global)))
{ {
fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n", fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
......
...@@ -4364,12 +4364,14 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) ...@@ -4364,12 +4364,14 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
return new Field_blob(max_length, maybe_null, name, table, return new Field_blob(max_length, maybe_null, name, table,
collation.collation); collation.collation);
break; // Blob handled outside of case break; // Blob handled outside of case
#ifdef HAVE_SPATIAL
case MYSQL_TYPE_GEOMETRY: case MYSQL_TYPE_GEOMETRY:
return new Field_geom(max_length, maybe_null, name, table, return new Field_geom(max_length, maybe_null, name, table,
(Field::geometry_type) (Field::geometry_type)
((type() == Item::TYPE_HOLDER) ? ((type() == Item::TYPE_HOLDER) ?
((Item_type_holder *)this)->get_geometry_type() : ((Item_type_holder *)this)->get_geometry_type() :
((Item_geometry_func *)this)->get_geometry_type())); ((Item_geometry_func *)this)->get_geometry_type()));
#endif /* HAVE_SPATIAL */
} }
} }
...@@ -6489,10 +6491,12 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) ...@@ -6489,10 +6491,12 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
if (Field::result_merge_type(fld_type) == INT_RESULT) if (Field::result_merge_type(fld_type) == INT_RESULT)
decimals= 0; decimals= 0;
prev_decimal_int_part= item->decimal_int_part(); prev_decimal_int_part= item->decimal_int_part();
#ifdef HAVE_SPATIAL
if (item->field_type() == MYSQL_TYPE_GEOMETRY) if (item->field_type() == MYSQL_TYPE_GEOMETRY)
geometry_type= (item->type() == Item::FIELD_ITEM) ? geometry_type= (item->type() == Item::FIELD_ITEM) ?
((Item_field *)item)->get_geometry_type() : ((Item_field *)item)->get_geometry_type() :
(Field::geometry_type)((Item_geometry_func *)item)->get_geometry_type(); (Field::geometry_type)((Item_geometry_func *)item)->get_geometry_type();
#endif /* HAVE_SPATIAL */
} }
......
...@@ -5584,8 +5584,13 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) ...@@ -5584,8 +5584,13 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
#endif /* ! NO_EMBEDDED_ACCESS_CHECKS */ #endif /* ! NO_EMBEDDED_ACCESS_CHECKS */
} }
if (!m_sp->m_chistics->detistic) if (!m_sp->m_chistics->detistic)
{
used_tables_cache |= RAND_TABLE_BIT; used_tables_cache |= RAND_TABLE_BIT;
const_item_cache= FALSE;
}
DBUG_RETURN(res); DBUG_RETURN(res);
} }
...@@ -5593,6 +5598,10 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) ...@@ -5593,6 +5598,10 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
void Item_func_sp::update_used_tables() void Item_func_sp::update_used_tables()
{ {
Item_func::update_used_tables(); Item_func::update_used_tables();
if (!m_sp->m_chistics->detistic) if (!m_sp->m_chistics->detistic)
{
used_tables_cache |= RAND_TABLE_BIT; used_tables_cache |= RAND_TABLE_BIT;
const_item_cache= FALSE;
}
} }
...@@ -731,7 +731,6 @@ pthread_handler_t handle_bootstrap(void *arg); ...@@ -731,7 +731,6 @@ pthread_handler_t handle_bootstrap(void *arg);
void end_thread(THD *thd,bool put_in_cache); void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache(); void flush_thread_cache();
bool mysql_execute_command(THD *thd); bool mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd, bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length); char* packet, uint packet_length);
void log_slow_statement(THD *thd); void log_slow_statement(THD *thd);
......
...@@ -784,7 +784,6 @@ sys_var *sys_variables[]= ...@@ -784,7 +784,6 @@ sys_var *sys_variables[]=
&sys_innodb_max_purge_lag, &sys_innodb_max_purge_lag,
&sys_innodb_table_locks, &sys_innodb_table_locks,
&sys_innodb_support_xa, &sys_innodb_support_xa,
&sys_innodb_max_purge_lag,
&sys_innodb_autoextend_increment, &sys_innodb_autoextend_increment,
&sys_innodb_sync_spin_loops, &sys_innodb_sync_spin_loops,
&sys_innodb_concurrency_tickets, &sys_innodb_concurrency_tickets,
......
...@@ -1405,12 +1405,12 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, ...@@ -1405,12 +1405,12 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
{ {
Sroutine_hash_entry *rn= Sroutine_hash_entry *rn=
(Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) + (Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) +
key->length); key->length + 1);
if (!rn) // OOM. Error will be reported using fatal_error(). if (!rn) // OOM. Error will be reported using fatal_error().
return FALSE; return FALSE;
rn->key.length= key->length; rn->key.length= key->length;
rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry); rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry);
memcpy(rn->key.str, key->str, key->length); memcpy(rn->key.str, key->str, key->length + 1);
my_hash_insert(&lex->sroutines, (byte *)rn); my_hash_insert(&lex->sroutines, (byte *)rn);
lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next); lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
rn->belong_to_view= belong_to_view; rn->belong_to_view= belong_to_view;
...@@ -1595,7 +1595,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, ...@@ -1595,7 +1595,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
for (Sroutine_hash_entry *rt= start; rt; rt= rt->next) for (Sroutine_hash_entry *rt= start; rt; rt= rt->next)
{ {
sp_name name(rt->key.str, rt->key.length); sp_name name(thd, rt->key.str, rt->key.length);
int type= rt->key.str[0]; int type= rt->key.str[0];
sp_head *sp; sp_head *sp;
...@@ -1603,13 +1603,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, ...@@ -1603,13 +1603,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
&thd->sp_func_cache : &thd->sp_proc_cache), &thd->sp_func_cache : &thd->sp_proc_cache),
&name))) &name)))
{ {
name.m_name.str= strchr(name.m_qname.str, '.');
name.m_db.length= name.m_name.str - name.m_qname.str;
name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str,
name.m_db.length);
name.m_name.str+= 1;
name.m_name.length= name.m_qname.length - name.m_db.length - 1;
switch ((ret= db_find_routine(thd, type, &name, &sp))) switch ((ret= db_find_routine(thd, type, &name, &sp)))
{ {
case SP_OK: case SP_OK:
......
...@@ -369,17 +369,42 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) ...@@ -369,17 +369,42 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
* *
*/ */
sp_name::sp_name(THD *thd, char *key, uint key_len)
{
m_sroutines_key.str= key;
m_sroutines_key.length= key_len;
m_qname.str= ++key;
m_qname.length= key_len - 1;
if ((m_name.str= strchr(m_qname.str, '.')))
{
m_db.length= m_name.str - key;
m_db.str= strmake_root(thd->mem_root, key, m_db.length);
m_name.str++;
m_name.length= m_qname.length - m_db.length - 1;
}
else
{
m_name.str= m_qname.str;
m_name.length= m_qname.length;
m_db.str= 0;
m_db.length= 0;
}
m_explicit_name= false;
}
void void
sp_name::init_qname(THD *thd) sp_name::init_qname(THD *thd)
{ {
m_sroutines_key.length= m_db.length + m_name.length + 2; const uint dot= !!m_db.length;
/* m_sroutines format: m_type + [database + dot] + name + nul */
m_sroutines_key.length= 1 + m_db.length + dot + m_name.length;
if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1))) if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1)))
return; return;
m_qname.length= m_sroutines_key.length - 1; m_qname.length= m_sroutines_key.length - 1;
m_qname.str= m_sroutines_key.str + 1; m_qname.str= m_sroutines_key.str + 1;
sprintf(m_qname.str, "%.*s.%.*s", sprintf(m_qname.str, "%.*s%.*s%.*s",
m_db.length, (m_db.length ? m_db.str : ""), m_db.length, (m_db.length ? m_db.str : ""),
m_name.length, m_name.str); dot, ".", m_name.length, m_name.str);
} }
......
...@@ -72,16 +72,7 @@ public: ...@@ -72,16 +72,7 @@ public:
Creates temporary sp_name object from key, used mainly Creates temporary sp_name object from key, used mainly
for SP-cache lookups. for SP-cache lookups.
*/ */
sp_name(char *key, uint key_len) sp_name(THD *thd, char *key, uint key_len);
{
m_sroutines_key.str= key;
m_sroutines_key.length= key_len;
m_name.str= m_qname.str= key + 1;
m_name.length= m_qname.length= key_len - 1;
m_db.str= 0;
m_db.length= 0;
m_explicit_name= false;
}
// Init. the qualified name from the db and name. // Init. the qualified name from the db and name.
void init_qname(THD *thd); // thd for memroot allocation void init_qname(THD *thd); // thd for memroot allocation
......
...@@ -1745,7 +1745,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, ...@@ -1745,7 +1745,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/* close handler tables which are marked for flush */ /*
In order for the back off and re-start process to work properly,
handler tables having old versions (due to FLUSH TABLES or pending
name-lock) MUST be closed. This is specially important if a name-lock
is pending for any table of the handler_tables list, otherwise a
deadlock may occur.
*/
if (thd->handler_tables) if (thd->handler_tables)
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
...@@ -1810,6 +1816,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, ...@@ -1810,6 +1816,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->db_stat == 0 signals wait_for_locked_table_names table->db_stat == 0 signals wait_for_locked_table_names
that the tables in question are not used any more. See that the tables in question are not used any more. See
table_is_used call for details. table_is_used call for details.
Notice that HANDLER tables were already taken care of by
the earlier call to mysql_ha_flush() in this same critical
section.
*/ */
close_old_data_files(thd,thd->open_tables,0,0); close_old_data_files(thd,thd->open_tables,0,0);
/* /*
......
...@@ -65,11 +65,6 @@ ...@@ -65,11 +65,6 @@
static enum enum_ha_read_modes rkey_to_rnext[]= static enum enum_ha_read_modes rkey_to_rnext[]=
{ RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV }; { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
#define HANDLER_TABLES_HACK(thd) { \
TABLE *tmp=thd->open_tables; \
thd->open_tables=thd->handler_tables; \
thd->handler_tables=tmp; }
static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags); static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags);
...@@ -187,6 +182,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) ...@@ -187,6 +182,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
char *db, *name, *alias; char *db, *name, *alias;
uint dblen, namelen, aliaslen, counter; uint dblen, namelen, aliaslen, counter;
int error; int error;
TABLE *backup_open_tables;
DBUG_ENTER("mysql_ha_open"); DBUG_ENTER("mysql_ha_open");
DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d", DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
tables->db, tables->table_name, tables->alias, tables->db, tables->table_name, tables->alias,
...@@ -215,18 +211,40 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) ...@@ -215,18 +211,40 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
} }
} }
/*
Save and reset the open_tables list so that open_tables() won't
be able to access (or know about) the previous list. And on return
from open_tables(), thd->open_tables will contain only the opened
table.
The thd->handler_tables list is kept as-is to avoid deadlocks if
open_table(), called by open_tables(), needs to back-off because
of a pending name-lock on the table being opened.
See open_table() back-off comments for more details.
*/
backup_open_tables= thd->open_tables;
thd->open_tables= NULL;
/* /*
open_tables() will set 'tables->table' if successful. open_tables() will set 'tables->table' if successful.
It must be NULL for a real open when calling open_tables(). It must be NULL for a real open when calling open_tables().
*/ */
DBUG_ASSERT(! tables->table); DBUG_ASSERT(! tables->table);
HANDLER_TABLES_HACK(thd);
/* for now HANDLER can be used only for real TABLES */ /* for now HANDLER can be used only for real TABLES */
tables->required_type= FRMTYPE_TABLE; tables->required_type= FRMTYPE_TABLE;
error= open_tables(thd, &tables, &counter, 0); error= open_tables(thd, &tables, &counter, 0);
HANDLER_TABLES_HACK(thd); /* restore the state and merge the opened table into handler_tables list */
if (thd->open_tables)
{
thd->open_tables->next= thd->handler_tables;
thd->handler_tables= thd->open_tables;
}
thd->open_tables= backup_open_tables;
if (error) if (error)
goto err; goto err;
...@@ -351,7 +369,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ...@@ -351,7 +369,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
ha_rows select_limit_cnt, ha_rows offset_limit_cnt) ha_rows select_limit_cnt, ha_rows offset_limit_cnt)
{ {
TABLE_LIST *hash_tables; TABLE_LIST *hash_tables;
TABLE *table; TABLE *table, *backup_open_tables;
MYSQL_LOCK *lock; MYSQL_LOCK *lock;
List<Item> list; List<Item> list;
Protocol *protocol= thd->protocol; Protocol *protocol= thd->protocol;
...@@ -361,7 +379,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ...@@ -361,7 +379,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
uint num_rows; uint num_rows;
byte *key; byte *key;
uint key_len; uint key_len;
bool not_used; bool need_reopen;
DBUG_ENTER("mysql_ha_read"); DBUG_ENTER("mysql_ha_read");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'", DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias)); tables->db, tables->table_name, tables->alias));
...@@ -375,6 +393,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ...@@ -375,6 +393,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
List_iterator<Item> it(list); List_iterator<Item> it(list);
it++; it++;
retry:
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
(byte*) tables->alias, (byte*) tables->alias,
strlen(tables->alias) + 1))) strlen(tables->alias) + 1)))
...@@ -427,9 +446,34 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ...@@ -427,9 +446,34 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
} }
tables->table=table; tables->table=table;
HANDLER_TABLES_HACK(thd); /* save open_tables state */
lock= mysql_lock_tables(thd, &tables->table, 1, 0, &not_used); backup_open_tables= thd->open_tables;
HANDLER_TABLES_HACK(thd); /*
mysql_lock_tables() needs thd->open_tables to be set correctly to
be able to handle aborts properly. When the abort happens, it's
safe to not protect thd->handler_tables because it won't close any
tables.
*/
thd->open_tables= thd->handler_tables;
lock= mysql_lock_tables(thd, &tables->table, 1,
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen);
/* restore previous context */
thd->open_tables= backup_open_tables;
if (need_reopen)
{
mysql_ha_close_table(thd, tables);
hash_tables->table= NULL;
/*
The lock might have been aborted, we need to manually reset
thd->some_tables_deleted because handler's tables are closed
in a non-standard way. Otherwise we might loop indefinitely.
*/
thd->some_tables_deleted= 0;
goto retry;
}
if (!lock) if (!lock)
goto err0; // mysql_lock_tables() printed error message already goto err0; // mysql_lock_tables() printed error message already
......
...@@ -93,6 +93,10 @@ const char *xa_state_names[]={ ...@@ -93,6 +93,10 @@ const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
}; };
#ifndef EMBEDDED_LIBRARY
static bool do_command(THD *thd);
#endif // EMBEDDED_LIBRARY
#ifdef __WIN__ #ifdef __WIN__
static void test_signal(int sig_ptr) static void test_signal(int sig_ptr)
{ {
...@@ -1199,21 +1203,26 @@ pthread_handler_t handle_one_connection(void *arg) ...@@ -1199,21 +1203,26 @@ pthread_handler_t handle_one_connection(void *arg)
} }
if (thd->user_connect) if (thd->user_connect)
decrease_user_connections(thd->user_connect); decrease_user_connections(thd->user_connect);
if (thd->killed ||
net->vio && net->error && net->report_error)
{
statistic_increment(aborted_threads, &LOCK_status);
}
if (net->error && net->vio != 0 && net->report_error) if (net->error && net->vio != 0 && net->report_error)
{ {
if (!thd->killed && thd->variables.log_warnings > 1) if (!thd->killed && thd->variables.log_warnings > 1)
{
sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
thd->thread_id,(thd->db ? thd->db : "unconnected"), thd->thread_id,(thd->db ? thd->db : "unconnected"),
sctx->user ? sctx->user : "unauthenticated", sctx->user ? sctx->user : "unauthenticated",
sctx->host_or_ip, sctx->host_or_ip,
(net->last_errno ? ER(net->last_errno) : (net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR))); ER(ER_UNKNOWN_ERROR)));
net_send_error(thd, net->last_errno, NullS);
statistic_increment(aborted_threads,&LOCK_status);
} }
else if (thd->killed)
{ net_send_error(thd, net->last_errno, NullS);
statistic_increment(aborted_threads,&LOCK_status);
} }
end_thread: end_thread:
...@@ -1520,7 +1529,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) ...@@ -1520,7 +1529,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
1 request of thread shutdown (see dispatch_command() description) 1 request of thread shutdown (see dispatch_command() description)
*/ */
bool do_command(THD *thd) static bool do_command(THD *thd)
{ {
char *packet= 0; char *packet= 0;
ulong packet_length; ulong packet_length;
...@@ -1550,12 +1559,12 @@ bool do_command(THD *thd) ...@@ -1550,12 +1559,12 @@ bool do_command(THD *thd)
DBUG_PRINT("info",("Got error %d reading command from socket %s", DBUG_PRINT("info",("Got error %d reading command from socket %s",
net->error, net->error,
vio_description(net->vio))); vio_description(net->vio)));
/* Check if we can continue without closing the connection */ /* Check if we can continue without closing the connection */
if (net->error != 3) if (net->error != 3)
{
statistic_increment(aborted_threads,&LOCK_status);
DBUG_RETURN(TRUE); // We have to close it. DBUG_RETURN(TRUE); // We have to close it.
}
net_send_error(thd, net->last_errno, NullS); net_send_error(thd, net->last_errno, NullS);
net->error= 0; net->error= 0;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
...@@ -4007,12 +4016,6 @@ end_with_restore_list: ...@@ -4007,12 +4016,6 @@ end_with_restore_list:
if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0)) if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
break; break;
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
&thd->sp_func_cache, FALSE))
{
my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
goto error;
}
if (!(res = mysql_create_function(thd, &lex->udf))) if (!(res = mysql_create_function(thd, &lex->udf)))
send_ok(thd); send_ok(thd);
#else #else
......
...@@ -426,14 +426,14 @@ int mysql_create_function(THD *thd,udf_func *udf) ...@@ -426,14 +426,14 @@ int mysql_create_function(THD *thd,udf_func *udf)
} }
if (udf->name.length > NAME_LEN) if (udf->name.length > NAME_LEN)
{ {
my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name); my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name.str);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
rw_wrlock(&THR_LOCK_udf); rw_wrlock(&THR_LOCK_udf);
if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length))) if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length)))
{ {
my_error(ER_UDF_EXISTS, MYF(0), udf->name); my_error(ER_UDF_EXISTS, MYF(0), udf->name.str);
goto err; goto err;
} }
if (!(dl = find_udf_dl(udf->dl))) if (!(dl = find_udf_dl(udf->dl)))
......
This diff is collapsed.
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