111

I'm using PDO to insert a record (mysql and php)

$stmt->bindParam(':field1', $field1, PDO::PARAM_STR);
$stmt->bindParam(':field2', $field2, PDO::PARAM_STR);
$stmt->execute();

Is there a way to know if it inserted successfully, for example if the record was not inserted because it was a duplicate?

Edit: of course I can look at the database, but I mean programmatic feedback.

Chris
  • 8,736
  • 18
  • 49
  • 56

7 Answers7

163

PDOStatement->execute() returns true on success. There is also PDOStatement->errorCode() which you can check for errors.

shmeeps
  • 7,725
  • 2
  • 27
  • 35
Ólafur Waage
  • 68,817
  • 22
  • 142
  • 198
  • 1
    How do you look at the execute() value? – Mallow Jun 02 '11 at 21:53
  • You store it in a variable? It is either true or false. – Ólafur Waage Jun 02 '11 at 21:57
  • Something like this? $stmt -> execute(); if($stmt){//true} if(!$stmt){//false} – Mallow Jun 02 '11 at 22:05
  • 30
    No more like this, $value = $stmt->execute(); if($value){//true}else{//false} – Ólafur Waage Jun 03 '11 at 08:40
  • 25
    Or you can just do `if ($stmt->execute()) { //true }` – Gavin Jan 12 '14 at 21:26
  • 2
    Is `PDOStatement->execute()` and `PDOStatement->errorCode()` totally consistent with each other? Is there any circumstances when `PDOStatement->errorCode()` has something but `PDOStatement->execute()` returns true? Or when `PDOStatement->execute()` returns false but `PDOStatement->errorCode()` has nothing? – datasn.io Jan 20 '15 at 07:08
  • This does not ensure that an insert ever happened! Only that there was not an error. It will work if rejected as a duplicate, but not if not inserted based on a WHERE or JOIN. – user1032531 Feb 09 '16 at 20:10
  • What about `query()` function? like this `$db->query("INSERT ..")`, well will it return *true* on success too? – Martin AJ Jul 04 '16 at 15:09
  • @MartinAJ although way too late: If you're interested in the affected rows, you should use `$db->exec("Insert...")`, see http://php.net/manual/en/pdo.exec.php – Jakumi Sep 06 '16 at 07:48
  • 2
    But INSERT IGNORE would also return true even if no new record was inserted – Pringles Jul 20 '17 at 13:41
  • 3
    How this is the accepted answer, "Your common sense" 's Answer is correct, Insert usually throws a fatal error, How can you handle the fatal error with if() Statement? – beginner Sep 27 '17 at 06:34
31

Given that most recommended error mode for PDO is ERRMODE_EXCEPTION, no direct execute() result verification will ever work. As the code execution won't even reach the condition offered in other answers.

So, there are three possible scenarios to handle the query execution result in PDO:

  1. To tell the success, no verification is needed. Just keep with your program flow.
  2. To handle the unexpected error, keep with the same - no immediate handling code is needed. An exception will be thrown in case of a database error, and it will bubble up to the site-wide error handler that eventually will result in a common 500 error page.
  3. To handle the expected error, like a duplicate primary key, and if you have a certain scenario to handle this particular error, then use a try..catch operator.

For a regular PHP user it sounds a bit alien - how's that, not to verify the direct result of the operation? - but this is exactly how exceptions work - you check the error somewhere else. Once for all. Extremely convenient.

So, in a nutshell: in a regular code you don't need any error handling at all. Just keep your code as is:

$stmt->bindParam(':field1', $field1, PDO::PARAM_STR);
$stmt->bindParam(':field2', $field2, PDO::PARAM_STR);
$stmt->execute();
echo "Success!"; // whatever

On success it will tell you so, on error it will show you the regular error page that your application is showing for such an occasion.

Only in case you have a handling scenario other than just reporting the error, put your insert statement in a try..catch operator, check whether it was the error you expected and handle it; or - if the error was any different - re-throw the exception, to make it possible to be handled by the site-wide error handler usual way. Below is the example code from my article on error handling with PDO:

try {
     $pdo->prepare("INSERT INTO users VALUES (NULL,?,?,?,?)")->execute($data);
} catch (PDOException $e) {
    if ($e->getCode() == 1062) {
        // Take some action if there is a key constraint violation, i.e. duplicate name
    } else {
        throw $e;
    }
}
echo "Success!";

In the code above we are checking for the particular error to take some action and re-throwing the exception for the any other error (no such table for example) which will be reported to a programmer.

While again - just to tell a user something like "Your insert was successful" no condition is ever needed.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • 2
    What's the meaning of "Success"? Is that mean a new row inserted, or that means there isn't any error? – Martin AJ Jul 04 '16 at 14:54
  • For the INSERT query it's pretty much the same. – Your Common Sense Jul 04 '16 at 15:14
  • You are right .. Just may you please tell me what about `query()` function? Can I use try-catch for `query()` instead of `prepared()->execute()` ? – Martin AJ Jul 04 '16 at 15:18
  • 3
    You should never use query() for inserts in the first place. Insert means there is input and inpout means it should be prepared. – Your Common Sense Jul 04 '16 at 15:25
  • Yeah I see what you're saying. But in this case, all inserted values are made by the application *(they are some random string)*. So I think no need to pass them as prepared statement. – Martin AJ Jul 04 '16 at 15:28
  • You better don't make this decision conditional. Just keep it prepared all the way. Besides, if you need to insert more than 1 row you may benefit from multiple execution. – Your Common Sense Jul 04 '16 at 15:31
  • Agreed .. *multiple execution* is a great advantage of `execute()` function. – Martin AJ Jul 04 '16 at 16:41
  • Did you suggest suggest using an Exception to handle an *expected* error...? – Chuck Le Butt Feb 22 '17 at 10:54
  • @ChuckLeButt for clarity, I did suggest to *catch* an exception in such a case. – Your Common Sense Feb 22 '17 at 10:58
  • If it's expected, it's not an exception. Your answer is very badly worded and could lead to all sorts of misunderstandings from beginners -- the very thing you hate on SO. – Chuck Le Butt Feb 22 '17 at 11:23
  • @ChuckLeButt feel free to reword it, collaborative efforts are encouraged here. though I cannot think any other term. You catch an error which you expect and don't otherwise. What's so complex in this statement? – Your Common Sense Feb 22 '17 at 11:42
  • I was always taught that Exceptions are for exceptional circumstances, and for beginners that's a good rule of thumb. Using try ... catch for logic can quickly get out of hand. That said, it seems like a good use in this situation. – Chuck Le Butt Feb 22 '17 at 15:43
  • 1
    Using MySQL, I had to check if $e->errorInfo[1] == 1062 to verify that the insert failed, because $e->getCode() is always 23000. – tronman Mar 28 '17 at 15:26
9

Try looking at the return value of execute, which is TRUE on success, and FALSE on failure.

Dominic Rodger
  • 97,747
  • 36
  • 197
  • 212
9

If an update query executes with values that match the current database record then $stmt->rowCount() will return 0 for no rows were affected. If you have an if( rowCount() == 1 ) to test for success you will think the updated failed when it did not fail but the values were already in the database so nothing change.

$stmt->execute();
if( $stmt ) return "success";

This did not work for me when I tried to update a record with a unique key field that was violated. The query returned success but another query returns the old field value.

samayo
  • 16,163
  • 12
  • 91
  • 106
dan
  • 99
  • 1
  • 2
  • 4
    If you NEED the record to be inserted, best way is to check like this ............................. ....................... `if($stmt->execute() && ($stmt->rowCount()>0))` – jave.web Dec 17 '15 at 12:46
8

You can test the rowcount

    $sqlStatement->execute( ...);
    if ($sqlStatement->rowCount() > 0)
    {
        return true;
    }
crafter
  • 6,246
  • 1
  • 34
  • 46
  • A reference back to the docs is always helpful @YourCommonSense. It says " this behaviour is not guaranteed for all databases and should not be relied on for portable applications. " but is limited to select firstly, and secondly supported for mysql, which is the subject of this post. – crafter Oct 23 '17 at 07:34
  • 1
    @crafter Correct. It says that rowCount() can be unrelyable for `SELECT` queries (and even there, the docs speaks about *multiple* queries). It says nothing about `DELETE`, `INSERT` or `UPDATE`, which seem to be fine to work (the question was about an `INSERT` query). However, I'm new to PDO and if I'm wrong and someone has another references, please write them here. I'm interested to see if there are real disadvantages for the 3 commands above. – StanE Nov 11 '17 at 18:04
  • Apart from inconsistency of its own, this answer is also conceptually wrong, for the same reason as the accepted answer. – Your Common Sense Apr 20 '22 at 12:08
1

PDOStatement->execute() can throw an exception

so what you can do is

try
{
PDOStatement->execute();
//record inserted
}
catch(Exception $e)
{
//Some error occured. (i.e. violation of constraints)
}
Sumit P Makwana
  • 317
  • 5
  • 17
1

Use id as primary key with auto increment

$stmt->execute();
$insertid = $conn->lastInsertId();

incremental id is always bigger than zero even on first record so that means it will always return a true value for id coz bigger than zero means true in PHP

if ($insertid)
   echo "record inserted successfully";
else
   echo "record insertion failed";
jumper rbk
  • 414
  • 4
  • 18
  • What if I don't need an auto incremented field in my table? – Your Common Sense Oct 16 '16 at 04:13
  • Who dun? you? with the RESTFul API that is being used so widely auto increment id is like compulsory. – jumper rbk Oct 16 '16 at 04:41
  • Why would someone not have a primary and auto increment or any other sequence column? If verification method needed, add any sequential column. If this solution not for You don't add it. It's a fine one to me, I always use some sequential and auto-increment column, so I always have a way to test if my query was successful. – Samuel Ramzan Jan 27 '20 at 18:49