How To Use gearman client in MySQL Trigger implementation - mysql

I have set up gearman udf for database and trying to send a gearman job from mysql query. Normally it is just working fine. as conventional call from mysql query is as follows:
SELECT gman_do_background("eventName", "data");
Now the problem is happening when I am trying to give this call from a mysql trigger implementation. An error is showing up as follows:
MySQL said: #1415 - Not allowed to return a result set from a trigger
So, basically as you can see, either
There is some other way for the gearman call or
Somehow I have make a fake update call with the gearman select call inside there.
I am trying to write the Trigger which is pretty much simple as below:
BEGIN
SELECT gman_do_background("eventName", "#data") FROM
(
SELECT #data := CONCAT(a,',',b,',',c) FROM mytablename WHERE status = 1
)
END
but as yo can see, because of the 'SELECT' operation, its not saving and throwing the above error.
Can anyone please help me whether there is any alternate gearman call type(other than 'select') or is there any way to write update query that doesn't affect any mysql table/column? Thanks in advance.

First of all doing any non-transactional operations in a trigger are wrong. In case of a rollback you won't be able to undo calls to your udf function. So I'd suggest reconsider using triggers for this type of calls.
Highly recommended reading:
The Trouble with Triggers
Now as you figured out SELECTs on their own are prohibited in triggers since there is no client to return the resultset to.
But you can legitimately use INSERT INTO ... SELECT FROM ... syntax. You can create an auxiliary table with BLACKHOLE engine if it is enabled in your MySQL instance. Anything you write to blackhole goes to /dev/null.
CREATE TABLE dev_null
(
value VARCHAR(255) -- adjust data type as needed
) ENGINE=BLACKHOLE;
Then in your trigger
INSERT INTO dev_null
SELECT gman_do_background('eventName', #data)
FROM
(
...
)
Here is SQLFiddle demo

Maybe this link http://codesamplez.com/development/gearman-from-mysql-udf helps (tip 2)

Related

How a trigger on a table works on insert event?

Hypothetically, I am going to develop a trigger that inserts a record to Table A when an insertion made to an Table A.
Therefore, I want to know how the system handles that kind of loophole or it is going to continue as a loop until the system hangs which requires restart and possibly remove the DB.
I'm trying to gather information on almost every DBMS on this issue or loophole.
I can only speak to Oracle, I know nothing of MySQL.
In Oracle, this situation is known as mutation. Oracle will not spiral into an endless loop. It will detect the condition, and raise an ORA-04091 error.
That is:
ORA-04091: table XXXX is mutating, trigger/function may not see it
The standard solution is to define a package with three functions and a package level array. The three functions are as follows:
initialize - this will only zero out the array.
save_row - this will save the id of the current row (uk or pk) into the arrray.
process_rows - this will go through the array, and actually do the trigger action for each row.
Now, define some trigger actions:
statement level BEFORE: call initialize
row level BEFORE or AFTER: call save_row
statement level AFTER: call process_rows
In this way, Oracle can avoid mutation, and your trigger will work.
More details and some sample code can be found here:
https://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551198119097816936
You can only insert a record in same table if you are using instead of trigger. In all other cases you can only modify the record being inserted.
I hope this answers your quest.
you can create trigger in mysql DBMS.
check below link for create insert trigger syntex
http://www.techonthenet.com/oracle/triggers/after_insert.php

SQL Server : track table inserts

I have a table which get new data inserted every minute or so. According to the source code I have here, it is only done in one class which is not used anymore.
Is there any way to trace the inserts? What I mean is to see which queries they were inserted by, who sent those queries etc. As much info as possible.
I have tried several ways myself (e.g.sp_who2 'Active' stored procedure) without any success. I also have access to the machine running the SQL server and to the transaction backup files (.trn files) but have no idea how to open those files.
Add trigger to the table which follows inserts and insert to other table these variables:
getdate(),
host_name(),
App_Name(),
suser_sname()
Seems to me that this is enough
The trigger looks like this:
CREATE TRIGGER YourTrigger On YourTable
AFTER INSERT
AS
SET NOCOUNT ON;
INSERT logtable
SELECT APP_NAME(), HOST_NAME(), SUSER_SNAME(), GETDATE(), * FROM INSERTED
GO
OR
you can use Sql Server Profiler for catching the queries - it may be more flexible
You may use sp_depends like this:
sp_depends tablename
This only states information in the same database but it might say what you need!

Is it possible to add a check constraint that calls a user defined function in a different database?

I'm trying to add a user defined function that actually calls the SQL# CLR function RegEx_IsMatch to a column, but I get this error:
A user-defined function name cannot be prefixed with a database name in this context.
But if the function is in a different db, I'm not sure how to do this.
You shouldn't need to do this in a CHECK CONSTRAINT. An AFTER INSERT, UPDATE Trigger should be able to provide the same functionality as the CHECK CONSTRAINT. You just need to cancel the INSERT or UPDATE operation if the desired condition is (or is not) met. And this is easily done simply by issuing a ROLLBACK, which works due to Triggers existing within the transaction that is the DML statement itself. Hence, just do something along the lines of:
CREATE TRIGGER dbo.trCheckSomeField
ON dbo.SomeTable
AFTER INSERT, UPDATE
AS
SET NOCOUNT ON;
IF (EXISTS(
SELECT *
FROM Inserted ins
WHERE Utility.SQL#.RegEx_IsMatch(ins.SomeField, ...) = 0
)
)
BEGIN;
ROLLBACK TRAN;
RAISERROR('Your data suck!', 16, 1);
RETURN;
END;
Never tried it, but maybe you can create a helper function in the same DB which in turn calls into the other DB?
This may however fail because check constraints are supposed to be determinstic AFAIR, and calls into other databases aren't deterministic. In general it doesn't seem like a good idea to call into another DB, even if it is only for a regex check. Why not add the CLR assembly to this DB as well?

MySQL Triggers - AFTER INSERT trigger + UDF sys_exec() issue

Problem: I've got a table which holds certain records. After the insert has been done, I want to call an external program (php script) via MySQL's sys_* UDFs.
Now, the issue - the trigger I have passes the ID of the record to the script.
When I try to pull the data out via the script, I get 0 rows.
During my own testing, I came to a conclusion that the trigger invokes the php script and passes the parameters BEFORE the actual insert occured, thus I get no records for given ID.
I've tested this on MySQL 5.0.75 and 5.1.41 (Ubuntu OS).
I can confirm that parameters get passed to the script before actual insert happens because I've added sleep(2); to my php script and I've gotten the data correctly.
Without sleep(); statement, I'm receiving 0 records for given ID.
My question is - how to fix this problem without having to hardcode some sort of delay within the php script?
I don't have the liberty of assuming that 2 seconds (or 10 seconds) will be sufficient delay, so I want everything to flow "naturally", when one command finishes - the other gets executed.
I assumed that if the trigger is of type AFTER INSERT, everything within the body of the trigger will get executed after MySQL actually inserts the data.
Table layout:
CREATE TABLE test (
id int not null auto_increment PRIMARY KEY,
random_data varchar(255) not null
);
Trigger layout:
DELIMITER $$
CREATE TRIGGER `test_after_insert` AFTER INSERT ON `test`
FOR EACH ROW BEGIN
SET #exec_var = sys_exec(CONCAT('php /var/www/xyz/servers/dispatcher.php ', NEW.id));
END;
$$
DELIMITER ;
Disclaimer: I know the security issues when using sys_exec function, my problem is that the MySQL doesn't insert FIRST and THEN call the script with necessary parameters.
If anyone can shed some light on how to fix this or has a different approach that doesn't involve SELECT INTO OUTFILE and using FAM - I'd be very grateful. Thanks in advance.
Even if you use an AFTER trigger, the row isn't committed yet. But sys_exec() doesn't return until the php script exits, so the AFTER trigger can't complete, therefore you can't commit the INSERT either.
This is by design. After all, you may do more operations within the same transaction, or you may roll back the transaction. That's the problem with invoking external processes from a trigger: external processes can't see data within the scope of the transaction in the database.
You shouldn't do this task with a trigger. At best, you should use the trigger to set a "flag" column and then write an external process to look for rows with the flag set and then invoke that PHP script. That way only rows that have successfully been inserted AND committed will be processed.
If I understand it clearly, you insert a row in your DB. That invoke a trigger that launch an external command written in PHP. That command queries in its turn the same DB by using the id of the inserted row?
I don't think this is a problem of "delay".
The real "problem" is your initial insert and you external command connect to the same DB on two different sessions -- probably in two different transactions (depending your database engine and your transaction isolation level).
I assume, when the trigger in invoked the row insert is not yet committed to the DB. So the external command still see the DB as it was before.
BTW, if the above explanation is quite speculative -- what is more evident to me is that you should probably think about a different design than trying to made that work as it is.

Is it possible a trigger on a select statement with MySQL?

I know that triggers can be used on insert, update and delete, but what about a trigger (or sort of) on a select statement. I want to use a trigger to insert data on a table B when it is selected an existent record on a table A, it could be possible?.
Thanks in advance.
You should design your application so that database access occurs only through certain methods, and in those methods, add the monitoring you need.
Not exactly a trigger, but you can:
CREATE FUNCTION myFunc(...) BEGIN INSERT INTO myTable VALUES(...) END;
And then
SELECT myFunc(...), ... FROM otherTable WHERE id = 1;
Not an elegant solution, though.
It is not possible in the database itself.
However there are monitoring/instrumentation products for databases (e.g. for Sybase - not sure about MySQL) which track every query executed by the server, and can do anything based on that - usually store the query log into a data warehouse for later analysis, but they can just as well insert a record into table B for you, I would guess.
You can write an application which will be monitoring the query log and doing something when a select occurs. A pretty crude way to solve the problem though...