what's wrong with this sql trigger statement - php

I am writing my first sql trigger query.So i am trying to grasp the idea of trigger statement.My plan is to--
1.insert data to a table called 'trigger_table';
2.After insertion ,fetch data from that exact same table and store it to a php variable using PDO;
So i wrote the following trigger statement.And i get this error while executing sql in mysql workbench
ERROR 1415: Not allowed to return a result set from a trigger
SQL Statement:
CREATE TRIGGER `trigger_table_AINS` AFTER INSERT ON trigger_table FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN
SELECT * FROM trigger_table;
END
It would be a great help if anyone guide me towards the right path to accomplish my task.Thanks !
php code:
$db=new PDO("mysql:host=localhost;dbname=trigger",'root','');
$sql="INSERT INTO trigger_table (name,email) VALUES('zami','alzami#gmail.com')";
$conn=$db->prepare($sql);
if($conn->execute()){
$result=$conn->fetchAll(PDO::FETCH_OBJ);
}

Triggers are meant to react to an event to update, modify or delete content. As the error states, they aren't meant to return data.
Per the documentation:
A trigger is a named database object that is associated with a table, and that activates when a particular event occurs for the table. Some uses for triggers are to perform checks of values to be inserted into a table or to perform calculations on values involved in an update.
You may be after a Stored Routine
Stored routines (procedures and functions) are supported in MySQL 5.7. A stored routine is a set of SQL statements that can be stored in the server. Once this has been done, clients don't need to keep reissuing the individual statements but can refer to the stored routine instead.

Related

Do BEFORE UPDATE triggers affect mysqli_insert_id results?

I have a mysql table which has a trigger attached, that logs changes in this table to a second one
CREATE TRIGGER log_table BEFORE UPDATE ON table1
FOR EACH ROW BEGIN
INSERT INTO log_table(filed) VALUES(NEW.field);
END;
//
Now if I perform an INSERT INTO table1 from PHP an call mysqli_insert_id() afterwards.
Would that return the new ID in table1? Or the new ID in log_table?
LAST_INSERT_ID() called after the INSERT statement will return the new ID in table1 (of the INSERT statement), not the one in the log_table (of the trigger).
This is documented in the manual section of LAST_INSERT_ID:
Within the body of a stored routine (procedure or function) or a
trigger, the value of LAST_INSERT_ID() changes the same way as for
statements executed outside the body of these kinds of objects. The
effect of a stored routine or trigger upon the value of
LAST_INSERT_ID() that is seen by following statements depends on the
kind of routine:
If a stored procedure executes statements that change the value of
LAST_INSERT_ID(), the changed value is seen by statements that follow
the procedure call.
For stored functions and triggers that change the value, the value is
restored when the function or trigger ends, so following statements
will not see a changed value.

PDO - getting column count on a prepared statement, is it possible?

I'm trying to refine my database access classes to help at the time of processing form data. What I'm trying to accomplish is this:
add an SQL query to my connection object.
classify the SQL query by its commands and arguments.
use the classification data to automatically add the required attribute to a given form input tag (and, optionally, insert a given or corresponding RegEx for advanced matching).
add a session-driven temporary object holding the form members to check for both completeness and compliancy with a given set of rules or matches.
execute the SQL query once all the given requirements are satisfied.
Then, the way to proceed (in my actual code) is like this:
if (!empty($data = \Helpers\Forms\getData($_POST))) {
if (!empty($rules = \Helpers\Forms\getRules($_POST))) {
if ($data->isCompliant($rules)) {
// rest continues here...
}
}
}
So far, I've got steps 1, 3 and 5 fully completed. I got steps 2 and 4 just partially implemented because I need a way to do a metadata scan on a given prepared SQL query and that's where I'm a bit lost.
According to the PDO manual, the columnCount() method doesn't provide an accurate result until the execute() method is called.
However, the execute method actually executes the query and I don't want to do it because if it's a SELECT query, it would actually be ok but not for a INSERT, DELETE, UPDATE or any other kind of query.
So my question is... is there any way to get the column count for a given SQL query without executing it? Or maybe... is there a way to perform a dummy execution of a given SQL query to obtain this column count value?

SQL Injection within a stored procedure?

I've found somewhere in the code where a string isn't being escaped properly. I've been trying to see if it is exploitable (don't worry, I'll end up escaping it or using prepared statements anyway, this is just for a learning experience).
This is using mysqli->query() function;
The Query is generated in PHP like so:
$Query = "CALL some_proc(".$_SomeID.",'".$_UnescapedString."')";
By inputting $_UnescapedString as test'); DROP TABLE SomeTable; -- I got the query:
CALL some_proc(1, 'test'); DROP TABLE SomeTable; -- ')
This query was successfully run but it seems that it didn't run the second query. I tested this by putting invalid SQL in the second query and got no errors. I assume this means mysqli is smart enough to only execute a single query?
Now my question is, can I somehow inject SQL into the stored procedure itself? Here is the procedure:
BEGIN
SELECT COUNT(*) AS SomeCount
FROM DataTable
WHERE DataTable.SomeID = _SomeID
AND DataTable.SomeValue LIKE CONCAT('%',_UnescapedString,'%');
END
I've tried various SQL such as test','%')-- to see if the query would carry on as normal, but it only changes the stored procedure call, i.e:
CALL some_proc(1, 'test', '%')--');
Is there anyway to get a DROP TABLE command into _UnescapedString?
Disclaimer, I use SQL Server and not mySQL, but assuming the behavior with regards to parameters in stored procedures is the same, and also assuming that _UnescapedString is an input parameter, putting DROP TABLE in the parameter would look like this:
SELECT COUNT(*) AS SomeValue
FROM DataTable
WHERE DataTable.SomeID = _SomeID
AND DataTable.SomeValue LIKE '%DROP TABLE%');
With regards to the query:
CALL some_proc(1, 'test'); DROP TABLE SomeTable; -- ')
Maybe the DROP TABLE command did not execute due to the user account under which you are running having insufficient permissions to execute DDL statements?
Restricting the permissions of the user account being used to access the database from the web server is a way to limit the damage that an SQL Injection attack could cause. However, it won't stop them.

How to log MySQLi querys in a new table

Using PHP5, with the MySQLi class for executing MySQL queries, how can I log each query processed using MySQLi::query in a new table in the currently connected database?
Is it possible to do some extension on the function, like in Java?
If you use version of mysql that supports triggers. Just create a trigger, this way you will not have to pollute code with unnecessary business logic
http://dev.mysql.com/doc/refman/5.0/en/triggers.html
Support for triggers is included beginning with MySQL 5.0.2. So when you deploy your app create triggers at the same time you create tables.
Define a table for your logs
create table querylog (
tm timestamp,
query varchar(4096));
and when you do a query, log the query string in this table
insert into querylog (tm, query)
values(now(), '$query_string')
You can do this either explicit at every query or in a function my_query, you define and call instead of mysqli_query or, as #E_p suggested, in a trigger.

php: mysql_insert_id() issues

Can the php function mysql_insert_id() return no result after processing the INSERT query in mysql db?
Just to clarify. There was a script performing by cron on the production site. It contained a cycle for generating invoices for users. Each iteration consists of a INSERT db query and the mysql_insert_id() operation going right after the query - to fetch the generated invoice number. A set of iterations were performed without fetching the last inserted number.
Can it be caused by high db server load or by some other reasons that are not linked to the problem at the php code site?
Any help would be appreciated!
Offhand, I can think of a few cases where MySQL wouldn't return the ID:
The table you're inserting into doesn't have an AUTO_INCREMENTed primary key.
You're inserting multiple rows at once.
You're calling mysql_insert_id() from a different connection than the INSERT query was executed.
The INSERT query didn't succeed (for instance, it encountered a deadlock). Make sure you are checking the return value from mysql_query(), then use mysql_errno() and mysql_error().
MySQL docs have a full list of conditions and details on how this function works.
Of course, it's also possible there is a bug in MySQL, which would depend on which version of MySQL you are using.
If you're running the commands through a shell script, and run them both separately as in;
mysql -e "insert into table ( field1 ) values ( 'val1' );" "database"
lastId=`mysql -e "select last_insert_id();" "database"`
Then that won't work as the second call makes a new connection to the server. You need to do something like the following, as it is all done within a single database call / connection;
lastId=`mysql -e "
insert into table ( field1 ) values ( 'val1' );
select last_insert_id();
" "database"`
You'll need to look up the extra parameters required for the MySQL command to remove formatting and header row - I'm afraid I can't remember them off the top of my head!

Categories