Apparently I cannot combine the GET DIAGNOSTICS and ROLLBACK statements inside a stored procedure: besides catching the error, I want to be able to reverse all the previous processed data, not just to stop the execution. Please find bellow my script:
Create the log table:
CREATE TABLE tbl_logs (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`txt` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`));
Create the stored procedure:
DELIMITER $$
CREATE PROCEDURE `test`()
BEGIN
DECLARE state CHAR(5) DEFAULT ’00000′;
DECLARE msg TEXT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
begin
rollback;
GET DIAGNOSTICS CONDITION 1 state = RETURNED_SQLSTATE, msg = MESSAGE_TEXT;
insert into tbl_logs (txt) select concat(‘Error ‘,state,’: ‘,msg);
end;
start transaction;
insert into tbl_logs (txt) select state;
– drop table no_such_table;
insert into tbl_logs (txt) select ‘commit’;
commit;
END
call the procedure:
call test();
select * from tbl_logs;
=> check the table: 2 rows
00000
commit
Alter the procedure:
Take the comment out, making the drop table visible.
call the procedure:
call test();
select * from tbl_logs;
=> check the table: 2 new rows instead of just one, the last
00000
Error 42S02: Unknown table ‘no_such_table’
=> the handler catches the error and stops the execution, is just that doesn’t consider the rollback (no matter what/where other DML are previously made, they are committed)…
What am I doing wrong?
As documented under DROP TABLE Syntax:
Note
DROP TABLE automatically commits the current active transaction, unless you use the TEMPORARY keyword.
Related
I have created a student table.
CREATE TABLE `student` (
`id` int DEFAULT NULL,
`name` varchar(5) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
I have created a stored procedure inserting the data.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_studentinsert1`(in_id int, in_name varchar(5),inn_id int, inn_name varchar(10))
BEGIN
DECLARE `_rollback` BOOL DEFAULT 0;
DECLARE exit HANDLER FOR SQLEXCEPTION
begin
ROLLBACK;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'SQLError occured. Triggered ROLLBACK';
select 'err' as message;
-- ERROR
end;
start transaction;
insert into student(id,name) values(in_id,in_name);
INSERT INTO student(id,name) values(inn_id,inn_name);
commit;
select * from student;
END$$
DELIMITER ;
. I have written two insert queries inside of stored procedure. I have given first two input parameters valid data, For 2nd record , I have given invalid data, once run the sp, first record inserted & 2nd record exception happen but once exception happen , 1st record rollback not happen.
Please help me.
One of the client has asked us to write a store procedure in mysql, which states that one data should be accessed by only one resources (Even if their happens to be Multiple resources ready to read the data, whomsoever will come first will take the lock first and would change its flag so that not other resources should be able to take a lock on this data row in a table.
Store procedure is to be written for it, i believe it to be similar to bank transaction management, but i have no clue how to write a stored procedure for it, any help will be highly appreciated, Thanks well in advance.
Step : 1
CREATE TABLE `test_db`.`Jobs` (
`id` INT NOT NULL,
`JOB` VARCHAR(45) NOT NULL,
`status` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC));
Step : 2
DELIMITER $$
create procedure aabraKaDaabra(IN ids INT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
DECLARE EXIT HANDLER FOR SQLWARNING ROLLBACK;
START TRANSACTION;
select id from Jobs where id=ids for update;
update Jobs set status = 'Submitted' where id=ids;
commit;
END$$;
Step : 3
select * from test_db.Jobs order by id desc;
Note:
Make sure that you have inserted a few of the value for the table.
Step : 4
call test_db.aabraKaDaabra(1);
This is what i was expecting and solved it , it worked like a charm
I am using mysql v5.6.
After inserting duplicate record in users table through stored procedure It throws an exception and this is good but unable to rollback for table POSTS.
Here is SQL codes for SP :
DELIMITER //
CREATE PROCEDURE usp_add_user_tests
( IN `i_name` VARCHAR(50),
IN `i_email` VARCHAR(100),
IN `i_status` TINYINT(1) UNSIGNED,
OUT `p_sqlcode` INT(11) UNSIGNED,
OUT `p_status_message` VARCHAR(100)
)
MODIFIES SQL DATA
BEGIN
DECLARE duplicate_key CONDITION FOR 1062;
DECLARE EXIT HANDLER FOR duplicate_key
BEGIN SET p_sqlcode=1062; SET p_status_message='Duplicate key error';
ROLLBACK ;
END;
SET p_sqlcode=0;
INSERT INTO posts (title)
VALUES('test');
INSERT INTO users (name,email,status)
VALUES(i_name,i_email,i_status);
IF p_sqlcode<>0 THEN
SET p_status_message=CONCAT(p_status_message,' when inserting new user');
ELSE
SET p_status_message='Success';
END IF;
END //
DELIMITER ;
Is it possible to rollback for table posts without using Start Transaction statement.
I don't think you have actually started a "transaction". I am pretty sure that you need to implement one of the mechanisms listed here: https://dev.mysql.com/doc/refman/5.7/en/commit.html
I just build a stored procedure to test transaction in mysql.
But somehow it's not working.
Here is my code:
USE `test`;
DROP procedure IF EXISTS `testTran`;
DELIMITER $$
USE `test`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `testTran`()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION rollback;
START TRANSACTION;
INSERT INTO `test`.`books`(`name`,`number`) VALUES ('asd', 20);
ALTER TABLE `test`.`books` ADD COLUMN `name` VARCHAR(45) NULL AFTER `number` ;
COMMIT;
END$$
DELIMITER ;
Inside transaction, the second command is create an exist column which will be fail. What I expect is the first insert will be rollback. But actually, it's not. The insert do work.
Can anyone help?
In order to use transactions you need to convert the tables to a transaction table like InnoDB.
Optionally, you can rollback changes made by your stored procedure using SAVEPOINT.
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK TO identifier;
SAVEPOINT identifier;
START TRANSACTION;
INSERT INTO `test`.`books`(`name`,`number`) VALUES ('asd', 20);
ALTER TABLE `test`.`books` ADD COLUMN `name` VARCHAR(45) NULL AFTER `number` ;
COMMIT;
The ALTER TABLE statement causes an implicit COMMIT before it is executed.
Getting the warning 0 row(s) affected, 1 warning(s):
1072 Key column 'name' doesn't exist in table And I do not know what it means. Does anybody have an explaination?
The table/SP is as follows
CREATE TABLE IF NOT EXISTS `sectors`
(
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
`sector` VARCHAR(25) NOT NULL ,
--
PRIMARY KEY (`id`) ,
UNIQUE INDEX `sector_idx` USING BTREE (`sector` ASC)
);
DELIMITER $$
CREATE PROCEDURE `AddSector` (IN sector VARCHAR(25),
OUT result BOOLEAN)
MODIFIES SQL DATA
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING, SQLEXCEPTION SET result = FALSE;
SET result = TRUE;
--
INSERT INTO `sectors` (`sector`) VALUES (sector);
COMMIT;
END $$
Change the procedure to:
DELIMITER $$
CREATE PROCEDURE `AddSector` (IN pSector VARCHAR(25), <<-- fix nameclash here
OUT result BOOLEAN)
MODIFIES SQL DATA
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING, SQLEXCEPTION SET result = FALSE;
SET result = TRUE;
INSERT INTO `sectors` (`sector`) VALUES (pSector); <<-- and here
-- COMMIT; <<-- You don't need a commit.
END $$
All stuff inside a stored proc is already run inside an implicit transaction, so the commit is not needed, and may actually be an error (not sure).
DELIMITER ;