开发者

My database query keeps setting all columns to the same value in MySQL

Here is my update method for Kohana 3.

public function update($type, $id, $updates) {
        $info = $this->getInfo($type);
        $dbTable = $info['table'];

        $updatesKeysToValues = array();

        var_dump($updates);

        foreach($updates as $key => $value) {
            // if the value is null or the key isnt set for this, don't update!
            if ($value === null OR ! isset($info['columnsToUpdateData'][$key])) continue;
            $updatesKeyToValues[] = "`$key` = :$key";

        }

        $updatesKeyToValues = implode(', ', $updatesKeyToValues);

        $query = 'UPDATE `' . $dbTable . '` SET ' . $updatesKeyToValues . ' WHERE id = :id LIMIT 1' ; 

        echo $query;

        $dbQuery = DB::query(Database::UPDATE, $query);

        foreach($updates as $key => $value) {
                echo "$key === $value\n<br>";
                $dbQuery->bind(':' . $key, $value);
         }

        $success = $dbQuery->bind(':id', $id)    
                        ->execute();    

        var_dump($success);

    }

During every var_dump() and echo the data is fine. There is nothing to suggest why this is happening.

Essentially what I am doing is getting the data for this table from the config, building a query string with named params, looping and defining the named params and then executing. Instead of working, I end up with all fields the same (seems to be whatever was the last array value).

I can't seem to figure it out, can you? Many thanks for your time.

UPDATE

I just had a thought, are underscores valid in param names in a query?

ANOTHER UPDATE

Here is the output of the echo $query

UPDATE `personnel` SET `first_name` = :first_name, `last_name` = :last_name, `email` = :email WHERE id = :id LIMIT 1

I also cooked up that method of binding multiple params to the query too. I've never done it in a loop before, but I assumed it would work. In Kohana 2.x, I'd always used $bindings[] = 'tom@jones.com' etc, but the new Kohana doesn't accept a开发者_如何学编程n array as far as I can tell.

FINAL UPDATE

Thanks everyone, I think it is being passed by reference. I got around it by setting it to $updates[$key]

Looks like I could of also used the param() method instead of bind. View source


the bind function is using a reference the your $value

public function bind($param, & $var)
{
 // Bind a value to a variable
    $this->_parameters[$param] =& $var;
    return $this;
}

Something that seems to work in a test

$a = array("a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6);
$v = array();
$t = array();
$i = 0;
foreach($a as $key => $value)
{
    $t[] = $key;
    $v[] = &$t[$i];
    $i++;
}

print_r($v);

results are here: http://www.antiyes.com/test/hmm.php

do you think the $key & $value in

$dbQuery->bind(':' . $key, $value);

are being passed by reference ?

below didnt work


this line

$updatesKeyToValues[] = "`$key` = :$key";

could you change it to:

$updatesKeyToValues[] = "`" . $key ."` = " . ":" . $key;

and see what happens?


I don't know what data access layer you're using here, but I'm guessing this:

foreach($updates as $key => $value) {
    $dbQuery->bind(':' . $key, $value);
}

could be doing something really deceptive: taking the parameters by reference.

So what would happen would be that since $value is a real variable, the bind() function receives a reference to it and remembers that it's this variable — not the variable's current value — that it will bind to the given parameter. Then you go the next time round the foreach loop, and we've got the classic loop problem of C-like languages: you're not getting a new instance of $key and $value, you're actually changing the existing variables you already had, just like for the standard for ($i= 0... loop.

So, when it comes time to do the query, what's parameter :a? It's the current value of $value, the last one in the loop. What's parameter :b? The same. And so on.

I know some PHP parameterisation interfaces do this (mysqli, I think?), but in general receiving parameters by reference is IMO extremely likely to lead to unwanted behaviours like this, and I certainly consider it totally inappropriate for a parameter-binding interface like this.

ETA: just looked at query.php in the link you posted to John's comment. Yes. Sigh. It's taking parameters by reference. How awful.


Why don't you use the query-builder?

This is just a quick guess, as I haven't had enough time to play with the query-builder myself.

$query = DB::update();
$query->set($updates);
// etc

Check out the source and I'm sure you could figure out how the query-builder works :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜