I need to call a procedure that modifies root password inside a trigger.
This is the procedure
delimiter //
create procedure foobar ()
begin SET PASSWORD FOR 'root'#'localhost' = 'foobar';
end//
delimiter ;
and this is the trigger
delimiter //
create trigger rootpass
after delete on map
for each row
begin
call foobar;
end //
delimiter ;
It seems the syntax is correct but when I launch a delete I get this error
ERROR 1445 (HY000): Not allowed to set autocommit from a stored function or trigger
So I think I'm trying to do a forbidden thing, is there any way this could work in mysql?
I know the whole thing sounds weird/horrible but this is the way for my application to understand that something has been deleted.
When executing a statement would cause an implicit commit of the current transaction, that statement is not permitted within a trigger or stored function.
This includes a statement in a stored procedure that is invoked by a trigger or function -- there is no layer of abstraction here that makes the invalid action any more valid.
Related
I am getting this error on the SQL schema. The error message i am getting is
"
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'CREATE TRIGGER updtrigger_r4_balance AFTER UPDATE ON
resellers4 FOR EACH R' at line 2"
What syntax is going wrong? I am attaching 2 SQL schema. Both having same problem.
delimiter // DROP TRIGGER IF EXISTS updtrigger_r4_balance;
CREATE TRIGGER updtrigger_r4_balance AFTER
UPDATE
ON resellers4 FOR EACH ROW
BEGIN
IF NEW.callsLimit <= 0
THEN
UPDATE
resellers4_child r4c
INNER JOIN
resellers3 r3
ON (r4c.reseller3_id = r3.id)
SET
r4c.reseller3_callsLimit = r4c.reseller3_callsLimit + r3.callsLimit, r3.callsLimit = 0
WHERE
r4c.reseller4_id = new.id;
END
IF;
END
// delimiter ;
Another one is:
delimiter //
DROP TRIGGER
IF EXISTS updtrigger_r4_balance_add;
CREATE TRIGGER updtrigger_r4_balance_add BEFORE UPDATE ON resellers4 FOR EACH ROW
BEGIN
IF OLD.callsLimit <= 0 THEN
UPDATE resellers3 r3
INNER JOIN resellers4_child r4c ON (r4c.reseller3_id=r3.id)
SET
r3.callsLimit = r3.callsLimit+r4c.reseller3_callsLimit,
r4c.reseller3_callsLimit = 0
WHERE r4c.reseller4_id=new.id;
END IF;
END
//
delimiter ;
After you change the delimiter you have to use it instead of ;
delimiter //
DROP TRIGGER IF EXISTS updtrigger_r4_balance_add; <--- use // instead
MySQL uses ; to separate the queries. Multiple queries can be sent to the server in a single request; the server use the current delimiter (default ;) to split the received text into queries.
There are complex SQL constructs (triggers, stored procedures etc) that may include one or more queries or a BEGIN..END compound statement in their definition.
Because such constructs usually contains two or more queries, separated by the usual delimiter (;), MySQL needs a way to know where the enclosing compound construct ends.
The DELIMITER statement is used to replace the default delimiter (;) with a different one when a compound statement is defined. This allows the standard delimiter (;) to be used inside the body of the compound statement.
It works this way:
The DELIMITER statement is used to change the current delimiter; various values are used as delimiter instead. // is suggested in the documentation but other values can be used too. The only rule is to use a character (or a sequence of characters) that does not appear in the compound statement that is to be defined after it.
From now on, all the subsequent queries must end with the new delimiter (and not with ;).
Declare the complex construct (be it a trigger, stored procedure at event). If it contains more than one statements they have to be separated by ;.
End the complex construct with the delimiter declared on step 1.
Use DELIMITER ; to reset the delimiter. If another statement follows then you have to terminate the DELIMITER statement with the delimiter you set on step 1 (because it is the current delimiter; the new one becomes effective after this statement is parsed and executed).
The solution of your problem is simple: either you use the delimiter you set (//) to separate the DROP TRIGGER and the CREATE TRIGGER statements:
delimiter //
DROP TRIGGER
IF EXISTS updtrigger_r4_balance_add //
CREATE TRIGGER updtrigger_r4_balance_add BEFORE UPDATE ON resellers4 FOR EACH ROW
BEGIN
...
END
//
delimiter ;
Or you move the DROP TRIGGER statement before the DELIMITER statement and leave it as it is (terminated with ;):
DROP TRIGGER
IF EXISTS updtrigger_r4_balance_add;
delimiter //
CREATE TRIGGER updtrigger_r4_balance_add BEFORE UPDATE ON resellers4 FOR EACH ROW
BEGIN
...
END
//
delimiter ;
Also after delimiter changes try to replace word new in statement
r4c.reseller4_id = new.id;
with uppercase one. Because OLD and NEW are MySQL extensions to triggers, so they aren't case sensitive.
I am trying to understand, why delimiter used with stored procedure in mysql?
but i couldn't.
DELIMITER //
CREATE PROCEDURE GetAllProducts()
BEGIN
SELECT * FROM products;
END //
DELIMITER ;`
Mysql's default delimiter is ; which is used for one statement in the command line , something as
select * from users ;
When you write a trigger or stored procedure to execute the entire code mysql needs to understand that its a block of code/query.
If no delimiter is provided then when mysql encounters any ; inside the store procedure or trigger it will think that as one statement and will try to execute it. So we need to provide a delimiter for store procedure or trigger and make mysql understand that anything within that delimiter is one complete set of code.
So in your example
SELECT * FROM products;
it will be a part of the complete statement when there is a delimiter other than ; is provided at the beginning.
I am trying out functions and triggers int postgreSQL, however i am having a problem, when the function is triggered it is giving me an error
ERROR: control reached end of trigger procedure without RETURN
this particular procedure is only executing an insert into command so i do not see why it needs a return
this is the script:
CREATE OR REPLACE FUNCTION forest_aud_func() returns trigger as $tree_stamp$
BEGIN
insert into Audit values('k',124,'l');
END;
$tree_stamp$
LANGUAGE plpgsql;
create trigger forest_aud_ins after insert on forest
for each row execute procedure forest_aud_func()
insert into forest values('Blue',1600,'Malta','Health Ltd')
The error message tells you all. You need to do a RETURN from the trigger function:
CREATE OR REPLACE FUNCTION forest_aud_func() returns trigger as $tree_stamp$
BEGIN
insert into Audit values('k',124,'l');
return new;
END;
$tree_stamp$
LANGUAGE plpgsql;
From the manual:
A trigger function must return either NULL or a record/row value having exactly the structure of the table the trigger was fired for.
I am working on MySQL 5.1.3 and using PHPMyAdmin 3.1.3.1 to access it. With PHP as the Server side scripting Language. My problem statement is can we call a Stored Procedure or Function from the Trigger statement so that when ever an INSERT|UPDATE|DELETE trigger is called, it calls the SP for updating some other tables according to the logic defined.
Look here Mysql Trigger Syntax
mysql> delimiter //
mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
-> FOR EACH ROW
-> BEGIN
-> IF NEW.amount < 0 THEN
-> SET NEW.amount = 0;
-> ELSEIF NEW.amount > 100 THEN
-> SET NEW.amount = 100;
-> END IF;
-> END;//
mysql> delimiter;
It can be easier to define a stored procedure separately and then invoke it from the trigger using a simple CALL statement. This is also advantageous if you want to invoke the same routine from within several triggers.
There are some limitations on what can appear in statements that a trigger executes when activated:
The trigger cannot use the CALL statement to invoke stored procedures that return data to the client or that use dynamic SQL. (Stored procedures are permitted to return data to the trigger through OUT or INOUT parameters.)
The trigger cannot use statements that explicitly or implicitly begin or end a transaction such as START TRANSACTION, COMMIT, or ROLLBACK.
when trying to create a simple procedure in mysql 5.1.47-community it fails everytime i've tried everything!
even simple things like this!
DELIMITER //
CREATE PROCEDURE two ()
begin
SELECT 1+1;
end;
//
The error is
ERROR: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'mydb' at line 1
The error message you've given doesn't correspond to the code you've pasted. You're referring to "mydb" somewhere in the SQL you're running yet it's not anywhere in the code you've put in the question.
The code you've given should work fine as I see no syntax errors, you may just need to give it a database to work on ("test" in my case here, perhaps it should be "mydb" for you?).
DELIMITER //
CREATE PROCEDURE test.two ()
begin
SELECT 1+1;
end;
//
DELIMITER ;
CALL test.two;
However, I suspect the error you're getting is become of a line in your SQL that you're not showing us.
EDIT
It could perhaps be the delimiter command. You're changing the delimiter to // rather than the default ;. So perhaps you've run that command (and changed the delimiter for your session to //), and then tried to run USE mydb; where the ; is no longer recognised as a valid delimiter for your session, and that could be giving you the error. Try putting delimiter ; before your use line and see if that helps (and then use it again after you've defined your stored procedure so you can call it). This is just a theory though, as I'm not sure of the intricacies of the delimiter command.
Remove the final delimiter "end" instead "end;"
I had the same problem using heidisql as the fronted to enter the SQL. My first attempt was:
CREATE PROCEDURE Add_Two (IN someNumber int, OUT result INT)
BEGIN
SELECT someNumber +2 INTO result;
END
and this resulted in SQL ERROR (1064) because i was not aware that when using a client program a delimiter is needed to define the stored procedures.
After changing the above to this:
DELIMITER //
CREATE PROCEDURE Add_Two(IN someNumber int, OUT result INT)
BEGIN
SELECT someNumber +2 INTO result;
END
//
It worked out.
Example to call it
SET #someNumber :=8;
CALL Add_Two(#someNumber, #result);
SELECT #result;