I'm trying to insert rows into a table via a trigger or stored procedure without writing any data to the binary log. Is this possible? I know that for normal connections you can set SQL_LOG_BIN=0 to disable binary logging for the connection, but I haven't been able to get that to work for triggers. If there's a way to do this with a federated engine table, that would also be OK.
edit:
I can almost accomplish this via a stored procedure:
CREATE PROCEDURE nolog_insert(`id` INT, `data` blob)
BEGIN
SET SESSION SQL_LOG_BIN = 0;
INSERT INTO `table` (`id`, `data`) VALUES (id, data);
SET SESSION SQL_LOG_BIN = 1;
END
I insert a record by calling the procedure from the mysql prompt:
call nolog_insert(50, 'notlogged');
As expected, the record (50, 'notlogged') is inserted into the table, but is not written to the binary log.
However, I want to run this procedure from a trigger. When using a trigger as follows:
create trigger my_trigger before insert on blackhole_table for each row call nolog_insert(new.id, new.data);
The data is both inserted to the table and written to the binary log.
If you run statement based replication triggers are executed on both the master and the slave but not replicated. Perhaps that could solve your problem.
Other than that, it's not allowed to change sql_log_bin inside a transaction so I would say that there is no good way to have the effects of a trigger not replicated when using row based replication.
Related
Sooo, I´m writing in MySQL a trigger to count how many attempts of an insert query happened (even failed attempts) but so far nothing.
If the insert is succesful, the variable 'attempts' increases its value by one. But when the insert query fails (because you tried to insert something ilogical) the trigger makes a rollback and 'attempts' doesn't increase.
How to avoid the rollback? Or how to outsmart it so 'attempts' will increase?
Here is my code:
CREATE TABLE myData (myValues INT);
SET attempts =0;
DELIMITER |
CREATE TRIGGER countingAttempts BEFORE INSERT ON myData FOR EACH ROW
SET #attempts = #attempts+1;
DELIMITER ;
INSERT INTO myData VALUES(10); /* It works, attempts becomes 1*/
INSERT INTO myData VALUES (X); /* The insert query fails because 'myValues' is INT and X is not an INT, attempts should become 2, but the trigger rollsback and attemps doesn´t change*/
It seems like you are trying to count attempted inserts that result in errors due to bad data (presumably with STRICT_TRANS_TABLES mode enabled).
There is no "rollback", since no insert was actually done. The trigger simply isn't executed by the point the error is detected.
(Though if you are inserting multiple rows, the trigger will be executed for initial correct rows before the erroneous one, so you will see the variable increased in that case.)
You could experiment with disabling STRICT_TRANS_TABLES and doing some validation in your trigger instead, but that's going to have an effect on all other tables and update statements too, so I wouldn't recommend it.
The other option I see is to not do inserts from the client, but instead call a stored procedure to do the insert; that gives you a chance to increment your counter in the stored procedure whether the insert works or not.
I have this STP:
CREATE DEFINER=`user1`#`%` PROCEDURE `test`(
OUT result TINYINT
)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET result = -1;
ROLLBACK;
END;
START TRANSACTION;
INSERT INTO testtable (field1, field2) VALUES (11, 22);
SET result = 1;
END
After I execute it inside MySQLWorkbench (6.3 64b), testtable have new record. I though data must be not commited because there is no commit statement.
Then I try to call that STP again by C# client, and this time, new data is not commited.
Please help me to explain this problem, I dont understand what is the different between calling STP inside Workbench and calling STP by another client.
Thanks.
The difference is that when you query the table again inside mysql workbench you are inside the same session. Even though your changes have not been committed, even though your changes are not committed you can still see them because the same client session is allowed to see uncommited changes.
If however you start up a new session of mysql workbench or the mysql shell you will not see the changes that you have made through your existing workbench session.
I have to limit table record to 25. after I just delete everything (in the future will modify it to delete just oldest rows)
DELIMITER //
CREATE PROCEDURE p1 () delete FROM tests;//
CREATE TRIGGER trigger1
BEFORE INSERT
ON tests
FOR EACH ROW
BEGIN
SELECT COUNT(*) INTO #cnt FROM tests;
IF #cnt >= 25 THEN
CALL p1();
END IF;
END
//
DELIMITER ;
, but I am getting error:
Can't update table 'tests' in stored function/trigger because it is already used by statement which invoked this stored function/trigger
So I can not add any more fields.
The MySQL trigger FAQ sais that you cannot modify the table that calls the trigger.
But you can set up a cron job, or CREATE EVENT in MySQL that cleans the table at regular intervals. (CREATE EVENT needs the PROCESS privilege, and a running event_scheduler. The event_scheduler is turned off by default: it can be turned on from SQL console, but the MySQL config must be modified to ensure that it starts when MySQL restarts.)
It seems that you can't update or delete from the same table which invoked the trigger.
But you can work around this by creating another table, for example tests2 and instead of inserting into tests just insert into tests2, and have the trigger insert the NEW. values into tests, then you can count from tests and delete from tests like how you want it.
see this sqlFiddle
The problem with this is then tests2 gets filled up with Inserted data So you might have to manually delete from tests2.
My MySQL 5.5 server has set autocommit=1.
My stored procedure has several DMLs but without explicit transaction management.
When I issue call the_procedure() from MySQL CLI (autocommit is still 1), do all the procedure's DMLs run in one transaction?
Or do they run in separate transactions, and causing implicit transaction commit after every DML (due to autocommit)?
This is surprising to me but:
Although MySQL will automatically initiate a transaction on your
behalf when you issue DML statements, you should issue an explicit
START TRANSACTION statement in your program to mark the beginning of
your transaction.
It's possible that your stored program might be run within a server in
which autocommit is set to TRUE, and by issuing an explicit START
TRANSACTION statement you ensure that autocommit does not remain
enabled during your transaction. START TRANSACTION also aids
readability by clearly delineating the scope of your transactional
code.
They run in separate transactions if autocommit=1. Suppose you define
CREATE TABLE test ( id int PRIMARY KEY )//
CREATE PROCEDURE sp_test_trans()
BEGIN
INSERT INTO test (id) VALUES (1);
INSERT INTO test (id) VALUES (2);
ROLLBACK;
END//
If you run this procedure with autocommit=0, the ROLLBACK will undo the insertions. If you run it with autocommit=1, the ROLLBACK will do nothing. Fiddle here.
Another example:
CREATE PROCEDURE sp_test_trans_2()
BEGIN
INSERT INTO test (id) VALUES (1);
INSERT INTO test (id) VALUES (1);
END//
If you run this procedure with autocommit=0, failure of the second insert will cause a ROLLBACK undoing the first insertion. If you run it with autocommit=1, the second insert will fail but the effects of the first insert will not be undone.
Tests done in the following SQL Fiddle, shows that by not explicitly handle transactions are handled separately when the variable autocommit is 1 (TRUE).
how to create trigger in mysql in coldfusion at the time of insert, update and delete operation.
Thanks
Yugal
I don't really get the point of this because the whole idea of using triggers is to automatically have the database do something without the need to do it from your server-side language on every insert/update or delete.
So basically it's code you only execute once to create the trigger.
I suppose it's just creating a trigger between your <CFQUERY> tags similar to how you do an insert, update or delete operation
Before the insert
CREATE TRIGGER triggerName BEFORE INSERT ON tableName FOR EACH ROW what_ever_you_want_your_trigger_todo;
After the insert
CREATE TRIGGER triggerName AFTER INSERT ON tableName FOR EACH ROW what_ever_you_want_your_trigger_todo;
http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
But really I would do this using a mysql-client, set and forget it. Depending on the use of BEFORE or AFTER it will be executed either before or after your insert/update/delete statement on that table.