automerge
This commit is contained in:
commit
eecf716a83
78
mysql-test/include/wait_show_condition.inc
Normal file
78
mysql-test/include/wait_show_condition.inc
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# include/wait_show_condition.inc
|
||||||
|
#
|
||||||
|
# SUMMARY
|
||||||
|
#
|
||||||
|
# Waits until the show statement ($show_statement) has at least within one of
|
||||||
|
# the rows of the result set for the field ($field) a value which fulfils
|
||||||
|
# a condition ($condition), or the operation times out.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# USAGE
|
||||||
|
#
|
||||||
|
# let $show_statement= SHOW PROCESSLIST;
|
||||||
|
# let $field= State;
|
||||||
|
# let $condition= = 'Updating';
|
||||||
|
# --source include/wait_show_condition.inc
|
||||||
|
#
|
||||||
|
# OR
|
||||||
|
#
|
||||||
|
# let $wait_timeout= 60; # Override default of 30 seconds with 60.
|
||||||
|
# let $show_statement= SHOW PROCESSLIST;
|
||||||
|
# let $field= State;
|
||||||
|
# let $condition= = 'Updating';
|
||||||
|
# --source include/wait_show_condition.inc
|
||||||
|
#
|
||||||
|
# Please do not use this use routine if you can replace the SHOW statement
|
||||||
|
# with a select. In such a case include/wait_condition.inc is recommended.
|
||||||
|
#
|
||||||
|
# Created: 2009-02-18 mleich
|
||||||
|
#
|
||||||
|
|
||||||
|
let $max_run_time= 30;
|
||||||
|
if ($wait_timeout)
|
||||||
|
{
|
||||||
|
let $max_run_time= $wait_timeout;
|
||||||
|
}
|
||||||
|
# Reset $wait_timeout so that its value won't be used on subsequent
|
||||||
|
# calls, and default will be used instead.
|
||||||
|
let $wait_timeout= 0;
|
||||||
|
|
||||||
|
# The smallest timespan till UNIX_TIMESTAMP() gets incremented is ~0 seconds.
|
||||||
|
# We add one second to avoid the case that somebody measures timespans on a
|
||||||
|
# real clock with fractions of seconds, detects that n seconds are sufficient,
|
||||||
|
# assigns n to this routine and suffers because he sometimes gets n - 1
|
||||||
|
# seconds in reality.
|
||||||
|
inc $max_run_time;
|
||||||
|
|
||||||
|
let $found= 0;
|
||||||
|
let $max_end_time= `SELECT UNIX_TIMESTAMP() + $max_run_time`;
|
||||||
|
while (`SELECT UNIX_TIMESTAMP() <= $max_end_time AND $found = 0`)
|
||||||
|
{
|
||||||
|
# Sleep a bit to avoid too heavy load.
|
||||||
|
real_sleep 0.2;
|
||||||
|
let $rowno= 1;
|
||||||
|
let $process_result= 1;
|
||||||
|
while (`SELECT $process_result = 1 AND $found = 0`)
|
||||||
|
{
|
||||||
|
let $field_value= query_get_value($show_statement, $field, $rowno);
|
||||||
|
if (`SELECT '$field_value' $condition`)
|
||||||
|
{
|
||||||
|
let $found= 1;
|
||||||
|
}
|
||||||
|
if (`SELECT '$field_value' = 'No such row'`)
|
||||||
|
{
|
||||||
|
# We are behind the last row of the result set.
|
||||||
|
let $process_result= 0;
|
||||||
|
}
|
||||||
|
inc $rowno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$found)
|
||||||
|
{
|
||||||
|
echo # Timeout in include/wait_show_condition.inc for $wait_condition;
|
||||||
|
echo # show_statement : $show_statement;
|
||||||
|
echo # field : $field;
|
||||||
|
echo # condition : $condition;
|
||||||
|
echo # max_run_time : $max_run_time;
|
||||||
|
}
|
||||||
|
|
17
mysql-test/r/innodb_bug42419.result
Normal file
17
mysql-test/r/innodb_bug42419.result
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b INT) ENGINE = InnoDB;
|
||||||
|
INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
|
||||||
|
COMMIT;
|
||||||
|
SET AUTOCOMMIT = 0;
|
||||||
|
CREATE TEMPORARY TABLE t1_tmp ( b INT );
|
||||||
|
INSERT INTO t1_tmp (b) SELECT b FROM t1 WHERE a = 3;
|
||||||
|
INSERT INTO t1_tmp (b) SELECT b FROM t1 WHERE a = 2;
|
||||||
|
SET AUTOCOMMIT = 0;
|
||||||
|
CREATE TEMPORARY TABLE t2_tmp ( a int, new_a int );
|
||||||
|
INSERT INTO t2_tmp VALUES (1,51),(2,52),(3,53);
|
||||||
|
UPDATE t1 SET a = (SELECT new_a FROM t2_tmp WHERE t2_tmp.a = t1.a) WHERE a = 1;
|
||||||
|
UPDATE t1 SET a = (SELECT new_a FROM t2_tmp WHERE t2_tmp.a = t1.a) WHERE a = 2;
|
||||||
|
INSERT INTO t1_tmp (b) SELECT b FROM t1 WHERE a = 1;
|
||||||
|
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||||
|
Reap the server message for connection user2 UPDATE t1 ...
|
||||||
|
UPDATE t1 SET a = (SELECT new_a FROM t2_tmp WHERE t2_tmp.a = t1.a) WHERE a = 3;
|
||||||
|
DROP TABLE t1;
|
@ -369,4 +369,14 @@ drop table t1;
|
|||||||
1
|
1
|
||||||
drop table t1;
|
drop table t1;
|
||||||
shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql
|
shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql
|
||||||
|
set @@global.server_id= 4294967295;
|
||||||
|
reset master;
|
||||||
|
select
|
||||||
|
(@a:=load_file("MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug37313.binlog"))
|
||||||
|
is not null;
|
||||||
|
(@a:=load_file("MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug37313.binlog"))
|
||||||
|
is not null
|
||||||
|
1
|
||||||
|
*** Unsigned server_id 4294967295 is found: 1 ***
|
||||||
|
set @@global.server_id= 1;
|
||||||
End of 5.0 tests
|
End of 5.0 tests
|
||||||
|
@ -443,3 +443,17 @@ SELECT ROW(a, 1) IN (SELECT SUM(b), 3) FROM t1 GROUP BY a;
|
|||||||
ROW(a, 1) IN (SELECT SUM(b), 3)
|
ROW(a, 1) IN (SELECT SUM(b), 3)
|
||||||
0
|
0
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
create table t1 (a varchar(200),
|
||||||
|
b int unsigned not null primary key auto_increment)
|
||||||
|
default character set 'utf8';
|
||||||
|
create table t2 (c varchar(200),
|
||||||
|
d int unsigned not null primary key auto_increment)
|
||||||
|
default character set 'latin1';
|
||||||
|
insert into t1 (a) values('abc');
|
||||||
|
insert into t2 (c) values('abc');
|
||||||
|
select * from t1,t2 where (a,b) = (c,d);
|
||||||
|
a b c d
|
||||||
|
abc 1 abc 1
|
||||||
|
select host,user from mysql.user where (host,user) = ('localhost','test');
|
||||||
|
host user
|
||||||
|
drop table t1,t2;
|
||||||
|
77
mysql-test/t/innodb_bug42419.test
Normal file
77
mysql-test/t/innodb_bug42419.test
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#
|
||||||
|
# Testcase for InnoDB
|
||||||
|
# Bug#42419 Server crash with "Pure virtual method called" on two concurrent connections
|
||||||
|
#
|
||||||
|
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
|
let $innodb_lock_wait_timeout= query_get_value(SHOW VARIABLES LIKE 'innodb_lock_wait_timeout%', Value, 1);
|
||||||
|
if (`SELECT $innodb_lock_wait_timeout < 10`)
|
||||||
|
{
|
||||||
|
--echo # innodb_lock_wait_timeout must be >= 10 seconds
|
||||||
|
--echo # so that this test can work all time fine on an overloaded testing box
|
||||||
|
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Save the initial number of concurrent sessions
|
||||||
|
--source include/count_sessions.inc
|
||||||
|
|
||||||
|
# First session
|
||||||
|
connection default;
|
||||||
|
|
||||||
|
|
||||||
|
--enable_warnings
|
||||||
|
CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b INT) ENGINE = InnoDB;
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
|
||||||
|
COMMIT;
|
||||||
|
SET AUTOCOMMIT = 0;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE t1_tmp ( b INT );
|
||||||
|
|
||||||
|
INSERT INTO t1_tmp (b) SELECT b FROM t1 WHERE a = 3;
|
||||||
|
INSERT INTO t1_tmp (b) SELECT b FROM t1 WHERE a = 2;
|
||||||
|
|
||||||
|
# Second session
|
||||||
|
connect (user2,localhost,root,,,$MASTER_MYPORT,$MASTER_MYSOCK);
|
||||||
|
|
||||||
|
SET AUTOCOMMIT = 0;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE t2_tmp ( a int, new_a int );
|
||||||
|
INSERT INTO t2_tmp VALUES (1,51),(2,52),(3,53);
|
||||||
|
|
||||||
|
UPDATE t1 SET a = (SELECT new_a FROM t2_tmp WHERE t2_tmp.a = t1.a) WHERE a = 1;
|
||||||
|
send
|
||||||
|
UPDATE t1 SET a = (SELECT new_a FROM t2_tmp WHERE t2_tmp.a = t1.a) WHERE a = 2;
|
||||||
|
|
||||||
|
# The last update will wait for a lock held by the first session
|
||||||
|
|
||||||
|
# First session
|
||||||
|
connection default;
|
||||||
|
|
||||||
|
# Poll till the UPDATE of the second session waits for lock
|
||||||
|
let $show_statement= SHOW PROCESSLIST;
|
||||||
|
let $field= State;
|
||||||
|
let $condition= = 'Updating';
|
||||||
|
--source include/wait_show_condition.inc
|
||||||
|
|
||||||
|
# If the testing box is overloadeded and innodb_lock_wait_timeout is too small
|
||||||
|
# we might get here ER_LOCK_WAIT_TIMEOUT.
|
||||||
|
--error ER_LOCK_DEADLOCK
|
||||||
|
INSERT INTO t1_tmp (b) SELECT b FROM t1 WHERE a = 1;
|
||||||
|
|
||||||
|
# Second session
|
||||||
|
connection user2;
|
||||||
|
--echo Reap the server message for connection user2 UPDATE t1 ...
|
||||||
|
reap;
|
||||||
|
|
||||||
|
# The server crashed when executing this UPDATE or the succeeding SQL command.
|
||||||
|
UPDATE t1 SET a = (SELECT new_a FROM t2_tmp WHERE t2_tmp.a = t1.a) WHERE a = 3;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
disconnect user2;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
# Wait till all disconnects are completed
|
||||||
|
--source include/wait_until_count_sessions.inc
|
@ -272,4 +272,24 @@ echo shell> mysqlbinlog std_data/corrupt-relay-bin.000624 > var/tmp/bug31793.sql
|
|||||||
error 1;
|
error 1;
|
||||||
exec $MYSQL_BINLOG $MYSQL_TEST_DIR/std_data/corrupt-relay-bin.000624 > $MYSQLTEST_VARDIR/tmp/bug31793.sql;
|
exec $MYSQL_BINLOG $MYSQL_TEST_DIR/std_data/corrupt-relay-bin.000624 > $MYSQLTEST_VARDIR/tmp/bug31793.sql;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #37313 BINLOG Contains Incorrect server id
|
||||||
|
#
|
||||||
|
|
||||||
|
let $save_server_id= `select @@global.server_id`;
|
||||||
|
let $s_id_max=`select (1 << 32) - 1`;
|
||||||
|
eval set @@global.server_id= $s_id_max;
|
||||||
|
|
||||||
|
reset master;
|
||||||
|
--exec $MYSQL_BINLOG $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug37313.binlog
|
||||||
|
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
|
||||||
|
eval select
|
||||||
|
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug37313.binlog"))
|
||||||
|
is not null;
|
||||||
|
let $s_id_unsigned= `select @a like "%server id $s_id_max%" /* must return 1 */`;
|
||||||
|
echo *** Unsigned server_id $s_id_max is found: $s_id_unsigned ***;
|
||||||
|
|
||||||
|
eval set @@global.server_id= $save_server_id;
|
||||||
|
--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug37313.binlog
|
||||||
|
|
||||||
--echo End of 5.0 tests
|
--echo End of 5.0 tests
|
||||||
|
@ -237,3 +237,21 @@ SELECT ROW(a, 1) IN (SELECT SUM(b), 1) FROM t1 GROUP BY a;
|
|||||||
SELECT ROW(a, 1) IN (SELECT SUM(b), 3) FROM t1 GROUP BY a;
|
SELECT ROW(a, 1) IN (SELECT SUM(b), 3) FROM t1 GROUP BY a;
|
||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug#37601 Cast Is Not Done On Row Comparison
|
||||||
|
#
|
||||||
|
create table t1 (a varchar(200),
|
||||||
|
b int unsigned not null primary key auto_increment)
|
||||||
|
default character set 'utf8';
|
||||||
|
|
||||||
|
create table t2 (c varchar(200),
|
||||||
|
d int unsigned not null primary key auto_increment)
|
||||||
|
default character set 'latin1';
|
||||||
|
|
||||||
|
insert into t1 (a) values('abc');
|
||||||
|
insert into t2 (c) values('abc');
|
||||||
|
select * from t1,t2 where (a,b) = (c,d);
|
||||||
|
|
||||||
|
select host,user from mysql.user where (host,user) = ('localhost','test');
|
||||||
|
drop table t1,t2;
|
||||||
|
75
sql/item.cc
75
sql/item.cc
@ -1608,42 +1608,11 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Collect arguments' character sets together.
|
|
||||||
We allow to apply automatic character set conversion in some cases.
|
|
||||||
The conditions when conversion is possible are:
|
|
||||||
- arguments A and B have different charsets
|
|
||||||
- A wins according to coercibility rules
|
|
||||||
(i.e. a column is stronger than a string constant,
|
|
||||||
an explicit COLLATE clause is stronger than a column)
|
|
||||||
- character set of A is either superset for character set of B,
|
|
||||||
or B is a string constant which can be converted into the
|
|
||||||
character set of A without data loss.
|
|
||||||
|
|
||||||
If all of the above is true, then it's possible to convert
|
bool agg_item_set_converter(DTCollation &coll, const char *fname,
|
||||||
B into the character set of A, and then compare according
|
|
||||||
to the collation of A.
|
|
||||||
|
|
||||||
For functions with more than two arguments:
|
|
||||||
|
|
||||||
collect(A,B,C) ::= collect(collect(A,B),C)
|
|
||||||
|
|
||||||
Since this function calls THD::change_item_tree() on the passed Item **
|
|
||||||
pointers, it is necessary to pass the original Item **'s, not copies.
|
|
||||||
Otherwise their values will not be properly restored (see BUG#20769).
|
|
||||||
If the items are not consecutive (eg. args[2] and args[5]), use the
|
|
||||||
item_sep argument, ie.
|
|
||||||
|
|
||||||
agg_item_charsets(coll, fname, &args[2], 2, flags, 3)
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool agg_item_charsets(DTCollation &coll, const char *fname,
|
|
||||||
Item **args, uint nargs, uint flags, int item_sep)
|
Item **args, uint nargs, uint flags, int item_sep)
|
||||||
{
|
{
|
||||||
Item **arg, *safe_args[2];
|
Item **arg, *safe_args[2];
|
||||||
if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For better error reporting: save the first and the second argument.
|
For better error reporting: save the first and the second argument.
|
||||||
@ -1724,6 +1693,46 @@ bool agg_item_charsets(DTCollation &coll, const char *fname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Collect arguments' character sets together.
|
||||||
|
We allow to apply automatic character set conversion in some cases.
|
||||||
|
The conditions when conversion is possible are:
|
||||||
|
- arguments A and B have different charsets
|
||||||
|
- A wins according to coercibility rules
|
||||||
|
(i.e. a column is stronger than a string constant,
|
||||||
|
an explicit COLLATE clause is stronger than a column)
|
||||||
|
- character set of A is either superset for character set of B,
|
||||||
|
or B is a string constant which can be converted into the
|
||||||
|
character set of A without data loss.
|
||||||
|
|
||||||
|
If all of the above is true, then it's possible to convert
|
||||||
|
B into the character set of A, and then compare according
|
||||||
|
to the collation of A.
|
||||||
|
|
||||||
|
For functions with more than two arguments:
|
||||||
|
|
||||||
|
collect(A,B,C) ::= collect(collect(A,B),C)
|
||||||
|
|
||||||
|
Since this function calls THD::change_item_tree() on the passed Item **
|
||||||
|
pointers, it is necessary to pass the original Item **'s, not copies.
|
||||||
|
Otherwise their values will not be properly restored (see BUG#20769).
|
||||||
|
If the items are not consecutive (eg. args[2] and args[5]), use the
|
||||||
|
item_sep argument, ie.
|
||||||
|
|
||||||
|
agg_item_charsets(coll, fname, &args[2], 2, flags, 3)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool agg_item_charsets(DTCollation &coll, const char *fname,
|
||||||
|
Item **args, uint nargs, uint flags, int item_sep)
|
||||||
|
{
|
||||||
|
if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return agg_item_set_converter(coll, fname, args, nargs, flags, item_sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_ident_for_show::make_field(Send_field *tmp_field)
|
void Item_ident_for_show::make_field(Send_field *tmp_field)
|
||||||
{
|
{
|
||||||
tmp_field->table_name= tmp_field->org_table_name= table_name;
|
tmp_field->table_name= tmp_field->org_table_name= table_name;
|
||||||
@ -3010,7 +3019,7 @@ bool Item_param::convert_str_value(THD *thd)
|
|||||||
str_value.set_charset(value.cs_info.final_character_set_of_str_value);
|
str_value.set_charset(value.cs_info.final_character_set_of_str_value);
|
||||||
/* Here str_value is guaranteed to be in final_character_set_of_str_value */
|
/* Here str_value is guaranteed to be in final_character_set_of_str_value */
|
||||||
|
|
||||||
max_length= str_value.length();
|
max_length= str_value.numchars() * str_value.charset()->mbmaxlen;
|
||||||
decimals= 0;
|
decimals= 0;
|
||||||
/*
|
/*
|
||||||
str_value_ptr is returned from val_str(). It must be not alloced
|
str_value_ptr is returned from val_str(). It must be not alloced
|
||||||
|
@ -1169,6 +1169,8 @@ bool agg_item_collations(DTCollation &c, const char *name,
|
|||||||
Item **items, uint nitems, uint flags, int item_sep);
|
Item **items, uint nitems, uint flags, int item_sep);
|
||||||
bool agg_item_collations_for_comparison(DTCollation &c, const char *name,
|
bool agg_item_collations_for_comparison(DTCollation &c, const char *name,
|
||||||
Item **items, uint nitems, uint flags);
|
Item **items, uint nitems, uint flags);
|
||||||
|
bool agg_item_set_converter(DTCollation &coll, const char *fname,
|
||||||
|
Item **args, uint nargs, uint flags, int item_sep);
|
||||||
bool agg_item_charsets(DTCollation &c, const char *name,
|
bool agg_item_charsets(DTCollation &c, const char *name,
|
||||||
Item **items, uint nitems, uint flags, int item_sep);
|
Item **items, uint nitems, uint flags, int item_sep);
|
||||||
|
|
||||||
|
@ -490,7 +490,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
|
|||||||
my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
|
my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
|
if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)))
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -835,6 +836,16 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
|
|||||||
get_value_func= &get_time_value;
|
get_value_func= &get_time_value;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else if (type == STRING_RESULT &&
|
||||||
|
(*a)->result_type() == STRING_RESULT &&
|
||||||
|
(*b)->result_type() == STRING_RESULT)
|
||||||
|
{
|
||||||
|
DTCollation coll;
|
||||||
|
coll.set((*a)->collation.collation);
|
||||||
|
if (agg_item_set_converter(coll, owner_arg->func_name(),
|
||||||
|
b, 1, MY_COLL_CMP_CONV, 1))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return set_compare_func(owner_arg, type);
|
return set_compare_func(owner_arg, type);
|
||||||
}
|
}
|
||||||
|
@ -976,7 +976,7 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info)
|
|||||||
|
|
||||||
fputc('#', file);
|
fputc('#', file);
|
||||||
print_timestamp(file);
|
print_timestamp(file);
|
||||||
fprintf(file, " server id %d end_log_pos %s ", server_id,
|
fprintf(file, " server id %lu end_log_pos %s ", server_id,
|
||||||
llstr(log_pos,llbuff));
|
llstr(log_pos,llbuff));
|
||||||
|
|
||||||
/* mysqlbinlog --hexdump */
|
/* mysqlbinlog --hexdump */
|
||||||
|
@ -2373,11 +2373,12 @@ typedef struct st_sargable_param
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
|
||||||
DYNAMIC_ARRAY *keyuse_array)
|
DYNAMIC_ARRAY *keyuse_array)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
|
TABLE_LIST *tables= tables_arg;
|
||||||
uint i,table_count,const_count,key;
|
uint i,table_count,const_count,key;
|
||||||
table_map found_const_table_map, all_table_map, found_ref, refs;
|
table_map found_const_table_map, all_table_map, found_ref, refs;
|
||||||
key_map const_ref, eq_part;
|
key_map const_ref, eq_part;
|
||||||
@ -2415,10 +2416,10 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
table_vector[i]=s->table=table=tables->table;
|
table_vector[i]=s->table=table=tables->table;
|
||||||
table->pos_in_table_list= tables;
|
table->pos_in_table_list= tables;
|
||||||
error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
||||||
if(error)
|
if (error)
|
||||||
{
|
{
|
||||||
table->file->print_error(error, MYF(0));
|
table->file->print_error(error, MYF(0));
|
||||||
DBUG_RETURN(1);
|
goto error;
|
||||||
}
|
}
|
||||||
table->quick_keys.clear_all();
|
table->quick_keys.clear_all();
|
||||||
table->reginfo.join_tab=s;
|
table->reginfo.join_tab=s;
|
||||||
@ -2503,7 +2504,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
{
|
{
|
||||||
join->tables=0; // Don't use join->table
|
join->tables=0; // Don't use join->table
|
||||||
my_message(ER_WRONG_OUTER_JOIN, ER(ER_WRONG_OUTER_JOIN), MYF(0));
|
my_message(ER_WRONG_OUTER_JOIN, ER(ER_WRONG_OUTER_JOIN), MYF(0));
|
||||||
DBUG_RETURN(1);
|
goto error;
|
||||||
}
|
}
|
||||||
s->key_dependent= s->dependent;
|
s->key_dependent= s->dependent;
|
||||||
}
|
}
|
||||||
@ -2513,7 +2514,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
|
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
|
||||||
conds, join->cond_equal,
|
conds, join->cond_equal,
|
||||||
~outer_join, join->select_lex, &sargables))
|
~outer_join, join->select_lex, &sargables))
|
||||||
DBUG_RETURN(1);
|
goto error;
|
||||||
|
|
||||||
/* Read tables with 0 or 1 rows (system tables) */
|
/* Read tables with 0 or 1 rows (system tables) */
|
||||||
join->const_table_map= 0;
|
join->const_table_map= 0;
|
||||||
@ -2529,7 +2530,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
if ((tmp=join_read_const_table(s, p_pos)))
|
if ((tmp=join_read_const_table(s, p_pos)))
|
||||||
{
|
{
|
||||||
if (tmp > 0)
|
if (tmp > 0)
|
||||||
DBUG_RETURN(1); // Fatal error
|
goto error; // Fatal error
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
found_const_table_map|= s->table->map;
|
found_const_table_map|= s->table->map;
|
||||||
@ -2601,7 +2602,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
if ((tmp= join_read_const_table(s, join->positions+const_count-1)))
|
if ((tmp= join_read_const_table(s, join->positions+const_count-1)))
|
||||||
{
|
{
|
||||||
if (tmp > 0)
|
if (tmp > 0)
|
||||||
DBUG_RETURN(1); // Fatal error
|
goto error; // Fatal error
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
found_const_table_map|= table->map;
|
found_const_table_map|= table->map;
|
||||||
@ -2650,12 +2651,12 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
set_position(join,const_count++,s,start_keyuse);
|
set_position(join,const_count++,s,start_keyuse);
|
||||||
if (create_ref_for_key(join, s, start_keyuse,
|
if (create_ref_for_key(join, s, start_keyuse,
|
||||||
found_const_table_map))
|
found_const_table_map))
|
||||||
DBUG_RETURN(1);
|
goto error;
|
||||||
if ((tmp=join_read_const_table(s,
|
if ((tmp=join_read_const_table(s,
|
||||||
join->positions+const_count-1)))
|
join->positions+const_count-1)))
|
||||||
{
|
{
|
||||||
if (tmp > 0)
|
if (tmp > 0)
|
||||||
DBUG_RETURN(1); // Fatal error
|
goto error; // Fatal error
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
found_const_table_map|= table->map;
|
found_const_table_map|= table->map;
|
||||||
@ -2732,7 +2733,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
*s->on_expr_ref ? *s->on_expr_ref : conds,
|
*s->on_expr_ref ? *s->on_expr_ref : conds,
|
||||||
1, &error);
|
1, &error);
|
||||||
if (!select)
|
if (!select)
|
||||||
DBUG_RETURN(1);
|
goto error;
|
||||||
records= get_quick_record_count(join->thd, select, s->table,
|
records= get_quick_record_count(join->thd, select, s->table,
|
||||||
&s->const_keys, join->row_limit);
|
&s->const_keys, join->row_limit);
|
||||||
s->quick=select->quick;
|
s->quick=select->quick;
|
||||||
@ -2778,7 +2779,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
{
|
{
|
||||||
optimize_keyuse(join, keyuse_array);
|
optimize_keyuse(join, keyuse_array);
|
||||||
if (choose_plan(join, all_table_map & ~join->const_table_map))
|
if (choose_plan(join, all_table_map & ~join->const_table_map))
|
||||||
DBUG_RETURN(TRUE);
|
goto error;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2788,6 +2789,17 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
}
|
}
|
||||||
/* Generate an execution plan from the found optimal join order. */
|
/* Generate an execution plan from the found optimal join order. */
|
||||||
DBUG_RETURN(join->thd->killed || get_best_combination(join));
|
DBUG_RETURN(join->thd->killed || get_best_combination(join));
|
||||||
|
|
||||||
|
error:
|
||||||
|
/*
|
||||||
|
Need to clean up join_tab from TABLEs in case of error.
|
||||||
|
They won't get cleaned up by JOIN::cleanup() because JOIN::join_tab
|
||||||
|
may not be assigned yet by this function (which is building join_tab).
|
||||||
|
Dangling TABLE::reginfo.join_tab may cause part_of_refkey to choke.
|
||||||
|
*/
|
||||||
|
for (tables= tables_arg; tables; tables= tables->next_leaf)
|
||||||
|
tables->table->reginfo.join_tab= NULL;
|
||||||
|
DBUG_RETURN (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -16410,6 +16410,69 @@ static void test_bug36326()
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Bug#41078: With CURSOR_TYPE_READ_ONLY mysql_stmt_fetch() returns short
|
||||||
|
string value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void test_bug41078(void)
|
||||||
|
{
|
||||||
|
uint rc;
|
||||||
|
MYSQL_STMT *stmt= 0;
|
||||||
|
MYSQL_BIND param, result;
|
||||||
|
ulong cursor_type= CURSOR_TYPE_READ_ONLY;
|
||||||
|
ulong len;
|
||||||
|
char str[64];
|
||||||
|
const char param_str[]= "abcdefghijklmn";
|
||||||
|
my_bool is_null, error;
|
||||||
|
|
||||||
|
DBUG_ENTER("test_bug41078");
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "SET NAMES UTF8");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
stmt= mysql_simple_prepare(mysql, "SELECT ?");
|
||||||
|
check_stmt(stmt);
|
||||||
|
verify_param_count(stmt, 1);
|
||||||
|
|
||||||
|
rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &cursor_type);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
bzero(¶m, sizeof(param));
|
||||||
|
param.buffer_type= MYSQL_TYPE_STRING;
|
||||||
|
param.buffer= (void *) param_str;
|
||||||
|
len= sizeof(param_str) - 1;
|
||||||
|
param.length= &len;
|
||||||
|
|
||||||
|
rc= mysql_stmt_bind_param(stmt, ¶m);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
bzero(&result, sizeof(result));
|
||||||
|
result.buffer_type= MYSQL_TYPE_STRING;
|
||||||
|
result.buffer= str;
|
||||||
|
result.buffer_length= sizeof(str);
|
||||||
|
result.is_null= &is_null;
|
||||||
|
result.length= &len;
|
||||||
|
result.error= &error;
|
||||||
|
|
||||||
|
rc= mysql_stmt_bind_result(stmt, &result);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_stmt_store_result(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
check_execute(stmt, rc);
|
||||||
|
|
||||||
|
DIE_UNLESS(len == sizeof(param_str) - 1 && !strcmp(str, param_str));
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read and parse arguments and MySQL options from my.cnf
|
Read and parse arguments and MySQL options from my.cnf
|
||||||
@ -16713,6 +16776,7 @@ static struct my_tests_st my_tests[]= {
|
|||||||
#ifdef HAVE_QUERY_CACHE
|
#ifdef HAVE_QUERY_CACHE
|
||||||
{ "test_bug36326", test_bug36326 },
|
{ "test_bug36326", test_bug36326 },
|
||||||
#endif
|
#endif
|
||||||
|
{ "test_bug41078", test_bug41078 },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user