8

I'm having an issue with PDO Prepared statements, where if you need to use the same bind variable multiple times, the query won't validate.

Example:

$params = array (
    ':status' => $status,
    ':userid' => $_SESSION['userid']
);

$stmt = $pdo->prepare ('
    INSERT INTO 
        tableName
        ( userId, status )
        VALUES
        ( :userid, ":status" )
        ON DUPLICATE KEY UPDATE
            status = ":status"
');

if ( ! $stmt->execute ( $params ))
{
    print_r( $stmt->errorInfo ());
}

EDIT: The values of the $params are:
Array ( [:status] => PAID [:userid] => 111 )

EDIT 2:
I've noticed that instead of the original values, instead of userid, 0 is inserted, and instead of status an empty string is inserted.

7
  • And what does the errorInfo display? Commented Aug 20, 2012 at 10:24
  • You can rewrite your query like INSERT INTO tableName ( userId, status ) VALUES ( ?, "?" ) ON DUPLICATE KEY UPDATE status = "?" and your $params will be like: array($_SESSION['userid'], $status, $status). And it's interesting what's the output of errorInfo. Commented Aug 20, 2012 at 10:28
  • It passes the query with no error, but inserts NULL for :status and :userid. Commented Aug 20, 2012 at 10:28
  • 1
    @Kao Make sure that $status and $_SESSION['userid'] are not nulls Commented Aug 20, 2012 at 10:30
  • Does your $params array hold the values you think it holds? var_dump ($params); Commented Aug 20, 2012 at 10:35

4 Answers 4

9

Problem was the quotes around the :status. Removed quotes and all is good.

Sign up to request clarification or add additional context in comments.

2 Comments

Also be aware of case sensitivity.
Still doesn't seem to work when PDO::ATTR_EMULATE_PREPARES is false, can't find any docs on that
3

Your array keys don't need to contain a colon. The colon is purely for PDO to know that what follows is a named parameter.

$params = array (
    ':status' => $status,
    ':userid' => $_SESSION['userid']
);

should be

$params = array (
    'status' => $status,
    'userid' => $_SESSION['userid']
);

4 Comments

Yeah, I just noticed that after posting my initial comment. Funny how little stuff like that is so easy to miss.
I've used it with the ':status' before, with great success. This is the only times it's not working. Also, according to the Docs on PDO, they use it with the :. Also by doing this it won't be able to differ from a table name or a variable.
That's weird, never noticed that in the docs before. I've always just used it without colons in the array keys and it works fine. I guess in that case it's back to the original question, does the array you're passing to execute actually hold the values you think it holds?
Edited the $params values into the question.
2

You're not calling the bindParam method anywhere, why? Just before you invoke execute, try adding

$stmt->bindParam(':userid', $_SESSION['userid'], PDO::PARAM_INT);
$stmt->bindParam(':status', $status, PDO::PARAM_STR);

And then just call $stmt->execute(); see how that works for you. Also turn your error messages up to full, and after instantiating your PDO instance, add this $db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); to ensure errors are always thrown.

the docs are handy things

2 Comments

Passing an array to execute is equally valid, not using bindParam is not inherently wrong. The bindParam approach is fine, but it's not the root cause of the problem in this case.
I know, but when you encounter difficulties, my first reaction is to go take the safest, admittedly: in the case of php often counter-intuitive, route and see if that fails, then gradually introduce your code that caused the problem, as a bonus: bindParam does allow you to use the PDO::* type constants
2

Works fine for me. E.g.

<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
setup($pdo);

echo 'client version: ', $pdo->getAttribute(PDO::ATTR_CLIENT_VERSION), "\n";
echo 'server version: ', $pdo->getAttribute(PDO::ATTR_SERVER_VERSION), "\n";
echo "before:\n";
foreach( $pdo->query('SELECT * FROM tmpTableName', PDO::FETCH_ASSOC) as $row ) {
    echo join(', ', $row), "\n";
}

$status = 1;
$_SESSION['userid'] = 'foo';

$params = array (
    'status' => $status,
    'userid' => $_SESSION['userid'],
);

$stmt = $pdo->prepare ('
    INSERT INTO 
        tmpTableName
        (userId, status)
    VALUES
        (:userid, :status)
    ON DUPLICATE KEY UPDATE
        status = :status
');

if ( ! $stmt->execute ( $params ))
{
    print_r( $stmt->errorInfo ());
}

echo "after:\n";
foreach( $pdo->query('SELECT * FROM tmpTableName', PDO::FETCH_ASSOC) as $row ) {
    echo join(', ', $row), "\n";
}

function setup($pdo) {
    $pdo->exec('
        CREATE TEMPORARY TABLE tmpTableName (
            userId varchar(32),
            status int,
            unique key(userId)
        )
    ');
    $pdo->exec("INSERT INTO tmpTableName (userId,status) VALUES ('foo', 0)");
    $pdo->exec("INSERT INTO tmpTableName (userId,status) VALUES ('bar', 0)");
}

prints

client version: mysqlnd 5.0.10 - 20111026 - $Id: b0b3b15c693b7f6aeb3aa66b646fee339f175e39 $
server version: 5.5.25a
before:
foo, 0
bar, 0
after:
foo, 1
bar, 0

on my machine

1 Comment

Just realized it was a few quotes causing the problem.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.