PDO "Integrity constraint violation - Duplicate entry", but no duplicates in table

a coder

I'm getting "Duplicate entry" on an insert query that worked fine with the old mysqli functions. Once I converted to PDO, the same insert statement breaks.

Here's the sample SQL data

CREATE TABLE IF NOT EXISTS `lookup_codes` (
  `id` int(3) NOT NULL,
  `code` varchar(10) NOT NULL,
  PRIMARY KEY (`id`,`code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `lookup_codes` (`id`, `code`) VALUES
(1, 'AR'),
(1, 'CN'),
(1, 'OA'),
(4, 'AR'),
(4, 'OA');

And here is the example php/pdo code. (This is not a code critique request - just trying to boil down a problem to a simple example, do not use this code in production, yada yada).

    // posted data from user
    $id = 2;
    $arr_codes = array('AR','CN');

    // make sure existing rows do not exist
    try
    {
        $q = "SELECT COUNT(*) FROM lookup_codes WHERE id=:id";
        if ($dbg) { echo "<p>SELECT COUNT(*) FROM lookup_codes WHERE id=$id<br>";}
        $stmt = $dbx_pdo->prepare($q);
        $stmt->bindParam(':id', $id, PDO::PARAM_INT);
        $stmt->execute();
        list($count_rows) = $stmt->fetch(PDO::FETCH_NUM); $stmt->closeCursor();

        if ($count_rows>0)
        {
            try
            {
                $q = "DELETE FROM lookup_codes WHERE id=:id";
                if ($dbg) { echo "<p>DELETE FROM lookup_codes WHERE id=$id<br>";}
                $stmt = $dbx_pdo->prepare($q);
                $stmt->bindParam(':id', $id, PDO::PARAM_INT);
                $stmt->execute();
                $stmt->closeCursor();

            } catch(PDOException $err) {
                echo $err->getMessage());
                exit;
            }

        }

    } catch(PDOException $err) {
        echo $err->getMessage());
        exit;
    }



    // set up prepared statement based on posted data
    foreach ($arr_codes as $code)
    {
        $arr_ip[] = array(
            'id'    => $id,
            'code'  => $code,
        );
    }
    $txt_prepared = join(',', array_fill(0, count($arr_ip), '( ?, ?)'));

    // try inserting
    try 
    {
        $q = "INSERT INTO lookup_codes (id, code) VALUES $txt_prepared";
        $stmt = $dbx_pdo->prepare($q);
        $cb = 1;
        foreach ($arr_ip as $rip)
        {
            $id = $rip['id'];
            $code   = $rip['code'];

            $stmt->bindParam($cb++, $id, PDO::PARAM_INT);
            $stmt->bindParam($cb++, $code, PDO::PARAM_STR);
            if ($dbg) { echo "<b>Binding</b> ($id, $code)<br>";}
        }
        $stmt->execute();
        $stmt->closeCursor();

    } catch(PDOException $err) {
        echo $err->getMessage());
        exit;
    }   

That's all there is on my test script. No header or meta redirects.. just a single run of code here.

The example above results in:

Error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-CN' for key 'PRIMARY'

Note that it reports back duplicate on the second submitted code.

The same INSERT works just fine when using mysqli_query(). There are no errors written to the error log.

What is going on here?

Jonathan Kuhn

The problem is the way you are binding on your insert query. You need to change $stmt->bindParam to $stmt->bindValue. bindParam takes a variable by reference so on each iteration of your loop as you change the value of $id and $code you are changing the value that was bound. bindValue will take a copy of the value from the variable and bind that instead.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related