6

I need to update a database and I use PDO's execute() method by giving it an array as parameters.

The idea is that it gives me an error when trying to insert a NULL value...

Here's an example of query/parameters sent:

Generated query:

UPDATE table SET name=?, id_extra1=?, id_extra2=? WHERE id_something=?

Array of parameters:

array (size=8)
  'name' => string 'testing' (length=6)
  'id_extra1' => string '2' (length=1)
  'id_extra2' => null
  'id_something' => string '1958' (length=4)

So the NULL value is for id_extra2

In the code for id_extra2 I have a condition like this (the idea is that I have either an ID or 0 and then I have to update the DB value with NULL):

if ($_POST['id_extra2']==0) {
    $_POST['id_extra2'] = null;
}

I tried setting $_POST['id_extra2'] to '' and to NULL and to 'null' but it's still not working.

Dharman
  • 30,962
  • 25
  • 85
  • 135
chris_so
  • 862
  • 1
  • 11
  • 20
  • 1
    **what** error it is giving you? – Your Common Sense Jul 18 '13 at 12:47
  • @eggyal I cannot use bindValue, I need to add the parameters list as an array in the `execute()` method – chris_so Jul 18 '13 at 12:49
  • Just set to to empty string, i.e `''` – samayo Jul 18 '13 at 12:50
  • @YourCommonSense - it simply returns `false` (it's the result of the `execute()` method)... I ran the generated query in a SQL editor and it's working just fine. So the issue here is with the NULL parameter sent as a param to the `execute()` method. – chris_so Jul 18 '13 at 12:52
  • 1
    @Simon_eQ - as I specified, I already tried this... still no luck! :( – chris_so Jul 18 '13 at 12:52
  • when you have an array, why can't you iterate over it via foreach and use bindValue, why do you **have to** pass the array as a whole to the execute method? EDIT: Because, as it says here: http://php.net/manual/en/pdostatement.execute.php " All values are treated as PDO::PARAM_STR". – stef77 Jul 18 '13 at 12:54
  • I am sure, you can use some function to get take that one array, from the POST/GET global you are working on. – samayo Jul 18 '13 at 12:56
  • is there a constraint on your table field so that it doesn't allow empty values in that field – DevZer0 Jul 18 '13 at 12:58
  • @DevZer0 It's not a constraint in the database. – chris_so Jul 18 '13 at 13:03
  • @stef77 - I use it this way because I have some dynamically generated queries and bindParams in loops aren't working so great. Already tried this once and it gave me some headaches – chris_so Jul 18 '13 at 13:06
  • Are you using [emulated prepared statements](http://www.php.net/manual/en/pdo.constants.php#pdo.constants.attr-emulate-prepares)? If so, PHP places quotes around each parameter when inlining as string literals into the SQL (per @stef77's comment above), so `NULL` values are impossible. If you use native prepared statements, this ought to work. Please confirm? – eggyal Jul 18 '13 at 13:16
  • @eggyal I'm not using anything, I'm just passing my array to the `execute()` method like this : `execute($params)`... It's working great, except for this case! The big wonderful NULL – chris_so Jul 18 '13 at 13:19
  • @cristic84 Please have a look at my answer, since it doesn't seem possible to get NULL working with directly passing it to execute. So, you might want to consider a workaround like I provided (or something similar). Should mean little to no more work compared to directly using execute. – stef77 Jul 18 '13 at 13:22
  • @cristic84: You're using prepared statements. By default, PDO just *emulates* real statement preparation by escaping your parameters and then inlining them into the SQL for transmission to the MySQL server; alternatively (and IMV preferably) you can use "native" prepared statements whereby the statement is first prepared on the MySQL server, and parameters then transmitted separately. `$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);`. – eggyal Jul 18 '13 at 13:24
  • @eggyal - tried what you've suggested me and still nothing – chris_so Jul 18 '13 at 19:35
  • 1
    @eggyal would you please remove the link which is rather misleading? – Your Common Sense Feb 13 '21 at 06:28

2 Answers2

2

Please consider using bindValue instead of passing the array to execute. As it says here:

All values are treated as PDO::PARAM_STR.

It should be possible to make this pretty transparent to the rest of your application, since you already have the values you want to UPDATE as an array. Try e.g. something like this:

<?php
function executeWithDataTypes(PDOStatement $sth, array $values) {
    $count = 1;
    foreach($values as $value) {
        $sth->bindValue($count, $values['value'], $values['type']);
        $count++;
    }

    return $sth->execute();
}

$sth = $handle->prepare("UPDATE table SET name = ?, id_extra1 = ?, id_extra2 = ? WHERE id_something = ?");

$values = array();
$values[] = array('value' => 'testing', 'type' => PDO::PARAM_STR);
$values[] = array('value' => 2, 'type' => PDO::PARAM_INT);
$values[] = array('value' => null, 'type' => PDO::PARAM_NULL);
$values[] = array('value' => 1958, 'type' => PDO::PARAM_INT);

$result = executeWithDataTypes($sth, $values);
?>

As you noted that using bindParam gave you headaches in the past, please be aware of the subtle difference between bindValue and bindParam. Personally, I never use bindParam because of side effects which make it harder to understand scripts, though there are of course cases where these effects will come in handy.

EDIT: You could of course simplify the function even more and get rid of the need of specifying the type as additional key in the passed array by doing something like:

$type = PDO::PARAM_STR;
switch(true) {
    case is_null($value): $type = PDO::PARAM_NULL; break;
    case is_numeric($value): $type = PDO::PARAM_INT; break;
    // ...
    default: break;
}

and determine the type based on the type of the value passed in the array; however, that's more error-prone, since e.g. floats are also numeric and that would lead to a wrong decision in the above switch statement, but I thought I'd mention it for the sake of completeness.

stef77
  • 1,000
  • 5
  • 19
  • I'm currently adding another update method that implements what you suggested me... I'll be back with an answer. Thanks @stef77 – chris_so Jul 18 '13 at 13:53
  • Here's what I did. When I have "normal" values it works flawless! If I have the `NULL` case, it returns FALSE :(... Any idea? http://pastebin.com/Tad8yFU8 – chris_so Jul 18 '13 at 14:39
  • What is displayed if you call `print_r($updatQuery->errorInfo());` in case of failure? – stef77 Jul 18 '13 at 14:48
  • Besides, be aware of some issues in your pastebin script: you won't be able to insert a string called "null" (better: set it to really `null`, not `"null"`, and check for `is_null`), the string "23" is not `is_int` and will therefore be passed with PDO::PARAM_STR and probably some more issues. And I don't understand your utf8_decode, perhaps you should change the collation of your database table to utf8_unicode_ci, the PDO connection to utf8 and your pages to utf8, so there's no special characters lost. – stef77 Jul 18 '13 at 14:50
  • here's the error ==> `[2] => Cannot add or update a child row: a foreign key constraint fails` - I have a constraint (key), but I also allow `NULL` values. As I said, I tested the code in an SQL editor and it runs perfectly with the `NULL` value... As for the `=='null'` verification, I want it this way because I'll set the returned value as `'null'` myself, so it's not an issue (I will modify this later, for now I want to see it's working). – chris_so Jul 18 '13 at 14:59
  • Also, the log shows me that the values are sent OK (especially the null one), so the bind type is ok. – chris_so Jul 18 '13 at 15:00
  • Let's get rid of all the fancy functions and wrappings and go back to the basics. Please do a `$updateQuery->bindValue(3, null, PDO::PARAM_NULL);` and the other parameters accordingly. If this works, you're good, if not, please provide details of your table definition statements including constraints, especially ON UPDATE clauses. You might also check http://stackoverflow.com/questions/1391777/how-do-i-insert-null-values-using-pdo as already mentioned in another comment. – stef77 Jul 18 '13 at 22:38
  • I'm having the same `constraint` problem when binding `null` value inside an array. If it helps, I found that when setting an array value to `null`, `print_r($array)` will show `Array( [0] => 'value' [1] => [2] => 'other value' )`. Key #1 is the null value, so we see the value is not set to "null", is actually nulled out, so there's no way any SQL NULL value will be set. Maybe it cannot be done with array binding. – aesede Apr 23 '15 at 14:09
0

There is no such question.

JUST send your null value into the database

No special function, not a complex over-engineered solution is ever needed.

It just works. Any method - execute(), bindValue() or bindParam() - use either method you wish. All you need is just a null value. And then just use it in the query as any other value.

$null = null;
$stmt = $pdo->prepare("INSERT INTO table (id) VALUES (?)");
$stmt->execute([$null]);

$stmt->bindParam(1, $null);
$stmt->execute();

$stmt->bindValue(1, $null);
$stmt->execute();

All work

Dharman
  • 30,962
  • 25
  • 85
  • 135
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • it has 7k views which means people are coming here looking for a way to add a null value. though a closure wouldn't change anything so be it – Your Common Sense Feb 15 '21 at 14:18