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 default_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);
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/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
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(2, 2, 1, 0);
507 call p_verify_status_increment(2, 2, 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(2, 2, 1, 0);
514 call p_verify_status_increment(2, 2, 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.
525 update ignore t1 set a=2 where a=1;
527 if (`select @@binlog_format = 'STATEMENT
'`)
530 call p_verify_status_increment(2, 2, 1, 0);
533 if (`select @@binlog_format != 'STATEMENT
'`)
536 call p_verify_status_increment(1, 0, 1, 0);
540 if (`select @@binlog_format = 'STATEMENT
'`)
543 call p_verify_status_increment(2, 2, 1, 0);
546 if (`select @@binlog_format != 'STATEMENT
'`)
549 call p_verify_status_increment(1, 0, 1, 0);
553 --echo # Create a stored function that modifies a
554 --echo # non-transactional table. Demonstrate that changes in
555 --echo # non-transactional tables do not affect the two phase commit
559 create function f1() returns int
565 call p_verify_status_increment(0, 0, 0, 0);
567 --echo # 16. A function changes non-trans-table.
569 --echo # For row-based logging, there is an extra commit for the
570 --echo # non-transactional changes saved in the transaction cache to
571 --echo # the binary log.
574 call p_verify_status_increment(1, 0, 1, 0);
576 call p_verify_status_increment(1, 0, 1, 0);
578 --echo # 17. Read-only statement, a function changes non-trans-table.
580 --echo # For row-based logging, there is an extra commit for the
581 --echo # non-transactional changes saved in the transaction cache to
582 --echo # the binary log.
587 call p_verify_status_increment(2, 0, 2, 0);
589 call p_verify_status_increment(2, 0, 2, 0);
591 --echo # 18. Read-write statement: UPDATE, change 0 (transactional) rows.
593 select count(*) from t2;
595 update t1 set a=2 where a=f1()+10;
597 select count(*) from t2;
598 call p_verify_status_increment(2, 0, 2, 0);
600 call p_verify_status_increment(2, 0, 2, 0);
602 --echo # Replace the non-transactional table with a temporary
603 --echo # transactional table. Demonstrate that a change to a temporary
604 --echo # transactional table does not provoke 2-phase commit, although
605 --echo # does trigger a commit and a binlog write (in statement mode).
608 set sql_mode=no_engine_substitution;
609 create temporary table t2 (a int);
610 call p_verify_status_increment(1, 0, 0, 0);
611 set sql_mode=default;
612 --echo # 19. A function changes temp-trans-table.
615 --echo # Two commits because a binary log record is written
616 call p_verify_status_increment(2, 0, 1, 0);
618 call p_verify_status_increment(2, 0, 1, 0);
620 --echo # 20. Read-only statement, a function changes non-trans-table.
623 --echo # Two commits because a binary log record is written
624 call p_verify_status_increment(2, 0, 1, 0);
626 call p_verify_status_increment(2, 0, 1, 0);
628 --echo # 21. Read-write statement: UPDATE, change 0 (transactional) rows.
631 update t1 set a=2 where a=f1()+10;
633 call p_verify_status_increment(2, 0, 1, 0);
635 call p_verify_status_increment(2, 0, 1, 0);
637 --echo # 22. DDL: ALTER TEMPORARY TABLE, should not cause a 2pc
639 alter table t2 add column b int default 5;
640 --echo # A commit is done internally by ALTER.
641 call p_verify_status_increment(2, 0, 2, 0);
643 --echo # There is nothing left to commit
644 call p_verify_status_increment(0, 0, 0, 0);
646 --echo # 23. DDL: RENAME TEMPORARY TABLE, does not start a transaction
648 --echo # No test because of Bug#8729 "rename table fails on temporary table"
650 --echo # 24. DDL: TRUNCATE TEMPORARY TABLE
653 call p_verify_status_increment(4, 0, 4, 0);
655 --echo # There is nothing left to commit
656 call p_verify_status_increment(0, 0, 0, 0);
658 --echo # 25. Read-write statement: unqualified DELETE
661 call p_verify_status_increment(2, 0, 1, 0);
663 --echo # There is nothing left to commit
664 call p_verify_status_increment(2, 0, 1, 0);
666 --echo # 25. DDL: DROP TEMPORARY TABLE, does not start a transaction
668 drop temporary table t2;
669 call p_verify_status_increment(1, 0, 1, 0);
671 call p_verify_status_increment(1, 0, 1, 0);
673 --echo # 26. Verify that SET AUTOCOMMIT issues an implicit commit
676 call p_verify_status_increment(2, 2, 2, 2);
678 call p_verify_status_increment(2, 2, 2, 2);
680 select a from t1 where a=3;
681 call p_verify_status_increment(1, 0, 1, 0);
682 delete from t1 where a=3;
683 call p_verify_status_increment(2, 2, 2, 2);
685 call p_verify_status_increment(0, 0, 0, 0);
687 call p_verify_status_increment(0, 0, 0, 0);
689 call p_verify_status_increment(2, 2, 2, 2);
690 --echo # Sic: not actually changing the value of autocommit
692 call p_verify_status_increment(0, 0, 0, 0);
694 select a from t1 where a=3;
695 call p_verify_status_increment(1, 0, 1, 0);
697 --echo # 27. Savepoint management
700 call p_verify_status_increment(2, 2, 2, 2);
702 call p_verify_status_increment(1, 0, 1, 0);
704 call p_verify_status_increment(2, 2, 2, 2);
707 call p_verify_status_increment(0, 0, 0, 0);
708 select a from t1 where a=3;
709 call p_verify_status_increment(1, 0, 1, 0);
711 call p_verify_status_increment(1, 0, 1, 0);
713 --echo # 28. Read-write statement: DO
715 create table t2 (a int);
716 call p_verify_status_increment(0, 0, 0, 0);
717 do (select f1() from t1 where a=2);
718 call p_verify_status_increment(2, 2, 2, 2);
720 call p_verify_status_increment(2, 2, 2, 2);
722 --echo # 29. Read-write statement: MULTI-DELETE
724 delete t1, t2 from t1 join t2 on (t1.a=t2.a) where t1.a=2;
726 call p_verify_status_increment(4, 4, 4, 4);
728 --echo # 30. Read-write statement: INSERT-SELECT, MULTI-UPDATE, REPLACE-SELECT
730 insert into t2 select a from t1;
733 replace into t2 select a from t1;
736 call p_verify_status_increment(8, 8, 8, 8);
738 # Multi-update is one of the few remaining statements that still
739 # locks the tables at prepare step (and hence starts the transaction.
740 # Disable the PS protocol, since in this protocol we get a different
741 # number of commmits (there is an extra commit after prepare
743 --disable_ps_protocol
744 update t1, t2 set t1.a=4, t2.a=8 where t1.a=t2.a and t1.a=1;
747 call p_verify_status_increment(4, 4, 4, 4);
749 --echo # 31. DDL: various DDL with transactional tables
751 --echo # Sic: no table is created.
752 create table if not exists t2 (a int) select 6 union select 7;
753 --echo # No table are locked before existing t2 is found, so nothing to commit.
754 call p_verify_status_increment(0, 0, 0, 0);
755 create table t3 select a from t2;
756 call p_verify_status_increment(2, 0, 4, 4);
757 alter table t3 add column (b int);
758 call p_verify_status_increment(2, 0, 2, 0);
759 alter table t3 rename t4;
760 call p_verify_status_increment(0, 0, 0, 0);
761 rename table t4 to t3;
762 call p_verify_status_increment(0, 0, 0, 0);
764 call p_verify_status_increment(2, 0, 2, 0);
765 create view v1 as select * from t2;
766 call p_verify_status_increment(0, 0, 0, 0);
768 call p_verify_status_increment(2, 0, 2, 0);
769 --echo # Sic: after this bug is fixed, CHECK leaves no pending transaction
771 call p_verify_status_increment(0, 0, 0, 0);
772 check table t1, t2, t3;
773 call p_verify_status_increment(6, 0, 6, 0);
775 call p_verify_status_increment(0, 0, 0, 0);
777 call p_verify_status_increment(0, 0, 0, 0);
782 drop table t1, t2, t3;
783 drop procedure p_verify_status_increment;