Sending empty values with PDO results in error - php

We have something like the following PDO Statement which we use to communicate with a PostgreSQL 8.4 DB.
$st = $db -> prepare("INSERT INTO Saba.Betriebskosten (personalkosten)
VALUES(:kd_personalkosten)");
$st -> bindParam(':kd_personalkosten', $val['kd_personalkosten']);
$val['kd_personalkosten'] is either empty/null or contains a double value. In the case it is empty/null, we just want to insert an empty value, but we receive the following error:
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for type double precision: '';
Which means that empty/null is converted to an empty STRING which is not compatible with the double precision field. How to circumvent this error?

it seems to me that value is "" (empty string) which bindParam converts to "" in SQL query, and since personalkosten is of type Double it raises the error.
This should fix this issue with empty text to double conversion:
$st -> bindParam(':kd_personalkosten', (float) $val['kd_personalkosten']);
If you would really want to insert NULL value when variable is empty then you should do this:
$value = $val['kd_personalkosten'];
if ($value === '' or $value === NULL) {
$st->bindValue(':kd_personalkosten', NULL, PDO::PARAM_NULL); // note the bindValue() instead of bindParam()
} else {
$st->bindParam(':kd_personalkosten', $value);
}
About bindValue vs bindParam from php manual:
bindParam()
Binds a PHP variable to a corresponding named or question mark
placeholder in the SQL statement that was used to prepare the
statement. Unlike PDOStatement::bindValue(), the variable is bound as
a reference and will only be evaluated at the time that
PDOStatement::execute() is called.
Most parameters are input parameters, that is, parameters that are
used in a read-only fashion to build up the query. Some drivers
support the invocation of stored procedures that return data as output
parameters, and some also as input/output parameters that both send in
data and are updated to receive it.
Basically bindValue allows you to bind a direct value or constant, whilst bindParam requires a variable or reference to be passed in.

Related

PHP PDO Bind or Execute [duplicate]

I often see code using bindParam or bindValue with PDO. Is simply passing arguments to execute frowned upon for any reason?
I understand that bindParam actually binds to the variables and that you can set the type of parameter being bound with both bind methods, but what if you are only inserting strings?
$query = "SELECT col1 FROM t1 WHERE col2 = :col2 AND col3 = :col3 AND col4 = :col4";
$pdo->bindValue(':col2', 'col2');
$pdo->bindValue(':col3', 'col3');
$pdo->bindValue(':col4', 'col4');
I often see the above, but personally I prefer:
$pdo->execute(array(':col2' => 'col2', ':col3' => 'col3', ':col4' => 'col4'));
It is not as verbose and visually it makes more sense to me to have the inputs "going in" to the query together. However, I hardly ever see it used.
Is there a reason to prefer the bind methods over passing parameters to execute when you don't have to take advantage of the special behaviors of the former?
You might find bindParam used when you just want to bind a variable reference to a parameter in the query, but perhaps still need to do some manipulations on it and only want the value of the variable calculated at time of query execution. It also allows you to do more complex things like bind a parameter to a stored procedure call and have the returned value updated into the bound variable.
For more, see the bindParam documentation, bindValue documentation and execute documentation.
For example
$col1 = 'some_value';
$pdo->bindParam(':col1', $col1);
$col1 = 'some_other_value';
$pdo->execute(); // would use 'some_other_value' for ':col1' parameter
bindValue and passing an array to execute behave in much the same way as the parameter value is fixed at that point and SQL executed accordingly.
Following the same example above, but using bindValue
$col1 = 'some_value';
$pdo->bindValue(':col1', $col1);
$col1 = 'some_other_value';
$pdo->execute(); // would use 'some_value' for ':col1' parameter
When passing values directly in execute all values are treated as strings (even if integer value is provided). So if you need to enforce data types, you should always use bindValue or bindParam.
I think you might see bind* used more than execute(array) as many consider it to be better coding practice to explicitly define data types in parameter declarations.
By passing the parameters along with the $pdo->execute() method, all values in the array with be passed, as PDO::PARAM_STR to the statement with the $pdo->bindParam() function.
The main difference that I can see now, is that with the $pdo->bindParam() function, you can define the data type passed along, using the PDO::PARAM_* constants as described in the PHP.net manual
Simple,
the value of bindParam may change but the value of bindValue can not change.
Example:
$someVal=10;
$someVal2=20;
/* In bindParam, the value argument is not bound and
will be changed if we change its value before execute.
*/
$ref->bindParam(':someCol',$someVal);
$someVal=$someVal2;
$ref->execute();
//someCol=20
/* In bindValue, the value argument is bound and
never changed if we change its value before execute.
*/
$ref->bindValue(':someCol',$someVal);
// here assignment is referral (&$someVal)
$someVal=$someVal2;
$ref->execute();
//someCol=10

String of strings and PDO

What I'm trying to do is pass an array of content tags into my postgresql database query.
I've got this function:
public static function arrayToPdo($array, $pdocon)
{
foreach($array as &$val)
{
$val = $pdocon->quote($val);
}
return implode(",", $array);
}
So that converts the array into a string of quoted values.
I've echoed it and I get 'home','test' which are the tags I expected.
So then I want to bind the return value of that function in my PDO. Here's the where part of the query.
where #> array[:tags]
Now I've substituted the placeholder with the values 'home' and 'test' and it works so the problem lies with how the binding works I think.
When I do the following it works fine:
"where #> array[" . arrayToPdo($array, $conn) . "]"
So here's the code where I bind the value:
$st->bindvalue(":tags", arrayToPdo($array, $conn), PDO::PARAM_STR);
I have another value being bound correctly just before so I feel like it should work.
I've been messing with it for a day and a half and I can't figure it out.
Basically when I enter the quoted values into the query string it works; when I concatenate the function into the query string it works; but when I bind it it doesn't.
There are no errors, I only know it is not working because the query doesn't return any records. I haven't found a way to see what is being inserted into the query string when it is executed so I'm not sure what the problem is.
Any help here would be much appreciated.
In array[:tags], :tags is a set of values, not a single value. Only single values can be bound.
What you probably want here is to use a syntax for an array that represents it as a single value.
Here: PHP array to postgres array
you'll find a function that converts a PHP array into such a syntax.
Then the clause in your query should look like:
"... where #> cast(:myarray as text[])"
Note that there is no array constructor, it's a cast.
Bind it as
$st->bindvalue(":tags", to_pg_array($array), PDO::PARAM_STR);
making sure that PDO is configured to use real prepared statements:
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
(otherwise I suspect that PDO could mess when requoting the parameter. With true prepared statements, parameters are passed by the driver outside of the query and are not quoted).

Cannot pass parameter 2 by reference error in php PDO

I am getting the error:
Cannot pass parameter 2 by reference in.....
in this line...
$stmt1->bindParam(':value', $_SESSION['quantity'.$i] * $_SESSION['price'.$i], PDO::PARAM_STR);
What is wrong with code above ??
I'd say it's the typical confusion between PDO:bindParam() and what you probably intended to use: PDO:bindValue().
PDOStatement::bindParam
Binds a PHP variable to a corresponding named or question mark
placeholder in the SQL statement that was used to prepare the
statement. Unlike PDOStatement::bindValue(), the variable is bound
as a reference and will only be evaluated at the time that
PDOStatement::execute() is called.
PDOStatement::bindValue
Binds a value to a corresponding named or question mark placeholder in
the SQL statement that was used to prepare the statement.
It expects the second paramter to be a variable which can be passed by reference. Assuming $stmt1is a PDO statement then, as the docs for bindparam say
Unlike PDOStatement::bindValue(), the variable is bound as a reference
and will only be evaluated at the time that PDOStatement::execute() is
called.
Your second param is an expression ($_SESSION['quantity'.$i] * $_SESSION['price'.$i]) not a variable. Since you appear to want to evaluate the exptression now, I guess you should used bindValue() instead.

PDO bindParam vs. execute

I often see code using bindParam or bindValue with PDO. Is simply passing arguments to execute frowned upon for any reason?
I understand that bindParam actually binds to the variables and that you can set the type of parameter being bound with both bind methods, but what if you are only inserting strings?
$query = "SELECT col1 FROM t1 WHERE col2 = :col2 AND col3 = :col3 AND col4 = :col4";
$pdo->bindValue(':col2', 'col2');
$pdo->bindValue(':col3', 'col3');
$pdo->bindValue(':col4', 'col4');
I often see the above, but personally I prefer:
$pdo->execute(array(':col2' => 'col2', ':col3' => 'col3', ':col4' => 'col4'));
It is not as verbose and visually it makes more sense to me to have the inputs "going in" to the query together. However, I hardly ever see it used.
Is there a reason to prefer the bind methods over passing parameters to execute when you don't have to take advantage of the special behaviors of the former?
You might find bindParam used when you just want to bind a variable reference to a parameter in the query, but perhaps still need to do some manipulations on it and only want the value of the variable calculated at time of query execution. It also allows you to do more complex things like bind a parameter to a stored procedure call and have the returned value updated into the bound variable.
For more, see the bindParam documentation, bindValue documentation and execute documentation.
For example
$col1 = 'some_value';
$pdo->bindParam(':col1', $col1);
$col1 = 'some_other_value';
$pdo->execute(); // would use 'some_other_value' for ':col1' parameter
bindValue and passing an array to execute behave in much the same way as the parameter value is fixed at that point and SQL executed accordingly.
Following the same example above, but using bindValue
$col1 = 'some_value';
$pdo->bindValue(':col1', $col1);
$col1 = 'some_other_value';
$pdo->execute(); // would use 'some_value' for ':col1' parameter
When passing values directly in execute all values are treated as strings (even if integer value is provided). So if you need to enforce data types, you should always use bindValue or bindParam.
I think you might see bind* used more than execute(array) as many consider it to be better coding practice to explicitly define data types in parameter declarations.
By passing the parameters along with the $pdo->execute() method, all values in the array with be passed, as PDO::PARAM_STR to the statement with the $pdo->bindParam() function.
The main difference that I can see now, is that with the $pdo->bindParam() function, you can define the data type passed along, using the PDO::PARAM_* constants as described in the PHP.net manual
Simple,
the value of bindParam may change but the value of bindValue can not change.
Example:
$someVal=10;
$someVal2=20;
/* In bindParam, the value argument is not bound and
will be changed if we change its value before execute.
*/
$ref->bindParam(':someCol',$someVal);
$someVal=$someVal2;
$ref->execute();
//someCol=20
/* In bindValue, the value argument is bound and
never changed if we change its value before execute.
*/
$ref->bindValue(':someCol',$someVal);
// here assignment is referral (&$someVal)
$someVal=$someVal2;
$ref->execute();
//someCol=10

How define the variable type in PDOStatement::bindValue()?

The PDOStatement::bindValue() method offers a way to specify the type of the variable bound:
PDOStatement::bindValue ( $parameter , $value [, $data_type = PDO::PARAM_STR ] )
I'm wondering, what's the purpose of specifying the data type, whereas when leaved as default (PARAM_STR) eventually the database will anyway cast the value to the proper type before using it?
For example, if you have these queries over an INTEGER field:
INSERT INTO table (integerField) VALUES (?) ;
SELECT * FROM table WHERE integerField = ? ;
And you bind an integer in PHP, PDO will by default bind it as a string, which is equivalent as:
INSERT INTO table (integerField) VALUES ("1") ;
SELECT * FROM table WHERE integerField = "1" ;
That will work flawlessly, because the SQL database (at least MySQL, I'm not really aware of how that would work on other RDBMS) knows how to convert the string back to an integer before using it.
What are the use cases where it would make a difference to bound typed parameters vs strings?
I'm no PDO-expert, but I can think of a few scenarioes where the data_type parameter is both useful and even needed.
Output parameters
When you define output or input/output parameters, you must provide both type and length of the expected output parameter.
Ref: http://www.php.net/manual/en/pdo.prepared-statements.php
Example #4
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
Example #5
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
DBMs without implicit casting
Explained in another answer to this question...
When parameter is not bound to castable data
Even databases with casting abilities will not always be able to cast you variable correctly.
Ref: Reasons to strongly type parameters in PDO?
$limit = 1;
$dbh->prepare("SELECT * FROM items LIMIT :limit");
$dbh->bindParam(":limit", $limit, PDO::PARAM_STR);
// Will throw "You have an error in your SQL syntax..."
That's mainly for interacting with databases that require correct typing. For example, if you enable strict mode in MySQL, you will get errors (failed queries) instead of warnings when there are type mismatches.
By default, MySQL does its best to convert data properly. But if you have ever seen 0000-00-00 in a date field, that is very likely the result of mysql trying to convert a string to a date and failing. In strict mode, the query would fail instead of trying to convert and using whatever the result is.
The data type parameter to PDOStatement::bindValue() isn't terribly useful. Essentially:
If you tell it PDO::PARAM_STR, it converts your value into a string.
If you tell it PDO::PARAM_INT and you pass a boolean, it converts it into a long.
If you tell it PDO::PARAM_BOOL and you pass it a long, it converts it into a boolean.
Nothing else seems to be converted. See here for a quick look at the source code and a little better explanation. Perhaps most importantly, PDO will not throw an exception or produce an error if you pass data with a type that doesn't match the data type you passed.

Categories