Commit 70a515df authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

Merge branch '10.6.12' into 10.6

parents 4c79e15c 80ae69c8
MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MAJOR=10
MYSQL_VERSION_MINOR=6 MYSQL_VERSION_MINOR=6
MYSQL_VERSION_PATCH=12 MYSQL_VERSION_PATCH=13
SERVER_MATURITY=stable SERVER_MATURITY=stable
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
#include <m_string.h> #include <m_string.h>
#include <errno.h> #include <errno.h>
#ifdef HAVE_gcov #ifdef HAVE_gcov
extern void __gcov_flush(); #include <gcov.h>
#endif #endif
#ifndef DBUG_OFF #ifndef DBUG_OFF
...@@ -2212,7 +2212,7 @@ void _db_suicide_() ...@@ -2212,7 +2212,7 @@ void _db_suicide_()
fprintf(stderr, "SIGKILL myself\n"); fprintf(stderr, "SIGKILL myself\n");
fflush(stderr); fflush(stderr);
#ifdef HAVE_gcov #ifdef HAVE_gcov
__gcov_flush(); __gcov_dump();
#endif #endif
retval= kill(getpid(), SIGKILL); retval= kill(getpid(), SIGKILL);
...@@ -2262,7 +2262,7 @@ my_bool _db_my_assert(const char *file, int line, const char *msg) ...@@ -2262,7 +2262,7 @@ my_bool _db_my_assert(const char *file, int line, const char *msg)
fprintf(stderr, "%s:%d: assert: %s\n", file, line, msg); fprintf(stderr, "%s:%d: assert: %s\n", file, line, msg);
fflush(stderr); fflush(stderr);
#ifdef HAVE_gcov #ifdef HAVE_gcov
__gcov_flush(); __gcov_dump();
#endif #endif
} }
return a; return a;
......
...@@ -2,7 +2,7 @@ SET DEBUG_SYNC= 'RESET'; ...@@ -2,7 +2,7 @@ SET DEBUG_SYNC= 'RESET';
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: '' debug_sync ON - current signals: ''
SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3';
SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2';
SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3';
...@@ -150,34 +150,34 @@ SET @myvar= 'now SIGNAL from_myvar'; ...@@ -150,34 +150,34 @@ SET @myvar= 'now SIGNAL from_myvar';
SET DEBUG_SYNC= @myvar; SET DEBUG_SYNC= @myvar;
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 'from_myvar' debug_sync ON - current signals: 'from_myvar'
SET DEBUG_SYNC= LEFT('now SIGNAL from_function_cut_here', 24); SET DEBUG_SYNC= LEFT('now SIGNAL from_function_cut_here', 24);
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 'from_function' debug_sync ON - current signals: 'from_myvar,from_function'
SET DEBUG_SYNC= 'now SIGNAL something'; SET DEBUG_SYNC= 'now SIGNAL something';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 'something' debug_sync ON - current signals: 'something,from_function,from_myvar'
SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
Warnings: Warnings:
Warning #### debug sync point wait timed out Warning #### debug sync point wait timed out
SET DEBUG_SYNC= 'now SIGNAL nothing'; SET DEBUG_SYNC= 'now SIGNAL nothing';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 'nothing' debug_sync ON - current signals: 'something,from_function,nothing,from_myvar'
SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0';
SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0'; SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 'nothing' debug_sync ON - current signals: 'something,from_function,from_myvar'
SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0'; SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0';
SET DEBUG_SYNC= 'now HIT_LIMIT 1'; SET DEBUG_SYNC= 'now HIT_LIMIT 1';
ERROR HY000: debug sync point hit limit reached ERROR HY000: debug sync point hit limit reached
SET DEBUG_SYNC= 'RESET'; SET DEBUG_SYNC= 'RESET';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: '' debug_sync ON - current signals: ''
SET DEBUG_SYNC= 'p1abcd SIGNAL s1 EXECUTE 2'; SET DEBUG_SYNC= 'p1abcd SIGNAL s1 EXECUTE 2';
SET DEBUG_SYNC= 'p2abc SIGNAL s2 EXECUTE 2'; SET DEBUG_SYNC= 'p2abc SIGNAL s2 EXECUTE 2';
SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2'; SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2';
...@@ -190,23 +190,30 @@ SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2'; ...@@ -190,23 +190,30 @@ SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2';
SET DEBUG_SYNC= 'p4a TEST'; SET DEBUG_SYNC= 'p4a TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 's4' debug_sync ON - current signals: 's4'
SET DEBUG_SYNC= 'p1abcd TEST'; SET DEBUG_SYNC= 'p1abcd TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 's1' debug_sync ON - current signals: 's4,s1'
SET DEBUG_SYNC= 'p7 TEST'; SET DEBUG_SYNC= 'p7 TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 's7' debug_sync ON - current signals: 's1,s7,s4'
SET DEBUG_SYNC= 'p9abcdef TEST'; SET DEBUG_SYNC= 'p9abcdef TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 's9' debug_sync ON - current signals: 's1,s7,s4,s9'
SET DEBUG_SYNC= 'p3abcdef TEST'; SET DEBUG_SYNC= 'p3abcdef TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 's3' debug_sync ON - current signals: 's1,s3,s4,s9,s7'
SET DEBUG_SYNC= 'now WAIT_FOR s9';
SET DEBUG_SYNC= 'now WAIT_FOR s1';
SET DEBUG_SYNC= 'now WAIT_FOR s4';
SET DEBUG_SYNC= 'now WAIT_FOR s7';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value
debug_sync ON - current signals: 's3'
SET DEBUG_SYNC= 'p1abcd CLEAR'; SET DEBUG_SYNC= 'p1abcd CLEAR';
SET DEBUG_SYNC= 'p2abc CLEAR'; SET DEBUG_SYNC= 'p2abc CLEAR';
SET DEBUG_SYNC= 'p5abcde CLEAR'; SET DEBUG_SYNC= 'p5abcde CLEAR';
...@@ -219,19 +226,19 @@ SET DEBUG_SYNC= 'p7 CLEAR'; ...@@ -219,19 +226,19 @@ SET DEBUG_SYNC= 'p7 CLEAR';
SET DEBUG_SYNC= 'p1abcd TEST'; SET DEBUG_SYNC= 'p1abcd TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 's3' debug_sync ON - current signals: 's3'
SET DEBUG_SYNC= 'p7 TEST'; SET DEBUG_SYNC= 'p7 TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 's3' debug_sync ON - current signals: 's3'
SET DEBUG_SYNC= 'p9abcdef TEST'; SET DEBUG_SYNC= 'p9abcdef TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: 's3' debug_sync ON - current signals: 's3'
SET DEBUG_SYNC= 'RESET'; SET DEBUG_SYNC= 'RESET';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value Variable_name Value
debug_sync ON - current signal: '' debug_sync ON - current signals: ''
CREATE USER mysqltest_1@localhost; CREATE USER mysqltest_1@localhost;
GRANT SUPER ON *.* TO mysqltest_1@localhost; GRANT SUPER ON *.* TO mysqltest_1@localhost;
connect con1,localhost,mysqltest_1,,; connect con1,localhost,mysqltest_1,,;
...@@ -292,4 +299,24 @@ disconnect con1; ...@@ -292,4 +299,24 @@ disconnect con1;
disconnect con2; disconnect con2;
connection default; connection default;
DROP TABLE t1; DROP TABLE t1;
#
# Test NO_CLEAR_EVENT flag. The signal should still be visible after
# the wait has completed succesfully.
#
SET DEBUG_SYNC= 'now SIGNAL s1';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value
debug_sync ON - current signals: 's1'
SET DEBUG_SYNC= 'now WAIT_FOR s1 NO_CLEAR_EVENT';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value
debug_sync ON - current signals: 's1'
SET DEBUG_SYNC= 'now WAIT_FOR s1';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value
debug_sync ON - current signals: ''
SET DEBUG_SYNC= 'now SIGNAL s1,s2,s5,s7';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
Variable_name Value
debug_sync ON - current signals: 's2,s7,s1,s5'
SET DEBUG_SYNC= 'RESET'; SET DEBUG_SYNC= 'RESET';
...@@ -298,6 +298,16 @@ SET DEBUG_SYNC= 'p9abcdef TEST'; ...@@ -298,6 +298,16 @@ SET DEBUG_SYNC= 'p9abcdef TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
SET DEBUG_SYNC= 'p3abcdef TEST'; SET DEBUG_SYNC= 'p3abcdef TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
#
# Wait for all signals currently active except s3.
#
SET DEBUG_SYNC= 'now WAIT_FOR s9';
SET DEBUG_SYNC= 'now WAIT_FOR s1';
SET DEBUG_SYNC= 'now WAIT_FOR s4';
SET DEBUG_SYNC= 'now WAIT_FOR s7';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
# #
# Clear the actions. # Clear the actions.
# #
...@@ -320,7 +330,7 @@ SHOW VARIABLES LIKE 'DEBUG_SYNC'; ...@@ -320,7 +330,7 @@ SHOW VARIABLES LIKE 'DEBUG_SYNC';
SET DEBUG_SYNC= 'p9abcdef TEST'; SET DEBUG_SYNC= 'p9abcdef TEST';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
# #
# Now cleanup. Actions are clear already, but signal needs to be cleared. # Now cleanup. Actions are clear already, but s3 signal needs to be cleared.
# #
SET DEBUG_SYNC= 'RESET'; SET DEBUG_SYNC= 'RESET';
SHOW VARIABLES LIKE 'DEBUG_SYNC'; SHOW VARIABLES LIKE 'DEBUG_SYNC';
...@@ -418,10 +428,24 @@ disconnect con2; ...@@ -418,10 +428,24 @@ disconnect con2;
connection default; connection default;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # Test NO_CLEAR_EVENT flag. The signal should still be visible after
--echo # the wait has completed succesfully.
--echo #
SET DEBUG_SYNC= 'now SIGNAL s1';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
SET DEBUG_SYNC= 'now WAIT_FOR s1 NO_CLEAR_EVENT';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
SET DEBUG_SYNC= 'now WAIT_FOR s1';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
SET DEBUG_SYNC= 'now SIGNAL s1,s2,s5,s7';
SHOW VARIABLES LIKE 'DEBUG_SYNC';
# #
# Cleanup after test case. # Cleanup after test case.
# Otherwise signal would contain 'flushed' here, # Otherwise signal would confuse the next test.
# which could confuse the next test.
# #
SET DEBUG_SYNC= 'RESET'; SET DEBUG_SYNC= 'RESET';
...@@ -145,6 +145,7 @@ my $opt_start_exit; ...@@ -145,6 +145,7 @@ my $opt_start_exit;
my $start_only; my $start_only;
my $file_wsrep_provider; my $file_wsrep_provider;
my $num_saved_cores= 0; # Number of core files saved in vardir/log/ so far. my $num_saved_cores= 0; # Number of core files saved in vardir/log/ so far.
my $test_name_for_report;
our @global_suppressions; our @global_suppressions;
...@@ -515,13 +516,13 @@ sub main { ...@@ -515,13 +516,13 @@ sub main {
} }
if ( not @$completed ) { if ( not @$completed ) {
my $test_name= mtr_grab_file($path_testlog); if ($test_name_for_report)
$test_name =~ s/^CURRENT_TEST:\s//; {
chomp($test_name); my $tinfo = My::Test->new(name => $test_name_for_report);
my $tinfo = My::Test->new(name => $test_name); $tinfo->{result}= 'MTR_RES_FAILED';
$tinfo->{result}= 'MTR_RES_FAILED'; $tinfo->{comment}=' ';
$tinfo->{comment}=' '; mtr_report_test($tinfo);
mtr_report_test($tinfo); }
mtr_error("Test suite aborted"); mtr_error("Test suite aborted");
} }
...@@ -3740,8 +3741,8 @@ sub resfile_report_test ($) { ...@@ -3740,8 +3741,8 @@ sub resfile_report_test ($) {
sub run_testcase ($$) { sub run_testcase ($$) {
my ($tinfo, $server_socket)= @_; my ($tinfo, $server_socket)= @_;
my $print_freq=20; my $print_freq=20;
$test_name_for_report= $tinfo->{name};
mtr_verbose("Running test:", $tinfo->{name}); mtr_verbose("Running test:", $test_name_for_report);
$ENV{'MTR_TEST_NAME'} = $tinfo->{name}; $ENV{'MTR_TEST_NAME'} = $tinfo->{name};
resfile_report_test($tinfo) if $opt_resfile; resfile_report_test($tinfo) if $opt_resfile;
...@@ -5130,12 +5131,10 @@ sub mysqld_start ($$) { ...@@ -5130,12 +5131,10 @@ sub mysqld_start ($$) {
if (!$rc) if (!$rc)
{ {
# Report failure about the last test case before exit # Report failure about the last test case before exit
my $test_name= mtr_grab_file($path_current_testlog); my $tinfo = My::Test->new(name => $test_name_for_report);
$test_name =~ s/^CURRENT_TEST:\s//;
my $tinfo = My::Test->new(name => $test_name);
$tinfo->{result}= 'MTR_RES_FAILED'; $tinfo->{result}= 'MTR_RES_FAILED';
$tinfo->{failures}= 1; $tinfo->{failures}= 1;
$tinfo->{logfile}=get_log_from_proc($mysqld->{'proc'}, $tinfo->{name}); $tinfo->{logfile}=get_log_from_proc($mysqld->{'proc'}, $test_name_for_report);
report_option('verbose', 1); report_option('verbose', 1);
mtr_report_test($tinfo); mtr_report_test($tinfo);
} }
......
...@@ -31,11 +31,12 @@ pk f1 f2 f3 ...@@ -31,11 +31,12 @@ pk f1 f2 f3
3 t q 1 3 t q 1
5 z t NULL 5 z t NULL
SET DEBUG_SYNC='now SIGNAL default_dml'; SET DEBUG_SYNC='now SIGNAL default_dml';
SET DEBUG_SYNC='now SIGNAL con2_dml';
connection default; connection default;
SET DEBUG_SYNC='now WAIT_FOR default_dml'; SET DEBUG_SYNC='now WAIT_FOR default_dml';
UPDATE t3 AS alias1 LEFT JOIN t3 AS alias2 ON ( alias1.f1 <> alias1.f2 ) SET alias1.f3 = 59 WHERE ( EXISTS ( SELECT t1.f3 FROM t1 WHERE t1.f1 = alias1.f1 ) ) OR alias2.f1 = 'h'; UPDATE t3 AS alias1 LEFT JOIN t3 AS alias2 ON ( alias1.f1 <> alias1.f2 ) SET alias1.f3 = 59 WHERE ( EXISTS ( SELECT t1.f3 FROM t1 WHERE t1.f1 = alias1.f1 ) ) OR alias2.f1 = 'h';
connect con2,localhost,root,,test; connect con2,localhost,root,,test;
set debug_sync='now WAIT_FOR default_dml'; set debug_sync='now WAIT_FOR con2_dml';
SET DEBUG_SYNC='now SIGNAL con1_dml2'; SET DEBUG_SYNC='now SIGNAL con1_dml2';
disconnect con2; disconnect con2;
connection con1; connection con1;
......
...@@ -35,6 +35,7 @@ SET DEBUG_SYNC='now WAIT_FOR con1_dml'; ...@@ -35,6 +35,7 @@ SET DEBUG_SYNC='now WAIT_FOR con1_dml';
begin; begin;
SELECT * FROM t1 for update; # Holds x lock of all records in the table t1 SELECT * FROM t1 for update; # Holds x lock of all records in the table t1
SET DEBUG_SYNC='now SIGNAL default_dml'; SET DEBUG_SYNC='now SIGNAL default_dml';
SET DEBUG_SYNC='now SIGNAL con2_dml';
--connection default --connection default
SET DEBUG_SYNC='now WAIT_FOR default_dml'; SET DEBUG_SYNC='now WAIT_FOR default_dml';
...@@ -42,7 +43,7 @@ SET DEBUG_SYNC='now WAIT_FOR default_dml'; ...@@ -42,7 +43,7 @@ SET DEBUG_SYNC='now WAIT_FOR default_dml';
# It holds the lock of all record in t3 and tries to acquire record lock for the table t1. # It holds the lock of all record in t3 and tries to acquire record lock for the table t1.
--connect (con2,localhost,root,,test) --connect (con2,localhost,root,,test)
set debug_sync='now WAIT_FOR default_dml'; set debug_sync='now WAIT_FOR con2_dml';
let $wait_condition= let $wait_condition=
select count(*) > 0 from information_schema.innodb_lock_waits; select count(*) > 0 from information_schema.innodb_lock_waits;
--source include/wait_condition.inc --source include/wait_condition.inc
......
...@@ -19,11 +19,12 @@ a b c ...@@ -19,11 +19,12 @@ a b c
1 NULL NULL 1 NULL NULL
set debug_sync='now SIGNAL go'; set debug_sync='now SIGNAL go';
set debug_sync='now WAIT_FOR parked2'; set debug_sync='now WAIT_FOR parked2';
set debug_sync='before_wait_for_refs SIGNAL waiting WAIT_FOR go2'; set debug_sync='before_wait_for_refs SIGNAL waiting WAIT_FOR go3';
drop table t1;; drop table t1;;
connection con2; connection con2;
set debug_sync='now WAIT_FOR waiting'; set debug_sync='now WAIT_FOR waiting';
set debug_sync='now SIGNAL go2'; set debug_sync='now SIGNAL go2';
set debug_sync='now SIGNAL go3';
connection default; connection default;
connection con1; connection con1;
connection default; connection default;
......
...@@ -20,15 +20,12 @@ set debug_sync='now WAIT_FOR parked'; ...@@ -20,15 +20,12 @@ set debug_sync='now WAIT_FOR parked';
select * from t1; select * from t1;
set debug_sync='now SIGNAL go'; set debug_sync='now SIGNAL go';
set debug_sync='now WAIT_FOR parked2'; set debug_sync='now WAIT_FOR parked2';
set debug_sync='before_wait_for_refs SIGNAL waiting WAIT_FOR go2'; set debug_sync='before_wait_for_refs SIGNAL waiting WAIT_FOR go3';
--send drop table t1; --send drop table t1;
--connection con2 --connection con2
set debug_sync='now WAIT_FOR waiting'; set debug_sync='now WAIT_FOR waiting';
set debug_sync='now SIGNAL go2'; set debug_sync='now SIGNAL go2';
set debug_sync='now SIGNAL go3';
# Write out show processlist if the debug sync point times out
let $wait_condition= select count(*)=0 from information_schema.processlist where state like "%debug%";
source include/wait_condition.inc;
--connection default --connection default
--reap --reap
......
...@@ -2,17 +2,17 @@ select @@global.debug_sync; ...@@ -2,17 +2,17 @@ select @@global.debug_sync;
ERROR HY000: Variable 'debug_sync' is a SESSION variable ERROR HY000: Variable 'debug_sync' is a SESSION variable
select @@session.debug_sync; select @@session.debug_sync;
@@session.debug_sync @@session.debug_sync
ON - current signal: '' ON - current signals: ''
show global variables like "debug_sync"; show global variables like "debug_sync";
Variable_name Value Variable_name Value
show session variables like "debug_sync"; show session variables like "debug_sync";
Variable_name Value Variable_name Value
debug_sync ON - current signal: '' debug_sync ON - current signals: ''
select * from information_schema.global_variables where variable_name="debug_sync"; select * from information_schema.global_variables where variable_name="debug_sync";
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
select * from information_schema.session_variables where variable_name="debug_sync"; select * from information_schema.session_variables where variable_name="debug_sync";
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
DEBUG_SYNC ON - current signal: '' DEBUG_SYNC ON - current signals: ''
set @@session.debug_sync=1; set @@session.debug_sync=1;
ERROR 42000: Incorrect argument type to variable 'debug_sync' ERROR 42000: Incorrect argument type to variable 'debug_sync'
set @@session.debug_sync=1.1; set @@session.debug_sync=1.1;
......
...@@ -77,7 +77,7 @@ READ_ONLY YES ...@@ -77,7 +77,7 @@ READ_ONLY YES
COMMAND_LINE_ARGUMENT OPTIONAL COMMAND_LINE_ARGUMENT OPTIONAL
GLOBAL_VALUE_PATH NULL GLOBAL_VALUE_PATH NULL
VARIABLE_NAME DEBUG_SYNC VARIABLE_NAME DEBUG_SYNC
SESSION_VALUE ON - current signal: '' SESSION_VALUE ON - current signals: ''
GLOBAL_VALUE NULL GLOBAL_VALUE NULL
GLOBAL_VALUE_ORIGIN COMPILE-TIME GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE DEFAULT_VALUE
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
#include <execinfo.h> #include <execinfo.h>
#endif #endif
#ifdef HAVE_gcov
#include <gcov.h>
#endif
/** /**
Default handler for printing stacktrace Default handler for printing stacktrace
*/ */
...@@ -409,9 +412,6 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack, ...@@ -409,9 +412,6 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack,
/* Produce a core for the thread */ /* Produce a core for the thread */
void my_write_core(int sig) void my_write_core(int sig)
{ {
#ifdef HAVE_gcov
extern void __gcov_flush(void);
#endif
signal(sig, SIG_DFL); signal(sig, SIG_DFL);
#ifdef HAVE_gcov #ifdef HAVE_gcov
/* /*
...@@ -419,7 +419,7 @@ void my_write_core(int sig) ...@@ -419,7 +419,7 @@ void my_write_core(int sig)
information from this process, causing gcov output to be incomplete. information from this process, causing gcov output to be incomplete.
So we force the writing of coverage information here before terminating. So we force the writing of coverage information here before terminating.
*/ */
__gcov_flush(); __gcov_dump();
#endif #endif
pthread_kill(pthread_self(), sig); pthread_kill(pthread_self(), sig);
#if defined(P_MYID) && !defined(SCO) #if defined(P_MYID) && !defined(SCO)
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "mariadb.h" #include "mariadb.h"
#include "debug_sync.h" #include "debug_sync.h"
#include <cstring>
#if defined(ENABLED_DEBUG_SYNC) #if defined(ENABLED_DEBUG_SYNC)
...@@ -48,6 +49,8 @@ struct st_debug_sync_action ...@@ -48,6 +49,8 @@ struct st_debug_sync_action
String wait_for; /* signal to wait for */ String wait_for; /* signal to wait for */
String sync_point; /* sync point name */ String sync_point; /* sync point name */
bool need_sort; /* if new action, array needs sort */ bool need_sort; /* if new action, array needs sort */
bool clear_event; /* do not clear signal when waited
for if false. */
}; };
/* Debug sync control. Referenced by THD. */ /* Debug sync control. Referenced by THD. */
...@@ -67,21 +70,99 @@ struct st_debug_sync_control ...@@ -67,21 +70,99 @@ struct st_debug_sync_control
}; };
/** /**
Definitions for the debug sync facility. Definitions for the debug sync facility.
1. Global string variable to hold a "signal" ("signal post", "flag mast"). 1. Global string variable to hold a set of of "signals".
2. Global condition variable for signaling and waiting. 2. Global condition variable for signaling and waiting.
3. Global mutex to synchronize access to the above. 3. Global mutex to synchronize access to the above.
*/ */
struct st_debug_sync_globals struct st_debug_sync_globals
{ {
String ds_signal; /* signal variable */ Hash_set<LEX_CSTRING> ds_signal_set; /* A set of active signals */
mysql_cond_t ds_cond; /* condition variable */ mysql_cond_t ds_cond; /* condition variable */
mysql_mutex_t ds_mutex; /* mutex variable */ mysql_mutex_t ds_mutex; /* mutex variable */
ulonglong dsp_hits; /* statistics */ ulonglong dsp_hits; /* statistics */
ulonglong dsp_executed; /* statistics */ ulonglong dsp_executed; /* statistics */
ulonglong dsp_max_active; /* statistics */ ulonglong dsp_max_active; /* statistics */
st_debug_sync_globals() : ds_signal_set(PSI_NOT_INSTRUMENTED, signal_key) {};
~st_debug_sync_globals()
{
clear_set();
}
void clear_set()
{
Hash_set<LEX_CSTRING>::Iterator it{ds_signal_set};
LEX_CSTRING *s;
while ((s= it++))
my_free(s);
ds_signal_set.clear();
}
/* Hash key function for ds_signal_set. */
static uchar *signal_key(const LEX_CSTRING *str, size_t *klen, my_bool)
{
*klen= str->length;
return (uchar*) str->str;
}
/**
Return true if the signal is found in global signal list.
@param signal_name Signal name identifying the signal.
@note
If signal is found in the global signal set, it means that the
signal thread has signalled to the waiting thread. This method
must be called with the debug_sync_global.ds_mutex held.
@retval true if signal is found in the global signal list.
@retval false otherwise.
*/
inline bool is_signalled(const char *signal_name, size_t length)
{
return ds_signal_set.find(signal_name, length);
}
void clear_signal(const String &signal_name)
{
DBUG_ENTER("clear_signal");
LEX_CSTRING *record= ds_signal_set.find(signal_name.ptr(),
signal_name.length());
if (record)
{
ds_signal_set.remove(record);
my_free(record);
}
DBUG_VOID_RETURN;
}
bool set_signal(const char *signal_name, size_t length)
{
/* Need to check if the signal is already in the hash set, because
Hash_set doesn't differentiate between OOM and key already in. */
if (is_signalled(signal_name, length))
return FALSE;
/* LEX_CSTRING and the string allocated with only one malloc. */
LEX_CSTRING *s= (LEX_CSTRING *) my_malloc(PSI_NOT_INSTRUMENTED,
sizeof(LEX_CSTRING) + length + 1,
MYF(0));
char *str= (char *)(s + 1);
memcpy(str, signal_name, length);
str[length]= '\0';
s->length= length;
s->str= str;
if (ds_signal_set.insert(s))
return TRUE;
return FALSE;
}
}; };
static st_debug_sync_globals debug_sync_global; /* All globals in one object */ static st_debug_sync_globals debug_sync_global; /* All globals in one object */
/** /**
...@@ -161,7 +242,7 @@ int debug_sync_init(void) ...@@ -161,7 +242,7 @@ int debug_sync_init(void)
int rc; int rc;
/* Initialize the global variables. */ /* Initialize the global variables. */
debug_sync_global.ds_signal.length(0); debug_sync_global.clear_set();
if ((rc= mysql_cond_init(key_debug_sync_globals_ds_cond, if ((rc= mysql_cond_init(key_debug_sync_globals_ds_cond,
&debug_sync_global.ds_cond, NULL)) || &debug_sync_global.ds_cond, NULL)) ||
(rc= mysql_mutex_init(key_debug_sync_globals_ds_mutex, (rc= mysql_mutex_init(key_debug_sync_globals_ds_mutex,
...@@ -195,7 +276,7 @@ void debug_sync_end(void) ...@@ -195,7 +276,7 @@ void debug_sync_end(void)
debug_sync_C_callback_ptr= NULL; debug_sync_C_callback_ptr= NULL;
/* Destroy the global variables. */ /* Destroy the global variables. */
debug_sync_global.ds_signal.free(); debug_sync_global.clear_set();
mysql_cond_destroy(&debug_sync_global.ds_cond); mysql_cond_destroy(&debug_sync_global.ds_cond);
mysql_mutex_destroy(&debug_sync_global.ds_mutex); mysql_mutex_destroy(&debug_sync_global.ds_mutex);
...@@ -271,6 +352,40 @@ void debug_sync_init_thread(THD *thd) ...@@ -271,6 +352,40 @@ void debug_sync_init_thread(THD *thd)
} }
/**
Returns an allocated buffer containing a comma-separated C string of all
active signals.
Buffer must be freed by the caller.
*/
static const char *get_signal_set_as_string()
{
mysql_mutex_assert_owner(&debug_sync_global.ds_mutex);
size_t req_size= 1; // In case of empty set for the end '\0' char.
for (size_t i= 0; i < debug_sync_global.ds_signal_set.size(); i++)
req_size+= debug_sync_global.ds_signal_set.at(i)->length + 1;
char *buf= (char *) my_malloc(PSI_NOT_INSTRUMENTED, req_size, MYF(0));
if (!buf)
return nullptr;
memset(buf, '\0', req_size);
char *cur_pos= buf;
for (size_t i= 0; i < debug_sync_global.ds_signal_set.size(); i++)
{
const LEX_CSTRING *signal= debug_sync_global.ds_signal_set.at(i);
memcpy(cur_pos, signal->str, signal->length);
if (i != debug_sync_global.ds_signal_set.size() - 1)
cur_pos[signal->length]= ',';
else
cur_pos[signal->length] = '\0';
cur_pos+= signal->length + 1;
}
return buf;
}
/** /**
End the debug sync facility at thread end. End the debug sync facility at thread end.
...@@ -554,7 +669,7 @@ static void debug_sync_reset(THD *thd) ...@@ -554,7 +669,7 @@ static void debug_sync_reset(THD *thd)
/* Clear the global signal. */ /* Clear the global signal. */
mysql_mutex_lock(&debug_sync_global.ds_mutex); mysql_mutex_lock(&debug_sync_global.ds_mutex);
debug_sync_global.ds_signal.length(0); debug_sync_global.clear_set();
mysql_mutex_unlock(&debug_sync_global.ds_mutex); mysql_mutex_unlock(&debug_sync_global.ds_mutex);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -1175,6 +1290,7 @@ static bool debug_sync_eval_action(THD *thd, char *action_str, char *action_end) ...@@ -1175,6 +1290,7 @@ static bool debug_sync_eval_action(THD *thd, char *action_str, char *action_end)
/* Set default for EXECUTE and TIMEOUT options. */ /* Set default for EXECUTE and TIMEOUT options. */
action->execute= 1; action->execute= 1;
action->timeout= opt_debug_sync_timeout; action->timeout= opt_debug_sync_timeout;
action->clear_event= true;
/* Get next token. If none follows, set action. */ /* Get next token. If none follows, set action. */
if (!(ptr= debug_sync_token(&token, &token_length, ptr, action_end))) if (!(ptr= debug_sync_token(&token, &token_length, ptr, action_end)))
...@@ -1225,6 +1341,15 @@ static bool debug_sync_eval_action(THD *thd, char *action_str, char *action_end) ...@@ -1225,6 +1341,15 @@ static bool debug_sync_eval_action(THD *thd, char *action_str, char *action_end)
goto set_action; goto set_action;
} }
/*
Try NO_CLEAR_EVENT.
*/
if (!my_strcasecmp(system_charset_info, token, "NO_CLEAR_EVENT")) {
action->clear_event= false;
/* Get next token. If none follows, set action. */
if (!(ptr = debug_sync_token(&token, &token_length, ptr, action_end))) goto set_action;
}
/* /*
Try HIT_LIMIT. Try HIT_LIMIT.
*/ */
...@@ -1325,13 +1450,19 @@ uchar *debug_sync_value_ptr(THD *thd) ...@@ -1325,13 +1450,19 @@ uchar *debug_sync_value_ptr(THD *thd)
if (opt_debug_sync_timeout) if (opt_debug_sync_timeout)
{ {
static char on[]= "ON - current signal: '"; static char on[]= "ON - current signals: '";
// Ensure exclusive access to debug_sync_global.ds_signal // Ensure exclusive access to debug_sync_global.ds_signal
mysql_mutex_lock(&debug_sync_global.ds_mutex); mysql_mutex_lock(&debug_sync_global.ds_mutex);
size_t lgt= (sizeof(on) /* includes '\0' */ + size_t lgt= sizeof(on) + 1; /* +1 as we'll have to append ' at the end. */
debug_sync_global.ds_signal.length() + 1 /* for '\'' */);
for (size_t i= 0; i < debug_sync_global.ds_signal_set.size(); i++)
{
/* Assume each signal is separated by a comma, hence +1. */
lgt+= debug_sync_global.ds_signal_set.at(i)->length + 1;
}
char *vend; char *vend;
char *vptr; char *vptr;
...@@ -1339,10 +1470,15 @@ uchar *debug_sync_value_ptr(THD *thd) ...@@ -1339,10 +1470,15 @@ uchar *debug_sync_value_ptr(THD *thd)
{ {
vend= value + lgt - 1; /* reserve space for '\0'. */ vend= value + lgt - 1; /* reserve space for '\0'. */
vptr= debug_sync_bmove_len(value, vend, STRING_WITH_LEN(on)); vptr= debug_sync_bmove_len(value, vend, STRING_WITH_LEN(on));
vptr= debug_sync_bmove_len(vptr, vend, debug_sync_global.ds_signal.ptr(), for (size_t i= 0; i < debug_sync_global.ds_signal_set.size(); i++)
debug_sync_global.ds_signal.length()); {
if (vptr < vend) const LEX_CSTRING *s= debug_sync_global.ds_signal_set.at(i);
*(vptr++)= '\''; vptr= debug_sync_bmove_len(vptr, vend, s->str, s->length);
if (i != debug_sync_global.ds_signal_set.size() - 1)
*(vptr++)= ',';
}
DBUG_ASSERT(vptr < vend);
*(vptr++)= '\'';
*vptr= '\0'; /* We have one byte reserved for the worst case. */ *vptr= '\0'; /* We have one byte reserved for the worst case. */
} }
mysql_mutex_unlock(&debug_sync_global.ds_mutex); mysql_mutex_unlock(&debug_sync_global.ds_mutex);
...@@ -1358,6 +1494,9 @@ uchar *debug_sync_value_ptr(THD *thd) ...@@ -1358,6 +1494,9 @@ uchar *debug_sync_value_ptr(THD *thd)
} }
/** /**
Execute requested action at a synchronization point. Execute requested action at a synchronization point.
...@@ -1413,12 +1552,28 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1413,12 +1552,28 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
read access too, to create a memory barrier in order to avoid that read access too, to create a memory barrier in order to avoid that
threads just reads an old cached version of the signal. threads just reads an old cached version of the signal.
*/ */
mysql_mutex_lock(&debug_sync_global.ds_mutex); mysql_mutex_lock(&debug_sync_global.ds_mutex);
if (action->signal.length()) if (action->signal.length())
{ {
/* Copy the signal to the global variable. */ int offset= 0, pos;
if (debug_sync_global.ds_signal.copy(action->signal)) bool error= false;
/* This loop covers all signals in the list except for the last one.
Split the signal string by commas and set a signal in the global
variable for each one. */
while (!error && (pos= action->signal.strstr(",", 1, offset)) > 0)
{
error= debug_sync_global.set_signal(action->signal.ptr() + offset,
pos - offset);
offset= pos + 1;
}
if (error ||
/* The last signal in the list. */
debug_sync_global.set_signal(action->signal.ptr() + offset,
action->signal.length() - offset))
{ {
/* /*
Error is reported by my_malloc(). Error is reported by my_malloc().
...@@ -1461,12 +1616,22 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1461,12 +1616,22 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
restore_current_mutex = false; restore_current_mutex = false;
set_timespec(abstime, action->timeout); set_timespec(abstime, action->timeout);
DBUG_EXECUTE("debug_sync_exec", DBUG_EXECUTE("debug_sync_exec", {
/* Functions as DBUG_PRINT args can change keyword and line nr. */ const char *signal_set= get_signal_set_as_string();
DBUG_PRINT("debug_sync_exec", if (!signal_set)
("wait for '%s' at: '%s' curr: '%s'", {
sig_wait, dsp_name, DBUG_PRINT("debug_sync_exec",
debug_sync_global.ds_signal.c_ptr()));); ("Out of memory when fetching signal set"));
}
else
{
/* Functions as DBUG_PRINT args can change keyword and line nr. */
DBUG_PRINT("debug_sync_exec",
("wait for '%s' at: '%s', curr: '%s'",
sig_wait, dsp_name, signal_set));
my_free((void *)signal_set);
}});
/* /*
Wait until global signal string matches the wait_for string. Wait until global signal string matches the wait_for string.
...@@ -1474,18 +1639,20 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1474,18 +1639,20 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
The facility can become disabled when some thread cannot get The facility can become disabled when some thread cannot get
the required dynamic memory allocated. the required dynamic memory allocated.
*/ */
while (stringcmp(&debug_sync_global.ds_signal, &action->wait_for) && while (!debug_sync_global.is_signalled(action->wait_for.ptr(),
!(thd->killed & KILL_HARD_BIT) && opt_debug_sync_timeout) action->wait_for.length()) &&
!(thd->killed & KILL_HARD_BIT) &&
opt_debug_sync_timeout)
{ {
error= mysql_cond_timedwait(&debug_sync_global.ds_cond, error= mysql_cond_timedwait(&debug_sync_global.ds_cond,
&debug_sync_global.ds_mutex, &debug_sync_global.ds_mutex,
&abstime); &abstime);
DBUG_EXECUTE("debug_sync", // TODO turn this into a for loop printing.
DBUG_EXECUTE("debug_sync", {
/* Functions as DBUG_PRINT args can change keyword and line nr. */ /* Functions as DBUG_PRINT args can change keyword and line nr. */
DBUG_PRINT("debug_sync", DBUG_PRINT("debug_sync",
("awoke from %s global: %s error: %d", ("awoke from %s error: %d",
sig_wait, debug_sync_global.ds_signal.c_ptr(), sig_wait, error));});
error)););
if (unlikely(error == ETIMEDOUT || error == ETIME)) if (unlikely(error == ETIMEDOUT || error == ETIME))
{ {
// We should not make the statement fail, even if in strict mode. // We should not make the statement fail, even if in strict mode.
...@@ -1498,6 +1665,10 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action) ...@@ -1498,6 +1665,10 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
} }
error= 0; error= 0;
} }
if (action->clear_event)
debug_sync_global.clear_signal(action->wait_for);
DBUG_EXECUTE("debug_sync_exec", DBUG_EXECUTE("debug_sync_exec",
if (thd->killed) if (thd->killed)
DBUG_PRINT("debug_sync_exec", DBUG_PRINT("debug_sync_exec",
...@@ -1571,10 +1742,10 @@ static void debug_sync(THD *thd, const char *sync_point_name, size_t name_len) ...@@ -1571,10 +1742,10 @@ static void debug_sync(THD *thd, const char *sync_point_name, size_t name_len)
st_debug_sync_control *ds_control= thd->debug_sync_control; st_debug_sync_control *ds_control= thd->debug_sync_control;
st_debug_sync_action *action; st_debug_sync_action *action;
DBUG_ENTER("debug_sync"); DBUG_ENTER("debug_sync");
DBUG_PRINT("debug_sync_point", ("hit: '%s'", sync_point_name));
DBUG_ASSERT(sync_point_name); DBUG_ASSERT(sync_point_name);
DBUG_ASSERT(name_len); DBUG_ASSERT(name_len);
DBUG_ASSERT(ds_control); DBUG_ASSERT(ds_control);
DBUG_PRINT("debug_sync_point", ("hit: '%s'", sync_point_name));
/* Statistics. */ /* Statistics. */
ds_control->dsp_hits++; ds_control->dsp_hits++;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
#include "my_global.h"
#include "hash.h" #include "hash.h"
...@@ -28,20 +29,18 @@ class Hash_set ...@@ -28,20 +29,18 @@ class Hash_set
public: public:
enum { START_SIZE= 8 }; enum { START_SIZE= 8 };
/** /**
Constructs an empty hash. Does not allocate memory, it is done upon Constructs an empty unique hash.
the first insert. Thus does not cause or return errors.
*/ */
Hash_set(PSI_memory_key psi_key, uchar *(*K)(const T *, size_t *, my_bool), Hash_set(PSI_memory_key psi_key, uchar *(*K)(const T *, size_t *, my_bool),
CHARSET_INFO *cs= &my_charset_bin) CHARSET_INFO *cs= &my_charset_bin)
{ {
my_hash_clear(&m_hash); my_hash_init(psi_key, &m_hash, cs, START_SIZE, 0, 0, (my_hash_get_key)K, 0,
m_hash.get_key= (my_hash_get_key)K; HASH_UNIQUE);
m_hash.charset= cs;
m_hash.array.m_psi_key= psi_key;
} }
Hash_set(PSI_memory_key psi_key, CHARSET_INFO *charset, ulong default_array_elements, Hash_set(PSI_memory_key psi_key, CHARSET_INFO *charset, ulong default_array_elements,
size_t key_offset, size_t key_length, my_hash_get_key get_key, size_t key_offset, size_t key_length, my_hash_get_key get_key,
void (*free_element)(void*), uint flags) void (*free_element)(void*),uint flags)
{ {
my_hash_init(psi_key, &m_hash, charset, default_array_elements, key_offset, my_hash_init(psi_key, &m_hash, charset, default_array_elements, key_offset,
key_length, get_key, free_element, flags); key_length, get_key, free_element, flags);
...@@ -65,8 +64,6 @@ class Hash_set ...@@ -65,8 +64,6 @@ class Hash_set
*/ */
bool insert(T *value) bool insert(T *value)
{ {
my_hash_init_opt(m_hash.array.m_psi_key, &m_hash, m_hash.charset,
START_SIZE, 0, 0, m_hash.get_key, 0, HASH_UNIQUE);
return my_hash_insert(&m_hash, reinterpret_cast<const uchar*>(value)); return my_hash_insert(&m_hash, reinterpret_cast<const uchar*>(value));
} }
bool remove(T *value) bool remove(T *value)
......
...@@ -677,33 +677,37 @@ bool String::append_with_prefill(const char *s,uint32 arg_length, ...@@ -677,33 +677,37 @@ bool String::append_with_prefill(const char *s,uint32 arg_length,
} }
int Binary_string::strstr(const Binary_string &s, uint32 offset) int Binary_string::strstr(const char *search, uint32 search_length, uint32 offset)
{ {
if (s.length()+offset <= str_length) if (search_length + offset <= str_length)
{ {
if (!s.length()) if (!search_length)
return ((int) offset); // Empty string is always found return ((int) offset); // Empty string is always found
const char *str = Ptr+offset; const char *str= Ptr + offset;
const char *search=s.ptr(); const char *end= Ptr + str_length - search_length + 1;
const char *end=Ptr+str_length-s.length()+1; const char *search_end= search + search_length;
const char *search_end=s.ptr()+s.length();
skip: skip:
while (str != end) while (str != end)
{ {
if (*str++ == *search) if (*str++ == *search)
{ {
char *i,*j; char *i= (char*) str;
i=(char*) str; j=(char*) search+1; char *j= (char*) search + 1 ;
while (j != search_end) while (j != search_end)
if (*i++ != *j++) goto skip; if (*i++ != *j++) goto skip;
return (int) (str-Ptr) -1; return (int) (str-Ptr) -1;
} }
} }
} }
return -1; return -1;
} }
int Binary_string::strstr(const Binary_string &s, uint32 offset)
{
return strstr(s.ptr(), s.length(), offset);
}
/* /*
** Search string from end. Offset is offset to the end of string ** Search string from end. Offset is offset to the end of string
*/ */
......
...@@ -330,6 +330,7 @@ class Binary_string: public Sql_alloc ...@@ -330,6 +330,7 @@ class Binary_string: public Sql_alloc
// Returns offset to substring or -1 // Returns offset to substring or -1
int strstr(const Binary_string &search, uint32 offset=0); int strstr(const Binary_string &search, uint32 offset=0);
int strstr(const char *search, uint32 search_length, uint32 offset=0);
// Returns offset to substring or -1 // Returns offset to substring or -1
int strrstr(const Binary_string &search, uint32 offset=0); int strrstr(const Binary_string &search, uint32 offset=0);
......
...@@ -3571,7 +3571,7 @@ char *bson_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -3571,7 +3571,7 @@ char *bson_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
} // endif Xchk } // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, false, true)) { if (!CheckMemory(g, initid, args, 2, false, false, true)) {
JTYP type; JTYP type= TYPE_JAR;
BJNX bnx(g); BJNX bnx(g);
PBVAL jvp = NULL, top = NULL; PBVAL jvp = NULL, top = NULL;
PBVAL jsp[2] = {NULL, NULL}; PBVAL jsp[2] = {NULL, NULL};
...@@ -5724,7 +5724,7 @@ char *bbin_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result, ...@@ -5724,7 +5724,7 @@ char *bbin_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
} // endif Xchk } // endif Xchk
if (!CheckMemory(g, initid, args, 2, false, false, true)) { if (!CheckMemory(g, initid, args, 2, false, false, true)) {
JTYP type; JTYP type = TYPE_JAR;
BJNX bnx(g); BJNX bnx(g);
PBVAL jvp = NULL, top = NULL; PBVAL jvp = NULL, top = NULL;
PBVAL jsp[2] = {NULL, NULL}; PBVAL jsp[2] = {NULL, NULL};
......
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