Keep checking for errors in queries - php

I'm a bit obsessed now. I'm writing a PHP-MYSQL web application, using PDO, that have to execute a lot of queries. Actually, every time i execute a query, i also check if that query gone bad or good. But recently i thought that there's no reason for it, and that's it is a wast of line to keep checking for an error.
Why should a query go wrong when your database connection is established and you are sure that your database is fine and has all the needed table and columns?

You're absolutely right and you're following the correct way.
In correct circumstances there should be no invalid queries at all. Each query should be valid with any possible input value.
But something still can happen:
You can lose the connection during the query
Table can be broken
...
So I offer you to change PDO mode to throw exception on errors and write one global handler which will catch this kind of errors and output some kind of sorry-page (+ add a line to a log file with some details)

Related

Multiple UPDATEs and INSERTs with PHP/MySQLi

I need to reconcile between an existing set of tables and new/changed information that I get on a regular basis, and so have a set of ~30 UPDATE/INSERT operations that has to run every time. Since 'mysql_query' is now deprecated, and I'd prefer not to recode everything in OO, is there a reasonable procedural way to run all of these in sequence without having to call 'mysqli_free_result()' after every single one?
Just for the record, I've tried running them as a set of mysqli_query statements without mysqli_free_result(), and it's a mess: some of the operations go through while others fail silently. Frankly, a shell script with a bunch of 'mysql -e' commands in it was much more reliable... but this needs to be a Web-driven app, so that's not viable anymore.
Your assumptions are wrong.
mysqli_query's behavior is similar to one of mysql_query and you don't need any other modifications. neither mysqli_free_result() is related to your problem.
the only meaningful part of your question is queries that fails silently. To make them fail noisily, just tell mysqli to do so. add this line before mysqli_connect
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
and the first query that fails will tell you the reason.
but in general, there is not a single problem with running multiple UPDATE and INSERT queries using mysqli_query().

How to debug AJAX (PHP) code that calls SQL statements?

I'm not sure if this is a duplicate of another question, but I have a small PHP file that calls some SQL INSERT and DELETE for an image tagging system. Most of the time both insertions and deletes work, but on some occasions the insertions don't work.
Is there a way to view why the SQL statements failed to execute, something similar to when you use SQL functions in Python or Java, and if it fails, it tells you why (example: duplicate key insertion, unterminated quote etc...)?
There are two things I can think of off the top of my head, and one thing that I stole from amitchhajer:
pg_last_error will tell you the last error in your session. This is awesome for obvious reasons, and you're going to want to log the error to a text file on disk in case the issue is something like the DB going down. If you try to store the error in the DB, you might have some HILARIOUS* hi-jinks in the process of figuring out why.
Log every query to this text file, even the successful ones. Find out if the issue affects identical operations (an issue with your DB or connection, again) or certain queries every time (issue with your app.)
If you have access to the guts of your server (or your shared hosting is good,) enable and examine the database's query log. This won't help if there's a network issue between the app and server, though.
But if I had to guess, I would imagine that when the app fails it's getting weird input. Nine times out of ten the input isn't getting escaped properly or - since you're using PHP, which murders variables as a matter of routine during type conversions - it's being set to FALSE or NULL or something and the system is generating a broken query like INSERT INTO wizards (hats, cloaks, spell_count) VALUES ('Wizard Hat', 'Robes', );
*not actually hilarious
Start monitoring your SQL queries by starting the log. There you can look what all queries are fired and errors if any.
This tutorial to start the logger will help.
Depending on which API your PHP file uses (let's hope it's PDO ;) you could check for errors in your current transaction with s.th. like
$naughtyPdoStatement->execute();
if ($naughtyPdoStatement->errorCode() != '00000')
DebuggerOfChoice::log( implode (' ', $naughtyPdoStatement->errorInfo() );
When using the legacy-APIs there's equivalents like mysql_errno, mysql_error, pg_last_error, etc... which should enable to do the same. DebuggerOfChoice::Log of course can be whatever log function you'd like to utilise

mysql surpress dupe key error

When i need to know if something in unique before it gets inserted. i usually just attempt to insert it and then if it fails, check if the mysql_errno() is 1062. If it is i know it failed as a duplicate key and i can do whatever i need to do.
The most common place for this is in a user table. I set the email as unique as thats the "username" for logging in. Instead of running additional queries to check uniqueness when processing registration forms, i just compile the query, execute it and check for the 1062 error number. If it fails with 1062 i tell the user nicely that the email is registered and all is good.
However i recently set up a very basic MITM sql query function which gives myself and other developers on the system access to query times, a log of all the sql queries at the bottom of the page, and most importantly, a function which establishes the mysql connection to the correct database on demand (rather than having to do the connect and pass link identifiers manually).
In the sql error query log this function creates on disk, is all my duplicate entries. This obviously doesn't look good to other people seeing errors (even though there handled and expected). Is there a way of surpressing errors somehow for this but still being able to check the mysql_errno() ?
Whilst doing a bit of housework on my account here at SO, I thought it best to answer this with my findings so i can close it. This is basically a conclusion from my last comment above.
If you (like me) use certain error codes in mysql in your application to reduce validation queries or code (duplicate key being the most common i find). The only way to stop an error being thrown is to catch the error inside mysql and handle it. I wont go into the how-to here but a good place to get started is:
http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html
Note: just for the new dev's out there, also dont forget to check out "ON DUPLICATE KEY" (google it). It was something blindly suggested to me elsewhere. It doesn't fit in this example but i've used it for year's to save checking for duplicate records before insertion (it does not return a failure on duplicate entries, so its only good if you were thinking of using a duplicate error handler to instead perform an update... hence finding your way here)

How do I use MySQL transactions in PHP?

I'm sorry, this is a very general question but I will try to narrow it down.
I'm new to this whole transaction thing in MySQL/PHP but it seems pretty simple. I'm just using mysql not mysqli or PDO. I have a script that seems to be rolling back some queries but not others. This is uncharted territory for me so I have no idea what is going on.
I start the transaction with mysql_query('START TRANSACTION;'), which I understand disables autocommit at the same time. Then I have a lot of complex code and whenever I do a query it is something like this mysql_query($sql) or $error = "Oh noes!". Then periodically I have a function called error_check() which checks if $error is not empty and if it isn't I do mysql_query('ROLLBACK;') and die($error). Later on in the code I have mysql_query('COMMIT;'). But if I do two queries and then purposely throw an error, I mean just set $error = something, it looks like the first query rolls back but the second one doesn't.
What could be going wrong? Are there some gotchas with transactions I don't know about? I don't have a good understanding of how these transactions start and stop especially when you mix PHP into it...
EDIT:
My example was overly simplified I actually have at least two transactions doing INSERT, UPDATE or DELETE on separate tables. But before I execute each of those statements I backup the rows in corresponding "history" tables to allow undoing. It looks like the manipulation of the main tables gets rolled back but entries in the history tables remain.
EDIT2:
Doh! As I finished typing the previous edit it dawned on me...there must be something wrong with those particular tables...for some reason they were all set as MyISAM.
Note to self: Make sure all the tables use transaction-supporting engines. Dummy.
I'd recommend using the mysqli or PDO functions rather than mysql, as they offer some worthwhile improvements—especially the use of prepared statements.
Without seeing your code, it is difficult to determine where the problem lies. Given that you say your code is complex, it is likely that the problem lies with your code rather than MySQL transactions.
Have you tried creating some standalone test scripts? Perhaps you could isolate the SQL statements from your application, and create a simple script which simply runs them in series. If that works, you have narrowed down the source of the problem. You can echo the SQL statements from your application to get the running order.
You could also try testing the same sequence of SQL statements from the MySQL client, or through PHPMyAdmin.
Are your history tables in the same database?
Mysql transactions only work using the mysqli API (not the classic methods). I have been using transactions. All I do is deactivate autocommit and run my SQL statements.
$mysqli->autocommit(FALSE);
SELECT, INSERT, DELETE all are supported. as long as Im using the same mysqli handle to call these statements, they are within the transaction wrapper. nobody outside (not using the same mysqli handle) will see any data that you write/delete using INSERT/DELETE as long as the transaction is still open. So its critical you make sure every SQL statement is fired with that handle. Once the transaction is committed, data is made available to other db connections.
$mysqli->commit();

Can I prevent long queries in PDO?

Is there any way to make a PDO object throw an error if a query takes too long? I have tried PDO::ATTR_TIMEOUT to no effect.
I'd like a way to have a query throw an error if it is running for longer than a certain amount of time. This is not something that I can do in the database, ie, no maintenance jobs running on the db or anything.
I'm not sure what you mean by "This is not something that I can do in the database", but I would suggest that you have the person administering the database set up an Oracle profile to limit this on the database side. There are parameters such as CPU_PER_CALL and LOGICAL_READS_PER_CALL that can cap queries. The profile can be applied only to specific users if desired.
I'm not sure if you can do this in Oracle but I'm going to say it's not possible to do this within PHP since PHP is issuing the query to Oracle to be run and then is waiting for Oracle's response back. It may be possible to modify the PDO extension to support this, but you would need to modify the extension code (the actual C code) as there probably isn't any way to do this in just PHP.

Categories