PDO PostgreSQL binding error - php

I found that when I'm trying to run update query with params, I'm getting error
inconsistent types deduced for parameter
Maybe that's because the type of target field (character varying), everything works fine with text column type. But I don't want to change column type only because of this. Then I was told that I should pass params directly (using bindValue or bindParam, determining the type of each value) instead of sending params array to execute method.
But when I do so I'm getting error
ERROR: bind message supplies 0 parameters, but prepared statement
"pdo_stmt_00000001" requires 1
The test code is
$Stmt = $DB->prepare("SELECT * FROM test_table WHERE test_field=:test_field");
$Stmt->bindValue(':test_field', 'test', PDO::PARAM_STR);
$Stmt->execute();
var_dump($DB->errorInfo());
So, as far as understand, binding does not work at all. Or I'm doing it wrong.
But maybe there is a way of solving it?
I'm running PHP 5.4.12 with PostgreSQL 9.2.3, libpq 8.4.16.

Well, it seems that the only solution is to cast all text values to text like this:
update test_table set test_field = :test_field::text
Otherwise error about inconsistent types is occurring.

I do it this way:
$stmt = $DB->prepare("SELECT * FROM test_table WHERE test_field=:test_field");
$stmt->execute(array(":test_field" => 'test'));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if($result)
{
return $result['id'];
// Or whatever you're trying to get.
}
return null;
You just have to throw in an array of parameters in the execute function, no need to add a special line for the binding.
Tell me if it works for you (or not).

Related

PDO: Database reports an error: SQLSTATE[HY000]: General error: 2031 [duplicate]

I'm getting this annoying error and although I have an idea of why I'm getting it, I can't for the life of me find a solution to it.
if ($limit) {
$sth->bindValue(':page', $page - 1, PDO::PARAM_INT);
$sth->bindValue(':entries_per_page', $page * $entries_per_page, PDO::PARAM_INT);
}
$sth->execute($criteria);
Query contains placeholders (:placeholder). But to add those LIMIT placeholders, I need to use the manual method (bindValue) because otherwise the engine will turn them into strings.
I'm not getting the Invalid number of parameters error, so all placeholders have been bound correctly (I assume).
Query:
SELECT `articles`.*, `regional_municipalities`.`name` AS `regional_municipality_name`,
`_atc_codes`.`code` AS `atc_code`, `_atc_codes`.`name` AS `substance`
FROM `articles`
LEFT JOIN `_atc_codes`
ON (`_atc_codes`.`id` = `articles`.`atc_code`)
JOIN `regional_municipalities`
ON (`regional_municipalities`.`id` = `articles`.`regional_municipality`)
WHERE TRUE AND `articles`.`strength` = :strength
GROUP BY `articles`.`id`
ORDER BY `articles`.`id`
LIMIT :page, :entries_per_page
All placeholder values reside in $criteria, except for the last two LIMIT, which I manually bind with bindValue().
This same error 2031 can be issued when one bind two values with the same parameter name, like in:
$sth->bindValue(':colour', 'blue');
$sth->bindValue(':colour', 'red');
..so, beware.
You cannot use ->bind* and ->execute($params). Use either or; if you pass parameters to execute(), those will make PDO forget the parameters already bound via ->bind*.
This exception also appears if you try to run a query with placeholders instead of preparing a statment such as
$stmt = $db->query('SELECT * FROM tbl WHERE ID > ?');
instead of
$stmt = $db->prepare('SELECT * FROM tbl WHERE ID > ?');
From the manual:
public bool PDOStatement::execute ([ array $input_parameters ] )
Execute the prepared statement. If the prepared statement included
parameter markers, you must either:
call PDOStatement::bindParam() to bind PHP variables to the parameter markers: bound variables pass their value as input and
receive the output value, if any, of their associated parameter
markers
or pass an array of input-only parameter values
You need to pick a method. You cannot mix both.
It's not exactly an answer, but this error also happens if you try to use a word with a hyphen as placeholders, for example:
$sth->bindValue(':page-1', $page1);
So better use
$sth->bindValue(':page_1', $page1);
This happens if you have mismatching parameters. For example:
$q = $db->prepare("select :a, :b");
$q->execute([":a"=>"a"]);
The exception also happens (at least in MySQL/PDO) when your SQL tries to UPDATE an AUTO_INCREMENT field.

shorthand PDO query

Currently to perform a query with PDO, I use the following lines of code:
$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
And after some research, I found a shorter way of executing the same command:
$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);
From there I thought I could possibly make it even shorter with the following code:
$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$result = $stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
But I get the following error:
Fatal error: Call to a member function fetchAll() on a non-object in
/home/.../index.php on line 20
QUESTION: Why am I getting this error? From my understanding, $stmt_test->execute([$id]) should be executing first, then the result of that would execute the ->fetchAll(PDO::FETCH_ASSOC) and from there return the array to $result, but since the error is happening, something must be flawed in my logic. What am I doing wrong? Also, does anyone know a better shorthand method to perform the previous query?
So you've got an answer for the question "Why I am getting this error", but didn't get one for the "shorthand PDO query".
For this we will need a bit of a thing called "programming".
One interesting thing about programming is that we aren't limited to the existing tools, like with other professions. With programming we can always create a tool of our own, and then start using it instead of a whole set of old tools.
And Object Oriented Programming is especially good at it, as we can take an existing object and just add some functionality, leaving the rest as is.
For example, imagine we want a shorthand way to run a prepared query in PDO. All we need is to extend the PDO object with a new shorthand method. The hardest part is to give the new method a name.
The rest is simple: you need only few lines of code
class MyPDO extends PDO
{
public function run($sql, $bind = NULL)
{
$stmt = $this->prepare($sql);
$stmt->execute($bind);
return $stmt;
}
}
This is all the code you need. You may store it in the same file where you store your database credentials. Note that this addition won't affect your existing code in any way - it remains exactly the same and you may continue using all the existing PDO functionality as usual.
Now you have to change only 2 letters in PDO constructor, calling it as
$conn = new MyPDO(...the rest is exactly the same...);
And immediately you may start using your shiny new tool:
$sql = "SELECT * FROM myTable WHERE id = :id";
$result = $conn->run($sql, ['id' => $id])->fetchAll(PDO::FETCH_ASSOC);
Or, giving it a bit of optimization,
$result = $conn->run("SELECT * FROM myTable WHERE id = ?", [$id])->fetchAll();
as you can always set default fetch mode once for all, and for just a single variable there is no use for the named placeholder. Which makes this code a real shorthand compared to the accepted answer,
$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$stmt_test->execute([$id]);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);
and even to the best answer you've got so far,
$result = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$result->execute([$id]);
not to mention that the latter is not always usable, as it fits for getting an array only. While with a real shorthand any result format is possible:
$result = $conn->run($sql, [$id])->fetchAll(); // array
$result = $conn->run($sql, [$id])->fetch(); // single row
$result = $conn->run($sql, [$id])->fetchColumn(); // single value
$result = $conn->run($sql, [$id])->fetchAll(PDO::FETCH_*); // dozens of different formats
$stmt_test->execute([$id]) returns a boolean value. That mean that
$result = $stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
isn't valid. Instead you should do
$stmt_test->execute([$id]);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);
The error you're getting comes form the way PDO was designed. PDOStatement::execute() doesn't return the statement, but a boolean indicating success. The shortcut you want therefore isn't possible.
See function definition in http://php.net/manual/en/pdostatement.execute.php
Additionally let me add that forEach() often (not always) is a code smell and takes relatively much memory as it has to store all rows as PHP values.
I believe PDO's execute() method returns either true or false. As the error already tells you: fetchAll() expects an object. Using three lines of code would be the shortest way.
Another option is to use an ORM like propel, it works really smooth and will save you alot of time.

db2_prepare(): Statement Prepare Failed when binding parameter

I am trying to prepare a statement for a table function on a DB2 on iSeries, but I'm getting a db2_prepare() warning. When I insert the parameter value directly into the SQL statement, it works fine.
Here is what I'm trying to prepare:
$sql = 'SELECT U8.VALIDUSER(?) '
. 'FROM SYSIBM.SYSDUMMY1';
$stmt = db2_prepare($this->conn, $sql);
db2_bind_param($stmt, 1, 'userID', DB2_PARAM_IN);
PHP returns: Warning: db2_prepare(): Statement Prepare Failed in... for the db2_prepare() line.
If I change it to this, it works:
$sql = 'SELECT U8.VALIDUSER(\'' . $userID . '\') '
. 'FROM SYSIBM.SYSDUMMY1';
$stmt = db2_prepare($this->conn, $sql);
Why does it fail when I bind the parameter, but works when I insert it directly? I naturally want to bind the parameter so I don't have to add unnecessary sanitization for this one situation.
Is there something I'm missing?
As mentioned in the comment, I'm guessing that your problem is that DB2 cannot determine what type your parameter is when it's doing the binding. If you add a CAST around the parameter to tell DB2 what type you are passing, it should work.
I'm not sure if PHP has an option, but in C#, you can pass in the type when defining the parameter, so that might be an option, if it's available, instead of hard-coding the type in SQL.
Check out this other answer I have about how to fetch the "native" DB2 errors, which are likely much more helpful than the ones thrown by PHP. I also have another answer about SQL0418N, which is probably the actual error you would have received if you were looking at the native error.

Calling stored procedure with Out parameter using PDO

I've been using PDO for awhile now and am refactoring a project so that it uses stored procs instead of inline SQL. I am getting an error that I can't explain.I am using PHP version 5.3.5 and MySQL version 5.0.7.
I'm just trying to get a basic stored proc with an output to work. Here is the stored proc:
DELIMITER //
CREATE PROCEDURE `proc_OUT` (OUT var1 VARCHAR(100))
BEGIN
SET var1 = 'This is a test';
END //
Here is the code I am using to call the proc, $db is an instance of PDO:
$stmt = $db->prepare("CALL proc_OUT(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// call the stored procedure
$stmt->execute();
echo $returnvalue;
Simple right? However, it results in the following error:
exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1414 OUT or INOUT argument 1 for routine mydb.proc_OUT is not a variable or NEW pseudo-variable in BEFORE trigger
If I call the proc directly like so:
CALL proc_OUT(#res);
SELECT #res;
it works as expected which leads me to believe that there is a problem with how it is being called with PHP, however I can't seem to find what the issue is. I am following the instructions in the manual but am still getting this error. Could anyone suggest what I could be doing wrong? Any advice would be very much appreciated. Thanks much!
It would seem that there is a bug at work here, best solution I've found is this:
http://www.php.net/manual/en/pdo.prepared-statements.php#101993
From the comment at the link above:
$dbh->query("CALL SomeStoredProcedure($someInParameter1, $someInParameter2, #someOutParameter)");
$dbh->query("SELECT #someOutParameter");
// OR, if you want very much to use PDO.Prepare(),
// insert "SELECT #someOutParameter" in your stored procedure and then use:
$stmt = $dbh->prepare("CALL SomeStoredProcedure(?, ?)");
$stmt ->execute(array($someInParameter1, $someInParameter2));
See also this: https://stackoverflow.com/a/4502524/815386
Got it! Just add a
SELECT #outputparam;
at the end of the stored procedure, where #outputparam is the name used for the param in the stored procedure definition. If you cannot edit the stored procedure, you should do a second query, for SELECT #outputparam, with PHP PDO to get the output param value.
Tip: If you're using the deprecated DBLib to connect to SQL Server and you modified the stored procedure as suggested, you'll also need to tweak your syntax to get the output param value in the calling PHP script:
$out = 0;
$sth = $db->prepare("DECLARE #myout INT; EXECUTE mysp :firstparam, :secondparam, #myout OUTPUT;"); // the DECLARE trick is needed with DBLib
$sth->bindParam(':firstparam', $firstparam, PDO::PARAM_INT);
$sth->execute();
$sth->bindColumn(1, $out, PDO::PARAM_INT);
$sth->fetch(PDO::FETCH_BOUND);
var_dump($out); // works
You need to specify that your parameter is IN/OUT style like PHP web site example :
http://php.net/manual/en/pdo.prepared-statements.php example #5
<?php
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// call the stored procedure
$stmt->execute();
print "procedure returned $value\n";

2nd MySQLi Query causes a "Call to a member function execute() on a non-object"

I've got a strange problem. There are 2 queries.
$sql = "SELECT `content_auftrag_id`
FROM `content`
WHERE `content_id` = '".$content_id."' LIMIT 1";
$ergebnis = $db->prepare( $sql );
$ergebnis->execute();
$ergebnis->bind_result( $content_auftrag_vorhanden );
$content_auftrag_id = "test";
$sql = "UPDATE `content` SET `content_auftrag_id` = '".$content_auftrag_id."'
WHERE `content_id` = '".$content_id."'";
$ergebnis2 = $db->prepare( $sql );
$ergebnis2->execute();
When I use them both, then an error occurs for the second one. If I only run the the second, then it works fine. How can it be that both together cause an error?
All variables are there and correct.
Thanks!
Okay, I think you didn't quite got the idea behind PreparedStatements. You shouldn't directly insert the parameters in your SQL-String, but use ?-placeholders and bind them in the Query using the bind_param()-method.
Your error seams to appear here:
$ergebnis2 = $db->prepare( $sql );
This function returns false if it wasn't successful. You should check if the value of ergebnis2 is not false.
Also, you should use the error-method to see the last appeared MySQL-Error.
You can only work on one prepared query at a time, so to speak. See Mysqli::execute() method:
"When using mysqli_stmt_execute(), the mysqli_stmt_fetch() function must be used to fetch the data prior to performing any additional queries."
You can also use the store_result() method to remove this block as well to perform the next query.
Also, take heed from those who warn you about abusing prepared statements like your example. Though it works without error if you don't actually have any parameters to bind to, it basically throws sql injection prevention out the window.
If $ergebnis2 is 'not an object', then I guess it must be false. Which means the prepare() call failed for whatever reason.
What does $db->error return after you have called the 2nd prepare?
Always check your return values, its basic debugging

Categories