419
IF v_value_of_first_token='next' THEN
420
/* 'next' is the same as 'continue but stop on the next statement',
421
but without going down into a function or called procedure (that would be 'step').
422
The value for call_stack_depth_when_set is calculated and stored in the breakpoints
423
table at the time the debuggee receives it, so it is only reliable if one says 'next'
424
while at a breakpoint. */
425
SET v_prefix = CONCAT('xxxmdbug_',@xxxmdbug_channel,@xxxmdbug_prefix_end_for_command); /* 'C ' */
426
CALL xxxmdbug.dbms_pipe_send(v_prefix,'tbreakpoint %.% 1-99999 call_stack_depth<=call_stack_depth_when_set');
427
CALL xxxmdbug.dbms_pipe_send(v_prefix,'continue');
431
IF v_value_of_first_token='step' THEN
432
/* 'step' is the same as 'continue but stop on the next statement',
433
including a statement that we reach after going down into a function or called procedure. */
434
SET v_prefix = CONCAT('xxxmdbug_',@xxxmdbug_channel,@xxxmdbug_prefix_end_for_command); /* 'C ' */
435
CALL xxxmdbug.dbms_pipe_send(v_prefix,'tbreakpoint %.% 1-99999');
436
CALL xxxmdbug.dbms_pipe_send(v_prefix,'continue');
440
420
IF v_value_of_first_token='source' THEN
441
421
SET message=RIGHT(message,LENGTH(message)-v_length_of_first_token);
442
422
CALL xxxmdbug.setup_internal(message,0);
1799
1783
/* When a command is considered "done", we call icc_change_statement_status() so that it will
1800
1784
change @xxxmdbug_status_last_command_result to 'Fail' or 'OK' etc., and increment @xxxmdbug_commands_count.
1801
1785
These values will be visible via 'information status'.
1802
For 'continue' 'exit' 'leave' 'skip' we have to say 'OK' every time so we do that early.
1786
For 'continue' 'exit' 'leave' 'skip' 'step','next' we have to say 'OK' every time so we do that early.
1803
1787
For 'execute' and 'set' we might declare 'fail' even though the debugger has done its bit, it's the DBMS that's rejecting.
1804
1788
This can be called from (generated) icc_core, debuggee_wait_loop, icc_process_user_command..., is_debuggee_and_is_attached. */
1805
1789
CREATE PROCEDURE xxxmdbug.icc_change_statement_status (last_command_result VARCHAR(128) CHARACTER SET utf8)
1829
1813
DECLARE v_prefix VARCHAR(128) CHARACTER SET utf8; /* sizeof('xxxmdbug_' + xxxmdbug_channel) + 'C ' + room to grow */
1831
1815
DECLARE v_at_breakpoint VARCHAR(3) CHARACTER SET utf8;
1816
DECLARE v_at_tbreakpoint VARCHAR(3) CHARACTER SET utf8;
1832
1817
DECLARE v_at_routine_exit VARCHAR(3) CHARACTER SET utf8;
1833
1818
DECLARE v_stack_depth INT;
1834
1819
DECLARE v_message_start INT;
1835
1820
DECLARE v_schema VARCHAR(66) CHARACTER SET utf8;
1836
1821
DECLARE v_routine VARCHAR(66) CHARACTER SET utf8;
1837
1822
DECLARE v_routine_type VARCHAR(10) CHARACTER SET utf8; /* todo: use this */
1838
1824
SET v_prefix = CONCAT('xxxmdbug_',@xxxmdbug_channel,@xxxmdbug_prefix_end_for_statement_status); /* 'R ' */
1839
1825
CALL xxxmdbug.dbms_pipe_receive(v_prefix,1,@xxxmdbug_x,v_message_start);
1844
1830
IF v_routine IS NULL THEN
1845
1831
signal sqlstate '05678' set mysql_errno=@xxxmdbug_signal_errno,message_text='assert.icc_send_statement_status';
1847
SET v_at_breakpoint = CASE WHEN @xxxmdbug_status_breakpoint_check_result = 1 THEN 'yes' ELSE 'no' END;
1833
SET v_at_breakpoint = CASE WHEN @xxxmdbug_status_breakpoint_check_result > 0 THEN 'yes' ELSE 'no' END;
1834
SET v_at_tbreakpoint = CASE WHEN @xxxmdbug_status_breakpoint_check_result = 2 THEN 'yes' ELSE 'no' END;
1849
1836
SET v_at_routine_exit='no';
1850
1837
IF called_from = 'routine_exit' THEN
1851
1838
SET v_at_breakpoint = 'no';
1839
SET v_at_tbreakpoint = 'no';
1852
1840
SET v_at_routine_exit = 'yes';
1854
1842
SET @xxxmdbug_number_of_last_status_message=@xxxmdbug_number_of_last_status_message+1;
1861
1849
'''',v_routine,''',',
1862
1850
'''',@xxxmdbug_status_line_number,''',',
1863
1851
'''',v_at_breakpoint,''',',
1852
'''',v_at_tbreakpoint,''',',
1864
1853
'''',v_at_routine_exit,''',',
1865
1854
'''',v_stack_depth,''',',
1866
1855
'''',HEX(@xxxmdbug_status_last_command),''',',
2031
/* icc_process_user_command_step_or_next() does what icc_process_user_command_break() does: adds a 'row' in breakpoints 'table'.
2032
'step' is the same as 'continue but stop on the next statement',
2033
including a statement that we reach after going down into a function or called procedure.
2034
'next' is the same as 'continue but stop on the next statement',
2035
but without going down into a function or called procedure (that would be 'step').
2036
The value for call_stack_depth_when_set is calculated and stored in the breakpoints
2037
table at the time the debuggee receives it, so it is only reliable if one says 'next'
2038
while at a breakpoint..
2039
The effect of 'step' is like 'tbreakpoint %.% 1-99999' followed by 'continue'.
2040
The effect of 'next' is like 'tbreakpoint %.% 1-99999 call_stack_depth<=call_stack_depth_when_set' followed by 'continue'.
2041
We actually create the temporary breakpoint, then check immediately afterward for breakpoints,
2042
so after 'step' or 'next' the information status will show we're stopped at a temporary breakpoint.
2043
Unlike gdb, 'step' does not go to the next line, it goes to the next iteration of the SQL statement, regardless of line number.
2044
Do not change statement status, it's changed already.
2045
Todo: We're not showing 'breakpoint_identifier=n' as we do for breakpoint/tbreakpoint -- should we do so?
2046
Todo: We're setting the temporary breakpoint as starting at line 1, not line 0 -- I wonder if that's the right decision? */
2047
CREATE PROCEDURE xxxmdbug.icc_process_user_command_step_or_next ()
2049
DECLARE v_call_stack_depth_when_set INT;
2051
SET v_call_stack_depth_when_set=LENGTH(@xxxmdbug_call_stack)/(66+66);
2052
SET @xxxmdbug_breakpoints_last_insert_id=@xxxmdbug_breakpoints_last_insert_id+1;
2053
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_breakpoint_identifier,10,@xxxmdbug_breakpoints_last_insert_id);
2054
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_schema_identifier,80,'%');
2055
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_routine_identifier,80,'%');
2056
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_routine_type,16,'ROUTINEE');
2057
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_line_number_minimum,10,1);
2058
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_line_number_maximum,10,99999);
2059
IF @xxxmdbug_token_value_1='next' THEN
2060
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_condition_identifier,80,'call_stack_depth');
2061
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_condition_operator,10,'<=');
2062
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_condition_value,@xxxmdbug_value_length,'call_stack_depth_when_set');
2064
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_condition_identifier,80,'');
2065
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_condition_operator,10,'');
2066
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_condition_value,@xxxmdbug_value_length,'');
2068
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_hit_count,10,0);
2069
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_is_temporary,5,1);
2070
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_is_temporary_and_to_be_cleared,5,0);
2071
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_is_matching_location,5,0);
2072
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_is_matching_condition,5,0);
2073
CALL xxxmdbug.fixed_insert(@xxxmdbug_breakpoints_call_stack_depth_when_set,10,v_call_stack_depth_when_set);
2042
2076
CREATE PROCEDURE xxxmdbug.icc_process_user_command ()
2044
2078
DECLARE v_prefix VARCHAR(128) CHARACTER SET utf8;
2926
2961
CALL xxxmdbug.fixed_select(@xxxmdbug_variables_old_value,@xxxmdbug_value_length,v_n4,v_table_variable_old_value,v_flags);
2927
2962
IF v_table_variable_value <> v_table_variable_old_value THEN
2928
2963
SET v_is_matching_condition = 1;
2964
IF v_is_temporary=0 THEN SET result = 1; ELSE SET result = 2; END IF;
2930
2965
LEAVE condition_check;
2933
2968
CALL xxxmdbug.compare(v_condition_value,v_table_variable_value,v_is_matching_condition); /* becomes = 1 if true */
2934
2969
IF v_is_matching_condition = 1 THEN
2970
IF v_is_temporary=0 THEN SET result = 1; ELSE SET result = 2; END IF;
3065
3101
SET @xxxmdbug_token_value_4 = SUBSTRING(@xxxmdbug_linked_list FROM @xxxmdbug_token_value_4_offset+24 FOR @xxxmdbug_token_value_4_length);
3067
3103
/* @xxxmdbug_token_value_1 will not be abbreviated form e.g. 'cont', it will be unabbreviated e.g. 'continue'. */
3068
IF @xxxmdbug_token_value_1=LEFT('attach',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='attach'; END IF;
3069
IF @xxxmdbug_token_value_1=LEFT('breakpoint',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='breakpoint'; END IF;
3070
IF @xxxmdbug_token_value_1=LEFT('clear',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='clear'; END IF;
3071
IF @xxxmdbug_token_value_1=LEFT('continue',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='continue'; END IF;
3072
IF @xxxmdbug_token_value_1=LEFT('debug',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='debug'; END IF;
3073
IF @xxxmdbug_token_value_1=LEFT('delete',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='delete'; END IF;
3074
IF @xxxmdbug_token_value_1=LEFT('execute',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='execute'; END IF;
3075
IF @xxxmdbug_token_value_1=LEFT('exit',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='exit'; END IF;
3076
IF @xxxmdbug_token_value_1=LEFT('leave',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='leave'; END IF;
3077
IF @xxxmdbug_token_value_1=LEFT('refresh',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='refresh'; END IF;
3078
IF @xxxmdbug_token_value_1=LEFT('set',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='set'; END IF;
3079
IF @xxxmdbug_token_value_1=LEFT('skip',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='skip'; END IF;
3080
IF @xxxmdbug_token_value_1=LEFT('tbreakpoint',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='tbreakpoint'; END IF;
3104
IF @xxxmdbug_token_value_1_length>0 THEN
3105
IF @xxxmdbug_token_value_1=LEFT('attach',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='attach'; END IF;
3106
IF @xxxmdbug_token_value_1=LEFT('breakpoint',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='breakpoint'; END IF;
3107
IF @xxxmdbug_token_value_1=LEFT('clear',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='clear'; END IF;
3108
IF @xxxmdbug_token_value_1=LEFT('continue',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='continue'; END IF;
3109
IF @xxxmdbug_token_value_1=LEFT('debug',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='debug'; END IF;
3110
IF @xxxmdbug_token_value_1=LEFT('delete',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='delete'; END IF;
3111
IF @xxxmdbug_token_value_1=LEFT('execute',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='execute'; END IF;
3112
IF @xxxmdbug_token_value_1=LEFT('exit',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='exit'; END IF;
3113
IF @xxxmdbug_token_value_1=LEFT('leave',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='leave'; END IF;
3114
IF @xxxmdbug_token_value_1=LEFT('next',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='next'; END IF;
3115
IF @xxxmdbug_token_value_1=LEFT('refresh',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='refresh'; END IF;
3116
IF @xxxmdbug_token_value_1=LEFT('set',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='set'; END IF;
3117
IF @xxxmdbug_token_value_1=LEFT('skip',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='skip'; END IF;
3118
IF @xxxmdbug_token_value_1=LEFT('step',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='step'; END IF;
3119
IF @xxxmdbug_token_value_1=LEFT('tbreakpoint',@xxxmdbug_token_value_1_length) THEN SET @xxxmdbug_token_value_1='tbreakpoint'; END IF;
3082
3121
/* Usually 'execute' is in the IN list, but not this time, because 'execute' does its own call to icc_change_statement_status. */
3083
IF @xxxmdbug_token_value_1 IN ('continue','exit','leave','skip') THEN CALL xxxmdbug.icc_change_statement_status('OK'); END IF;
3122
IF @xxxmdbug_token_value_1 IN ('continue','exit','leave','next','skip','step') THEN CALL xxxmdbug.icc_change_statement_status('OK'); END IF;
3105
3144
/* 0 means no wait, i.e. get from queue */
3106
3145
CALL xxxmdbug.icc_get_user_command(0);
3107
3146
IF @xxxmdbug_message <= 0x20 THEN LEAVE x1; END IF; /* if empty queue, go on */
3108
IF @xxxmdbug_token_value_1 IN ('continue','exit','leave','execute','skip') THEN LEAVE x1; END IF; /* if motion causer, go on */
3147
IF @xxxmdbug_token_value_1 IN ('continue','exit','leave','next','execute','skip','step') THEN LEAVE x1; END IF; /* if motion causer, go on */
3109
3148
/* This is replaced with user-variables code in the generated icc_core (if there are user variables and track_user_variables=1). */
3110
3149
CALL xxxmdbug.icc_process_user_command();
3114
3153
CALL xxxmdbug.icc_breakpoint_check(line_number,@xxxmdbug_breakpoint_check_result);
3115
3154
SET @xxxmdbug_status_breakpoint_check_result = @xxxmdbug_breakpoint_check_result;
3116
3155
CALL xxxmdbug.icc_send_statement_status('icc_core');
3117
IF @xxxmdbug_breakpoint_check_result = 1 THEN
3156
IF @xxxmdbug_breakpoint_check_result > 0 THEN
3119
IF @xxxmdbug_token_value_1 IN ('continue','exit','leave','execute','skip') THEN
3158
IF @xxxmdbug_token_value_1 IN ('continue','exit','leave','next','execute','skip','step') THEN
3121
3160
END IF; /* if motion causer, go on */
3122
3161
/* 1 means wait, i.e. we have to get a command that causes motion */
3123
CALL xxxmdbug.icc_get_user_command(1);
3124
IF @xxxmdbug_token_value_1 IN ('continue','exit','leave','execute','skip') THEN
3162
CALL xxxmdbug.icc_get_user_command(1);
3163
IF @xxxmdbug_token_value_1 IN ('next','step') THEN CALL xxxmdbug.icc_process_user_command_step_or_next(); END IF;
3164
IF @xxxmdbug_token_value_1 IN ('continue','exit','leave','next','execute','skip','step') THEN
3126
3166
END IF; /* if motion causer, go on */
3127
3167
/* This is replaced with :IF @xxxmdbug_token_value_2 = 'user_variables' ,,," in the generated icc_core (if track_user_variables=1). */
3283
3323
'x1: LOOP',@xxxmdbug_lf,
3284
3324
'CALL xxxmdbug.icc_get_user_command(0);',@xxxmdbug_lf,
3285
3325
'IF @xxxmdbug_message <= 0x20 THEN LEAVE x1; END IF;',@xxxmdbug_lf,
3286
'IF @xxxmdbug_token_value_1 IN (''continue'',''exit'',''leave'',''execute'',''skip'') THEN LEAVE x1; END IF;',@xxxmdbug_lf,
3326
'IF @xxxmdbug_token_value_1 IN (''continue'',''exit'',''leave'',''next'',''execute'',''skip'',''step'') THEN LEAVE x1; END IF;',@xxxmdbug_lf,
3287
3327
'IF @xxxmdbug_token_value_2 = ''user_variables'' THEN',@xxxmdbug_lf,
3288
3328
'SET v_ret='''';',@xxxmdbug_lf);
3289
3329
/* part 1 end */
3331
3371
'CALL xxxmdbug.icc_breakpoint_check(line_number,@xxxmdbug_breakpoint_check_result);',@xxxmdbug_lf,
3332
3372
'SET @xxxmdbug_status_breakpoint_check_result = @xxxmdbug_breakpoint_check_result;',@xxxmdbug_lf,
3333
3373
'CALL xxxmdbug.icc_send_statement_status(''icc_core'');',@xxxmdbug_lf,
3334
'IF @xxxmdbug_breakpoint_check_result = 1 THEN',@xxxmdbug_lf,
3374
'IF @xxxmdbug_breakpoint_check_result > 0 THEN',@xxxmdbug_lf,
3335
3375
'x2: LOOP',@xxxmdbug_lf,
3336
'IF @xxxmdbug_token_value_1 IN (''continue'',''exit'',''leave'',''execute'',''skip'') THEN',@xxxmdbug_lf,
3376
'IF @xxxmdbug_token_value_1 IN (''continue'',''exit'',''leave'',''next'',''execute'',''skip'',''step'') THEN',@xxxmdbug_lf,
3337
3377
'LEAVE x2;',@xxxmdbug_lf,
3338
3378
'END IF;',@xxxmdbug_lf,
3339
3379
'CALL xxxmdbug.icc_get_user_command(1);',@xxxmdbug_lf,
3340
'IF @xxxmdbug_token_value_1 IN (''continue'',''exit'',''leave'',''execute'',''skip'') THEN',@xxxmdbug_lf,
3380
'IF @xxxmdbug_token_value_1 IN (''next'',''step'') THEN CALL xxxmdbug.icc_process_user_command_step_or_next(); END IF;',@xxxmdbug_lf,
3381
'IF @xxxmdbug_token_value_1 IN (''continue'',''exit'',''leave'',''next'',''execute'',''skip'',''step'') THEN',@xxxmdbug_lf,
3341
3382
'LEAVE x2;',@xxxmdbug_lf,
3342
3383
'END IF;',@xxxmdbug_lf,
3343
3384
'IF @xxxmdbug_token_value_2 = ''user_variables'' THEN',@xxxmdbug_lf,
5549
5591
if v_g is null then signal sqlstate '56780' set mysql_errno=@xxxmdbug_signal_errno, message_text='assert 44'; end if;
5550
5592
/* inner_loop: 'SET' and 'EXECUTE' might change variables that we're watching.
5551
5593
So if they happened, go back and copy the variables again. */
5552
SET v_g = CONCAT(v_g,'IF @xxxmdbug_breakpoint_check_result=1 AND (@xxxmdbug_token_value_1 = ''set'' OR @xxxmdbug_token_value_1 = ''execute'') THEN ITERATE ',inner_loop_label,'; END IF;',@xxxmdbug_lf);
5594
SET v_g = CONCAT(v_g,'IF @xxxmdbug_breakpoint_check_result>0 AND (@xxxmdbug_token_value_1 = ''set'' OR @xxxmdbug_token_value_1 = ''execute'') THEN ITERATE ',inner_loop_label,'; END IF;',@xxxmdbug_lf);
5553
5595
/* inner_loop: by leaving inner_loop before doing the instruction, we "skip over" it */
5554
5596
SET v_g = CONCAT(v_g,'IF @xxxmdbug_token_value_1 = ''skip'' THEN LEAVE ',inner_loop_label,'; END IF;',@xxxmdbug_lf);