1
## Bug#12713 (Error in a stored function called from a SELECT doesn't cause
6
## - $engine_type should be set
9
set sql_mode=no_engine_substitution;
10
eval set storage_engine = $engine_type;
14
drop table if exists t1;
15
drop table if exists t2;
16
drop table if exists t3;
17
drop function if exists f2;
18
drop procedure if exists bug12713_call;
19
drop procedure if exists bug12713_dump_spvars;
20
drop procedure if exists dummy;
23
create table t1 (a int);
24
create table t2 (a int unique);
25
create table t3 (a int);
27
# a workaround for Bug#32633: Can not create any routine if
28
# SQL_MODE=no_engine_substitution
32
insert into t1 (a) values (1), (2);
33
insert into t3 (a) values (1), (2);
37
## Cause a failure every time
38
create function f2(x int) returns int
40
insert into t2 (a) values (x);
41
insert into t2 (a) values (x);
50
##============================================================================
53
## In each case, statement rollback is expected.
54
## for transactional engines, the rollback should be properly executed
55
## for non transactional engines, the rollback may cause warnings.
57
## The test pattern is as follows
59
## - statement with a side effect, that fails to insert N twice
60
## - a statement rollback is expected (expecting 1 row 1000+N only) in t2
61
## - a rollback is performed
62
## - expecting a clean table t2.
63
##============================================================================
65
insert into t2 (a) values (1001);
67
insert into t1 (a) values (f2(1));
72
insert into t2 (a) values (1002);
74
insert into t3 (a) select f2(2) from t1;
79
insert into t2 (a) values (1003);
81
update t1 set a= a + f2(3);
86
insert into t2 (a) values (1004);
88
update t1, t3 set t1.a = 0, t3.a = 0 where (f2(4) = 4) and (t1.a = t3.a);
93
insert into t2 (a) values (1005);
95
delete from t1 where (a = f2(5));
100
insert into t2 (a) values (1006);
102
delete from t1, t3 using t1, t3 where (f2(6) = 6) ;
107
insert into t2 (a) values (1007);
109
replace t1 values (f2(7));
114
insert into t2 (a) values (1008);
116
replace into t3 (a) select f2(8) from t1;
121
insert into t2 (a) values (1009);
123
select f2(9) from t1 ;
128
insert into t2 (a) values (1010);
130
show databases where (f2(10) = 10);
135
insert into t2 (a) values (1011);
137
show tables where (f2(11) = 11);
142
insert into t2 (a) values (1012);
144
show triggers where (f2(12) = 12);
149
insert into t2 (a) values (1013);
151
show table status where (f2(13) = 13);
156
insert into t2 (a) values (1014);
158
show open tables where (f2(14) = 14);
163
insert into t2 (a) values (1015);
165
show columns in mysql.proc where (f2(15) = 15);
170
insert into t2 (a) values (1016);
172
show status where (f2(16) = 16);
177
insert into t2 (a) values (1017);
179
show variables where (f2(17) = 17);
184
insert into t2 (a) values (1018);
186
show charset where (f2(18) = 18);
191
insert into t2 (a) values (1019);
193
show collation where (f2(19) = 19);
198
--echo # We need at least one procedure to make sure the WHERE clause is
200
create procedure dummy() begin end;
201
insert into t2 (a) values (1020);
203
show procedure status where (f2(20) = 20);
207
drop procedure dummy;
209
insert into t2 (a) values (1021);
211
show function status where (f2(21) = 21);
216
insert into t2 (a) values (1022);
217
prepare stmt from "insert into t1 (a) values (f2(22))";
224
insert into t2 (a) values (1023);
231
## This will insert a record 1024 in t1 (statement commit)
232
## This will insert a record 24 in t1 (statement commit)
233
## then will rollback the second insert only (24) (statement rollback)
234
## then will rollback the complete transaction (transaction rollback)
238
create procedure bug12713_call ()
240
insert into t2 (a) values (24);
241
insert into t2 (a) values (24);
246
insert into t2 (a) values (1024);
248
call bug12713_call();
253
--echo =======================================================================
254
--echo Testing select_to_file
255
--echo =======================================================================
257
insert into t2 (a) values (1025);
259
--replace_result $MYSQLTEST_VARDIR ..
261
eval select f2(25) into outfile "$MYSQLTEST_VARDIR/tmp/dml.out" from t1;
265
--remove_file $MYSQLTEST_VARDIR/tmp/dml.out
267
insert into t2 (a) values (1026);
268
--replace_result $MYSQLTEST_VARDIR ..
270
eval load data infile "../std_data_ln/words.dat" into table t1 (a) set a:=f2(26);
276
--echo =======================================================================
277
--echo Testing select_dumpvar
278
--echo =======================================================================
280
insert into t2 (a) values (1027);
282
select f2(27) into @foo;
287
--echo =======================================================================
288
--echo Testing Select_fetch_into_spvars
289
--echo =======================================================================
293
create procedure bug12713_dump_spvars ()
297
declare continue handler for sqlexception
299
select "Exception trapped";
302
select f2(28) into foo;
308
insert into t2 (a) values (1028);
309
call bug12713_dump_spvars ();
313
--echo =======================================================================
315
--echo =======================================================================
317
set autocommit=default;
323
drop procedure bug12713_call;
324
drop procedure bug12713_dump_spvars;
326
--echo # Bug#12713 Error in a stored function called from a SELECT doesn't
327
--echo # cause ROLLBACK of statem
329
--echo # Verify that two-phase commit is not issued for read-only
330
--echo # transactions.
332
--echo # Verify that two-phase commit is issued for read-write transactions,
333
--echo # even if the change is done inside a stored function called from
334
--echo # SELECT or SHOW statement.
338
drop table if exists t1;
339
drop table if exists t2;
340
drop function if exists f1;
341
drop procedure if exists p_verify_status_increment;
344
# Save binlog_format in a user variable. References to system
345
# variables are "unsafe", meaning they are written as rows instead of
346
# as statements to the binlog, if the loggging mode is 'mixed'. But
347
# we don't want p_verify_status_increment to affect the logging mode.
348
# Hence, we save binlog_format in a user variable (which is not
349
# unsafe) and use that inside p_verify_status_increment.
350
set @binlog_format=@@global.binlog_format;
352
set sql_mode=no_engine_substitution;
353
create table t1 (a int unique);
354
create table t2 (a int) engine=myisam;
355
set sql_mode=default;
357
--echo # An auxiliary procedure to track Handler_prepare and Handler_commit
362
p_verify_status_increment(commit_inc_mixed int, prepare_inc_mixed int,
363
commit_inc_row int, prepare_inc_row int)
365
declare commit_inc int;
366
declare prepare_inc int;
367
declare old_commit_count int default ifnull(@commit_count, 0);
368
declare old_prepare_count int default ifnull(@prepare_count, 0);
370
# Use a cursor to have just one access to I_S instead of 2, it is very slow
371
# and amounts for over 90% of test CPU time
373
select variable_value
374
from information_schema.session_status
375
where variable_name='Handler_commit' or variable_name='Handler_prepare'
376
order by variable_name;
378
if @binlog_format = 'ROW' then
379
set commit_inc= commit_inc_row;
380
set prepare_inc= prepare_inc_row;
382
set commit_inc= commit_inc_mixed;
383
set prepare_inc= prepare_inc_mixed;
388
set @commit_count=c_res;
390
set @prepare_count=c_res;
393
if old_commit_count + commit_inc <> @commit_count then
394
select concat("Expected commit increment: ", commit_inc,
395
" actual: ", @commit_count - old_commit_count)
397
elseif old_prepare_count + prepare_inc <> @prepare_count then
398
select concat("Expected prepare increment: ", prepare_inc,
399
" actual: ", @prepare_count - old_prepare_count)
402
select '' as 'SUCCESS';
406
--echo # Reset Handler_commit and Handler_prepare counters
409
--echo # 1. Read-only statement: SELECT
412
call p_verify_status_increment(1, 0, 1, 0);
414
call p_verify_status_increment(1, 0, 1, 0);
416
--echo # 2. Read-write statement: INSERT, insert 1 row.
418
insert into t1 (a) values (1);
419
call p_verify_status_increment(2, 2, 2, 2);
421
call p_verify_status_increment(2, 2, 2, 2);
423
--echo # 3. Read-write statement: UPDATE, update 1 row.
426
call p_verify_status_increment(2, 2, 2, 2);
428
call p_verify_status_increment(2, 2, 2, 2);
430
--echo # 4. Read-write statement: UPDATE, update 0 rows, 1 row matches WHERE
433
call p_verify_status_increment(2, 2, 1, 0);
435
call p_verify_status_increment(2, 2, 1, 0);
437
--echo # 5. Read-write statement: UPDATE, update 0 rows, 0 rows match WHERE
439
--echo # In mixed replication mode, there is a read-only transaction
440
--echo # in InnoDB and also the statement is written to the binary log.
441
--echo # So we have two commits but no 2pc, since the first engine's
442
--echo # transaction is read-only.
443
--echo # In the row level replication mode, we only have the read-only
444
--echo # transaction in InnoDB and nothing is written to the binary log.
446
update t1 set a=3 where a=1;
447
call p_verify_status_increment(2, 0, 1, 0);
449
call p_verify_status_increment(2, 0, 1, 0);
451
--echo # 6. Read-write statement: DELETE, delete 0 rows.
453
delete from t1 where a=1;
454
call p_verify_status_increment(2, 0, 1, 0);
456
call p_verify_status_increment(2, 0, 1, 0);
458
--echo # 7. Read-write statement: DELETE, delete 1 row.
460
delete from t1 where a=2;
461
call p_verify_status_increment(2, 2, 2, 2);
463
call p_verify_status_increment(2, 2, 2, 2);
465
--echo # 8. Read-write statement: unqualified DELETE
467
--echo # In statement or mixed replication mode, we call
468
--echo # handler::ha_delete_all_rows() and write statement text
469
--echo # to the binary log. This results in two read-write transactions.
470
--echo # In row level replication mode, we do not call
471
--echo # handler::ha_delete_all_rows(), but delete rows one by one.
472
--echo # Since there are no rows, nothing is written to the binary log.
473
--echo # Thus we have just one read-only transaction in InnoDB.
475
call p_verify_status_increment(2, 2, 1, 0);
477
call p_verify_status_increment(2, 2, 1, 0);
479
--echo # 9. Read-write statement: REPLACE, change 1 row.
482
call p_verify_status_increment(2, 2, 2, 2);
484
call p_verify_status_increment(2, 2, 2, 2);
486
--echo # 10. Read-write statement: REPLACE, change 0 rows.
489
call p_verify_status_increment(2, 2, 1, 0);
491
call p_verify_status_increment(2, 2, 1, 0);
493
--echo # 11. Read-write statement: IODKU, change 1 row.
495
insert t1 set a=1 on duplicate key update a=a+1;
496
call p_verify_status_increment(2, 2, 2, 2);
498
call p_verify_status_increment(1, 0, 1, 0);
500
call p_verify_status_increment(2, 2, 2, 2);
502
--echo # 12. Read-write statement: IODKU, change 0 rows.
504
insert t1 set a=2 on duplicate key update a=2;
505
call p_verify_status_increment(1, 0, 1, 0);
507
call p_verify_status_increment(1, 0, 1, 0);
509
--echo # 13. Read-write statement: INSERT IGNORE, change 0 rows.
511
insert ignore t1 set a=2;
512
call p_verify_status_increment(1, 0, 1, 0);
514
call p_verify_status_increment(1, 0, 1, 0);
516
--echo # 14. Read-write statement: INSERT IGNORE, change 1 row.
518
insert ignore t1 set a=1;
519
call p_verify_status_increment(2, 2, 2, 2);
521
call p_verify_status_increment(2, 2, 2, 2);
522
--echo # 15. Read-write statement: UPDATE IGNORE, change 0 rows.
524
update ignore t1 set a=2 where a=1;
525
call p_verify_status_increment(2, 2, 1, 0);
527
call p_verify_status_increment(2, 2, 1, 0);
529
--echo # Create a stored function that modifies a
530
--echo # non-transactional table. Demonstrate that changes in
531
--echo # non-transactional tables do not affect the two phase commit
535
create function f1() returns int
541
call p_verify_status_increment(0, 0, 0, 0);
543
--echo # 16. A function changes non-trans-table.
545
--echo # For row-based logging, there is an extra commit for the
546
--echo # non-transactional changes saved in the transaction cache to
547
--echo # the binary log.
550
call p_verify_status_increment(0, 0, 1, 0);
552
call p_verify_status_increment(0, 0, 1, 0);
554
--echo # 17. Read-only statement, a function changes non-trans-table.
556
--echo # For row-based logging, there is an extra commit for the
557
--echo # non-transactional changes saved in the transaction cache to
558
--echo # the binary log.
561
call p_verify_status_increment(1, 0, 2, 0);
563
call p_verify_status_increment(1, 0, 2, 0);
565
--echo # 18. Read-write statement: UPDATE, change 0 (transactional) rows.
567
select count(*) from t2;
568
update t1 set a=2 where a=f1()+10;
569
select count(*) from t2;
570
call p_verify_status_increment(2, 0, 2, 0);
572
call p_verify_status_increment(2, 0, 2, 0);
574
--echo # Replace the non-transactional table with a temporary
575
--echo # transactional table. Demonstrate that a change to a temporary
576
--echo # transactional table does not provoke 2-phase commit, although
577
--echo # does trigger a commit and a binlog write (in statement mode).
580
set sql_mode=no_engine_substitution;
581
create temporary table t2 (a int);
582
call p_verify_status_increment(0, 0, 0, 0);
583
set sql_mode=default;
584
--echo # 19. A function changes temp-trans-table.
587
--echo # Two commits because a binary log record is written
588
call p_verify_status_increment(2, 0, 1, 0);
590
call p_verify_status_increment(2, 0, 1, 0);
592
--echo # 20. Read-only statement, a function changes non-trans-table.
595
--echo # Two commits because a binary log record is written
596
call p_verify_status_increment(2, 0, 1, 0);
598
call p_verify_status_increment(2, 0, 1, 0);
600
--echo # 21. Read-write statement: UPDATE, change 0 (transactional) rows.
602
update t1 set a=2 where a=f1()+10;
603
call p_verify_status_increment(2, 0, 1, 0);
605
call p_verify_status_increment(2, 0, 1, 0);
607
--echo # 22. DDL: ALTER TEMPORARY TABLE, should not cause a 2pc
609
alter table t2 add column b int default 5;
610
--echo # A commit is done internally by ALTER.
611
call p_verify_status_increment(2, 0, 2, 0);
613
--echo # There is nothing left to commit
614
call p_verify_status_increment(0, 0, 0, 0);
616
--echo # 23. DDL: RENAME TEMPORARY TABLE, does not start a transaction
618
--echo # No test because of Bug#8729 "rename table fails on temporary table"
620
--echo # 24. DDL: TRUNCATE TEMPORARY TABLE, does not start a transaction
623
call p_verify_status_increment(2, 0, 2, 0);
625
--echo # There is nothing left to commit
626
call p_verify_status_increment(0, 0, 0, 0);
628
--echo # 25. Read-write statement: unqualified DELETE
631
call p_verify_status_increment(2, 0, 1, 0);
633
--echo # There is nothing left to commit
634
call p_verify_status_increment(2, 0, 1, 0);
636
--echo # 25. DDL: DROP TEMPORARY TABLE, does not start a transaction
638
drop temporary table t2;
639
call p_verify_status_increment(0, 0, 0, 0);
641
call p_verify_status_increment(0, 0, 0, 0);
643
--echo # 26. Verify that SET AUTOCOMMIT issues an implicit commit
646
call p_verify_status_increment(2, 2, 2, 2);
648
call p_verify_status_increment(2, 2, 2, 2);
650
select a from t1 where a=3;
651
call p_verify_status_increment(1, 0, 1, 0);
652
delete from t1 where a=3;
653
call p_verify_status_increment(2, 2, 2, 2);
655
call p_verify_status_increment(0, 0, 0, 0);
657
call p_verify_status_increment(0, 0, 0, 0);
659
call p_verify_status_increment(2, 2, 2, 2);
660
--echo # Sic: not actually changing the value of autocommit
662
call p_verify_status_increment(0, 0, 0, 0);
664
select a from t1 where a=3;
665
call p_verify_status_increment(1, 0, 1, 0);
667
--echo # 27. Savepoint management
670
call p_verify_status_increment(2, 2, 2, 2);
672
call p_verify_status_increment(0, 0, 0, 0);
674
--echo # Sic: a bug. Binlog did not register itself this time.
675
call p_verify_status_increment(1, 0, 1, 0);
678
call p_verify_status_increment(0, 0, 0, 0);
679
select a from t1 where a=3;
680
call p_verify_status_increment(1, 0, 1, 0);
682
call p_verify_status_increment(1, 0, 1, 0);
684
--echo # 28. Read-write statement: DO
686
create table t2 (a int);
687
call p_verify_status_increment(0, 0, 0, 0);
688
do (select f1() from t1 where a=2);
689
call p_verify_status_increment(2, 2, 2, 2);
691
call p_verify_status_increment(2, 2, 2, 2);
693
--echo # 29. Read-write statement: MULTI-DELETE
695
delete t1, t2 from t1 join t2 on (t1.a=t2.a) where t1.a=2;
697
call p_verify_status_increment(4, 4, 4, 4);
699
--echo # 30. Read-write statement: INSERT-SELECT, MULTI-UPDATE, REPLACE-SELECT
701
insert into t2 select a from t1;
703
replace into t2 select a from t1;
705
call p_verify_status_increment(8, 8, 8, 8);
707
# Multi-update is one of the few remaining statements that still
708
# locks the tables at prepare step (and hence starts the transaction.
709
# Disable the PS protocol, since in this protocol we get a different
710
# number of commmits (there is an extra commit after prepare
712
--disable_ps_protocol
713
update t1, t2 set t1.a=4, t2.a=8 where t1.a=t2.a and t1.a=1;
716
call p_verify_status_increment(4, 4, 4, 4);
718
--echo # 31. DDL: various DDL with transactional tables
720
--echo # Sic: no table is created.
721
create table if not exists t2 (a int) select 6 union select 7;
722
--echo # Sic: first commits the statement, and then the transaction.
723
call p_verify_status_increment(4, 4, 4, 4);
724
create table t3 select a from t2;
725
call p_verify_status_increment(4, 4, 4, 4);
726
alter table t3 add column (b int);
727
call p_verify_status_increment(2, 0, 2, 0);
728
alter table t3 rename t4;
729
call p_verify_status_increment(1, 0, 1, 0);
730
rename table t4 to t3;
731
call p_verify_status_increment(1, 0, 1, 0);
733
call p_verify_status_increment(2, 2, 2, 2);
734
create view v1 as select * from t2;
735
call p_verify_status_increment(1, 0, 1, 0);
737
call p_verify_status_increment(3, 0, 3, 0);
738
--echo # Sic: after this bug is fixed, CHECK leaves no pending transaction
740
call p_verify_status_increment(0, 0, 0, 0);
741
check table t1, t2, t3;
742
call p_verify_status_increment(6, 0, 6, 0);
744
call p_verify_status_increment(0, 0, 0, 0);
746
call p_verify_status_increment(0, 0, 0, 0);
751
drop table t1, t2, t3;
752
drop procedure p_verify_status_increment;