I am attempting to do an UPDATE and a SELECT in the same sql statement. For some reason, the below code is failing.
$sql = "UPDATE mytable SET last_activity=CURRENT_TIMESTAMP,
info1=:info1, info2=:info2 WHERE id = {$id};";
$sql .= "SELECT id, info1, info2 FROM myTable
WHERE info1 >=:valueA AND info2>:valueB;"
$stmt = $conn->prepare($sql);
$stmt->bindParam(":info1", $info1);
$stmt->bindParam(":info2", $info2);
$stmt->bindParam(":valueA", $valueA);
$stmt->bindParam(":valueB", $valueB);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($result);
QUESTION: what might I be doing wrong? I have been spending hours on this issue knowing that it's probably a small error right under my nose.
Edited:
I obtained this error message when loading the page that contains the php code:
Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]:
General error' in ajaxCall.php:89 Stack trace: #0 ajaxCall.php(89):
PDOStatement->fetchAll(2) #1 {main} thrown in ajaxCall.php on line 89
I am using ajax to call the php page that contains the above code, and when I load the php page from the browser, I get the above error message.
Line 89 is: $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
Since you are running two queries, you need to call nextRowset to access the results from the second one.
So, do it like this:
// code
$stmt->execute();
$stmt->nextRowset();
// code
When you run two or more queries, you get a multi-rowset result. That means that you get something like this (representation only, not really this):
Array(
[0] => rowset1,
[1] => rowset2,
...
)
Since you want the second set -the result from the SELECT-, you can consume the first one by calling nextRowset. That way, you'll be able to fetch the results from the 'important' set.
(Even though 'consume' might not be the right word for this, it fits for understanding purposes)
Executing two queries with one call is only allowed when you are using mysqlnd. Even then, you must have PDO::ATTR_EMULATE_PREPARES set to 1 when using prepared statements. You can set this using:
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
Alternatively, you can use $conn->exec($sql), which works regardless. However, it will not allow you to bind any data to the executed SQL.
All in all, don't execute multiple queries with one call.
Related
today I encounter an issue after upgrading from PHP 7.4 to PHP 8.1.
All the time I was using this code to establish an MySQL connection:
<?php
$kundencode=$_SESSION['kdnr'];
$i=0;
$q = $pdo->prepare("SELECT * FROM qi_rechnungen WHERE kdnr='$kundencode' ORDER BY rgnr DESC");
$q->execute([$_SESSION['id']]);
$res = $q->fetchAll();
foreach ($res as $row) {
$i++;
?>
This worked fine, but when using PHP 8.1 my system throws:
Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /home/clients-de/public_html/rechnungen2.php:60 Stack trace: #0 /home/clients-de/public_html/rechnungen2.php(60): PDOStatement->execute(Array) #1 {main} thrown in...
I can't see any mistake!?
What's the difference here between PHP 7.4 and 8.1?
Thank you for help...
The change that you encountered is that before PHP 8, PDO's error mode was set to silent by default. If it encountered any errors, it would just ignore them. This has now changed to the exception mode; every time an error is encountered, an exception will be thrown. So the issue was there before, it just remained unreported.
About the actual issue: you should really read up about prepared statements, they will make your code a lot safer. You're not providing any placeholders for prepared variables in your query, but you are passing them in the following line (which results in the exception):
$q->execute([$_SESSION['id']]);
As far as I see, the session ID is completely unnecessary for your query, but you could pass your customer number as a variable. The following should fix your issue:
$q = $pdo->prepare("SELECT * FROM qi_rechnungen WHERE kdnr=? ORDER BY rgnr DESC");
$q->execute([$kundencode]);
First of all, you shouldn't inline raw variables in query, use param binding.
Invalid parameter number: number of bound variables does not match number of tokens
This means that count of array passed into PDO::execute() method is different with count of params in query.
For your case, maybe this solution helps you:
// let's assume there is '5'
$kundencode=$_SESSION['kdnr'];
$q = $pdo->prepare("SELECT * FROM qi_rechnungen WHERE kdnr=:kundencode ORDER BY rgnr DESC");
// pass $kundencode into query
$q->bindValue('kundencode', $kundencode);
// SELECT * FROM qi_rechnungen WHERE kdnr='5' ORDER BY rgnr DESC
$q->execute();
If you want to pass $_SESSION['id'] into query, you must specify it in query template explicitly
#vixducis : That's exactly what I finally did yesterday - and got it to work as desired:
$q = $pdo->prepare("SELECT * FROM qi_domains WHERE kdnr = ? AND aktiv = ? ORDER BY id DESC");
$q->execute([$_SESSION['kdnr'], 0]);
So let me thank you all for your kind support!
This question already has an answer here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(1 answer)
Closed 6 years ago.
I am trying to bind a variable in this prepared statement, but i keep receiving the error:
Call to a member function bind_param() on a non-object
The function is called, and variables are passed to it. When i change the function to just echo the variable, the variable prints on the page fine, but if i try to bind it here i receive the error. can anyone help?
//CALL FROM PAGE ONE
check($username);
//FUNCTION ON PAGE 2
function check($username){
$DBH = getDBH();
$qSelect = $DBH->prepare("SELECT * FROM users WHERE username = ?");
$qSelect->bind_param("s", $username);
}
i know the function is not completely written here, but that shouldn't be a problem. I don't understand why i am receiving this error.
Well, one reason prepare() can fail is if the sql statement sent to it is not valid in the current DB.
prepare() will then return false.
Eg - if the table name is not correct or one or more field in the query does not exist.
as the error-message says, $qSelect seems to be not an object. try to debug this by using var_dump($qSelect); right after your prepare-call. also check if getDBH() returns what you need.
sounds like the prepare-call fails (don't know why) and so it returns false - false is not an object, so you can't call bind_param() on that.
EDIT: you havn't given the info, but it looks like you're using PHP's PDO. In that case, take a look at the documentation.
If the database server successfully
prepares the statement, PDO::prepare()
returns a PDOStatement object. If the
database server cannot successfully
prepare the statement, PDO::prepare()
returns FALSE or emits PDOException
(depending on error handling).
You should configure your server to return those PDO-Exceptions, which would tell you why the prepare call fails.
i'm using the mysqli approach as well and got the same error when I created another instance of mysqli before closing the first instance. So its important to use close() before starting the same piece of code. For example:
$DBH = getDBH();
$qSelect = $DBH->prepare("SELECT * FROM users WHERE username = ?");
$qSelect->bind_param("s", $username);
$qSelect->close(); // <--- use close before calling the same function( wich contains $DBH code) again;
It appears that prepare is quite dumb. It doesn't rely query entirely into the MySQL side, by this, I mean, if in your query, you have a table that happens to have the same name of a keyword, say "user", "order", ..., it just doesn't recognize it as a table, but rather as what the keyword commands actually do, so the query turns out to be a mess and the prepare just fail.
To fix this is simple, you have to type it in the "correct" way adding "`" in both sides of the table name. Example:
`user`, `order`, `...`
It's correct, yet, I find it silly from prepare to have this behavior.
I am trying to help other people with little experience in PHP like me.
In my case, this error occurred because I had an SQL syntax error. The console stack trace did not show the problem.
When I fixed the SQL, the error was gone.
Check the permissions of the user in database. User without "insert" permission causes "Call to a member function bind_param() on a non-object" message error too, when trying to insert.
In this snip-it of PHP code, I'm trying to access my database (dbconn is already defined)
public function get($statement) {
echo $statement . '<br/>';
$fetch = $this->dbconn->prepare($statement);
$fetch->execute();
$res = $fetch->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP);
return $res;
}
Some example outputs of the whole program are, with the query = "example1"
SELECT * FROM keywords WHERE 1
SELECT bin FROM bins WHERE place LIKE 'example1'
{"centralLat":0,"centralLon":0,"errors":[],"posts":[],"location":"example1"}
The code returns the intersection of posts a location (that has been hashed out into bins on a map) and the keywords. The code works fine, it does interpretation on the string and does the appropriate querys, finds intersections, yadda yadda. The problem is for some queries, PDO fails to execute the query
in this case of query = "example2"
SELECT * FROM keywords WHERE 1
SELECT bin FROM bins WHERE place LIKE 'example2' (this the the query that errors)
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: Invalid column index'
In the actual cases, it seems to consistently throw out these errors on SOME queries, but not all. For example: it will always run example1 successfully, but never run example2 successfully. But if I run either of the querys on phpMyAdmin, I cannot replicate the errors, and get the desired results.
The only notable difference, between example1 (and the like) and example2 (and the like) is that querys that work are LONGER (40+ characters), while queries that fail are SHORTER (39-)
Im not sure whats causing this error, any help would be appreciated.
I know this question has been asked many times, but I've read the answers to many of the questions and still cannot understand why I am receiving this error:
Fatal error: Uncaught exception 'PDOException' with message
'SQLSTATE[HY000]: General error: 2014 Cannot execute queries while
other unbuffered queries are active. Consider using
PDOStatement::fetchAll(). Alternatively, if your code is only ever
going to run against mysql, you may enable query buffering by setting
the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.'
The first thing that is odd, is that I do not get an error on my localhost (wampserver), but I do get it on my web server. The php version on my localhost is 5.3.10, and on my web server it is 5.3.13.
I have read that the source of this error is making a query when data left in the buffer from a previous query. This is not the case for me -- I have echo'd out all of the data and I know for a fact that every row returned in a query is being fetched.
With that said, I have found that changing one of my queries to fetchAll instead of fetch fixes the problem, but it simply makes no since because I know that all of the rows returned are being read. When I used fetchAll for the query (it is being made in a loop), I printed out the array each loop, and only one item was in the array for each query in the loop.
One more piece of information. It's not the query that I changed to fetchAll (which makes the error go away) that throws the PDO error, there is another query later in my php file that throws the error. My file is basically like this:
... code ...
query 1
... code ...
loop
query 2
end loop
... code ...
query 3
If I comment out query 3, there is no error. If I comment out, or change to fetchAll, query 2, there is no error. query 1 has no affect whatsoever.
I would also like to add that I have tried adding LIMIT 1 to all of the queries on the page (at the same time), and the error is still there. I think this proves there is not unread data in the buffer, right?
I'm really confused, so I would appreciate your advice. Before someone asks, I can't post the full code for this, but here is a simplified version of my code:
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
makeQuery($stmt, array(':par' => $var));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
for loop
makeQuery($stmt, array(':par' => $var));
$row2 = $stmt->fetch(PDO::FETCH_ASSOC);
... [use row2] ...
end for loop
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
makeQuery($stmt, array(':par' => $var));
$row3 = $stmt->fetch(PDO::FETCH_ASSOC);
Here is makeQuery().
/**************************************************************************************************************
* Function: makeQuery *
* Desc: Makes a PDO query. *
* Pre conditions: The statement/query and an array of named parameters (may be empty) must be passed. *
* Post conditions: The PDO query is executed. Exceptions are caught, displayed, and page execution stopped. *
**************************************************************************************************************/
function makeQuery($stmt, $array, $errMsg = '')
{
try
{
$stmt->execute($array);
}
catch (PDOException $e)
{
print $errMsg != ''?$errMsg:"Error!: " . $e->getMessage() . "<br/>";
die();
}
}
Thanks for your help!
EDIT: I also tried doing the following after query 2 (since that seems to be the source of the problem:
$row2 = $stmt->fetch(PDO::FETCH_ASSOC); var_dump($row2);
The output was:
bool(false)
Have I stumbled across a PDO bug?
You need to fetch until a row fetch attempt fails. I know you may only have one row in the result set and think one fetch is enough, but its not (when you're using unbuffered queries). PDO doesn't know how many rows there are until it reaches the end, where it tries to fetch the next row, but it fails.
You probably have other statements where you didn't fully "fetch until a fetch failed". Yes, I see that you fetch until the fetch failed for one of the statements, but that doesn't mean you did it for all of them.
To clarify -
When you execute a query via execute(), you create a result set that must be fetched from the db into php. PDO can only handle 1 of these "result set in progress of being fetched" at a time (per connection). You need to completely fetch the result set, all the way to the end of it, before you can start fetching a different result set from a different call to execute().
When you "call fetch() until a fetch() fails", the fact that you reached the end of the results is internally noted by PDO when that final call to fetch() fails due to there being no more results. PDO is then satisfied that the results are fully fetched, and it can clean up whatever internal resources between php and the db that were established for that result set, allowing you to make/fetch other queries.
There's other ways to make PDO "call fetch() until a fetch() fails".
Just use fetchAll(), which simply fetches all rows, and so it will hit the end of the result set.
or just call closeCursor()
*if you look at the source for closeCursor(), the default implementation literally just fetches the rows and discards them until it reaches the end. It's written in c obviously, but it more or less does this:
function closeCursor() {
while ($row = $stmt->fetch()) {}
$this->stmtFullyFetched = true;
}
Some db drivers may have a more efficient implementation that doesn't require them to fetch lots of rows that nobody cares about, but that's the default way PDO does it. Anyway...
Normally you don't have these problems when you use buffered queries. The reason is because with buffered queries, right after you execute them, PDO will automatically fully fetch the db results into php memory, so it does the "call fetch() until a fetch() fails" part for you, automatically. When you later call fetch() or fetchAll() yourself, it's fetching results from php memory, not from the db. So basically, the result set is immediately fully fetched when using buffered queries, so there's no opportunity to have more than 1 "result set in progress of being fetched" at the same time (because php is single threaded, so no chance of 2 queries running at the same time).
Given this:
$sql = "select * from test.a limit 1";
$stmt = $dbh->prepare($sql);
$stmt->execute(array());
Ways to fully fetch the result set (assuming you only want the first row):
$row = $stmt->fetch();
$stmt->closeCursor();
or
list($row) = $stmt->fetchAll(); //tricky
or
$row = $stmt->fetch();
while ($stmt->fetch()) {}
After struggling with this issue for days, I finally found that this worked for me:
$db = new PDO ($cnstring, $user, $pwd);
$db->setAttribute (PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
This also happen if you are trying to fetch a non SELECT query (Eg - UPDATE/INSERT/ALTER/CREATE). Make sure to use fetch or fetchAll only for SELECT queries.
Possible Duplicate Answer/Question
I have broken down this issue to it's essence but am still having problems.
When I try and use fetch_all to get the results of a stored procedure, I get results returned to array as expected, but subsequent mysqli calls throw "command out of sync" errors.
I even tried simplifying my stored procedure to...
CREATE PROCEDURE testp()
BEGIN
SELECT * FROM tbl
END
I made the table small, 10 rows 3 cols.
I use the following PHP
$query = "CALL testp()";
$result = $db->query($query);
$rows = $result->fetch_all(MYSQL_ASSOC);
$result->free();
print_r($rows);
$query = "SELECT * FROM tbl WHERE id = ?";
$stmt = $this->db->prepare($query);
echo $this->db->error;
$stmt->close();
Echo's "Commands out of sync; you can't run this command now"
and throws
Fatal error: Call to a member function close() on a non-object
$rows outputs as expected
Any ideas?
This is actually how mysqli works to be honest!
Things happen in batches of 2, which means you need to clear the last result before doing anything else. If you don't -> ERROR!
You can achieve that by using next_result(), example follows:
while($this->_mysqli->next_result());
..then carry on with your code successfully. The above example would fit just after the fetch_assoc_ process is run before returning the array.
(I know this was asked 3 months ago, but rather late than never ;)