I was researching about mysqli prepared statements and i have 2 questions about it.
As i was reading, i figure out that the order of execution of a prepared statement looks something like the following:
$sql = 'SELECT image_id, filename, caption FROM images WHERE image_id = ?';
// connect to the database
$conn = ....
$stmt = $conn->stmt_init();
$stmt->prepare($sql);
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->bind_result($image_id, $filename, $caption);
// optional: get total of records in the result set
$stmt->store_result();
$numRows = $stmt->num_rows;
// loop through the result set
while ($stmt->fetch()) {
// code goes here...
}
or
// fetch the result for one record
$stmt->fetch()
// free & close
$stmt->free_result();
$stmt->close;
$conn->close();
Here's my first question:
As i was reading, it also mentions the following:
If you don't bind the result to variables, use $row = $stmt->fetch(), and access each variable as $row['column_name']. So,
Are they any pros/cons using either of the 2 methods to loop the result set?
If there's no difference, then why bother binding the result using $stmt->bind_result in the first place? What's the point if i can use $row = $stmt->fetch() instead?
Here's my other question:
$stmt->free_result(); frees what exactly? the prepare() or the store_result() or else ?
$stmt->close; what am i closing exactly? the stmt_init() or the prepare() or else?
Hopefully your answers will make me understand better prepared statements so i can build something safe...
Thanks
$stmt->free_result() does pretty much what the name says: it frees the memory associated with a result.
$stmt->close closes the statement handle (the cursor actually), making it impossible to loop through the result set (again).
Although the manual states: 'You should always free your result with mysqli_free_result(), when your result object is not needed anymore', common practice is not to use free_result and close on a statement. When closed you cannot use the result set anymore, or reuse it and when php dies, memory is freed anyway.
Related
Let's say I have prepared a mysqli statement by doing $stmt = $connection->prepare("SELECT name, id, password_hash FROM person WHERE id = ?") and that I use this statement in a function:
function get_person_info($person_id) {
global $stmt;
$stmt->bind_param("s", $person_id);
$stmt->execute();
return $stmt->get_result()->fetch_array();
}
If I don't know how many times this function will be called, when should I close $stmt if I want optimal performance?
More specifically: what exactly happens when closing $stmt? I have read the documentation at php.net, but it was unclear to me whether or not I am supposed to close a statement if I plan on reusing it.
Don't close it. It will be closed at the script's end.
The following code:
$con = ConnectDB::getConnection();
if ($stmt = $con->prepare('---SQL here with 1 param---')) {
$stmt->bind_param('i', $this->id);
$stmt->execute();
$stmt->bind_result($device_id, $device_identifier);
while ($stmt->fetch()) {
$device = new Device($device_identifier, $device_id);
$all_devices[] = $device;
}
fetches an empty result? The first time through the loop, the $device_id and $device_identifier is empty, but the fetch() method returns true so it runs. HOWEVER - the SECOND iteration actually contains my result.
I could simply check if they are empty and ignore them, but i really can't understand why it is returning an empty pair? I tried running the SQL directly on the DB and it just returns 1 result row?
Any ideas?
As you may imagine, MySQLi prepared statement fetch does not return an empty first row. As such a behavior would make a very little sense.
You need to learn to create a correct proof for your assertions.
The code you posted is incorrect one. For some reason you are trying to judge a matter by indirect consequences. Why not to examine the matter itself?
$con = ConnectDB::getConnection();
if ($stmt = $con->prepare('---SQL here with 1 param---')) {
$stmt->bind_param('i', $this->id);
$stmt->execute();
$stmt->bind_result($device_id, $device_identifier);
$stmt->fetch();
var_dump($device_identifier, $device_id);
-- this code will tell you unambiguously, if your assumption on empty result was right or wrong.
After learning that, you may start debugging, to find a spot in your own code that is responsible for the current behavior.
Hope it helps.
I have a conventional query that works just fine that looks like this:
$result = $mysqli->query("SELECT value FROM activities WHERE name = 'Drywall'");
This succeeds in returning a row. However, for the purposes of diagnosing the problem I'm having with a prepared statement, I tried an identical query as a prepared statement like so:
$stmt = $mysqli->prepare("SELECT value FROM activities WHERE name = 'Drywall'");
$stmt->execute();
Despite the fact these are identical query strings, $stmt->num_rows is always 0. Why would the conventional query work, but the prepared statement not when they are the same exact query? Also, I realize including 'Drywall' in the prepared query string runs counter to the purpose of prepared statements, but I was just trying to eliminate the possibility that bind_param() was the culprit. So I was using bind_param() to fill in placeholders and that wasn't working either, despite my double-checking at runtime that the variable I was binding contained the correct value.
I think you want to use
$stmt->store_result();
before the call
$stmt->num_rows();
see last line of the descripton in the manual for $stmt->num_rows() (http://www.php.net/manual/en/mysqli-stmt.num-rows.php).
Check for proper use of the mysqli->prepare. The function depends on a parameter to be passed. It is different from passing the values directly in the query but can use with another way.
Verify the manual:
http://www.php.net/manual/pt_BR/mysqli.prepare.php
Did you try something like this:
$stmt = $mysqli->prepare("SELECT value FROM activities WHERE name = 'Drywall'");
$stmt->execute();
$res = $stmt->get_result();
$row = $res->fetch_assoc();
PS:
Prepared statements are Good. I would urge you to ALWAYS consider using them.
But in this case, a simple query would be much more efficient (would incur fewer round trips) than a prepared statement.
This question already has an answer here:
Why does mysqli num_rows always return 0?
(1 answer)
Closed 1 year ago.
after reading tons of threads, tutorials and whatever - I feel like posting here and hope that someone can help me.
I tried out every advice I could get, but it's still not working.
Here is my code :
$prep_stmt = "SELECT id, DATE_FORMAT(added,'%d.%M'), title FROM offers ORDER BY added DESC LIMIT ?, ?;";
$stmt = $mysqli->prepare($prep_stmt);
$stmt->bind_param ('ii',$lowlimit, $page);
$stmt->execute();
$stmt->bind_result($id, $added, $title);
while ($stmt->fetch()) {
... # some random output here
}
$count = $stmt->num_rows;
echo "c -> ". $count;exit;
I always get "c -> 0" ... but there IS output already ... so what am I doing wrong ? :/
You need to call the store_result() method before accessing the num_rows property.
From a comment on PHP manual documentation:
If you do not use mysqli_stmt_store_result(), and immediately call this function after executing a prepared statement, this function will usually return 0 as it has no way to know how many rows are in the result set as the result set is not saved in memory yet.
mysqli_stmt_store_result() saves the result set in memory thus you can immedietly use this function after you both execute the statement AND save the result set.
Your code should look like:
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($id, $added, $title);
while ($stmt->fetch()) {
# some random output here...
}
$count = $stmt->num_rows;
Taken from php.net You have to store it first.
$stmt->store_result();
$count = $stmt->num_rows
From the PHP manual, first comment http://fr2.php.net/manual/fr/mysqli-stmt.num-rows.php :
Please be advised, for people who sometimes miss to read this important Manual entry for this function:
If you do not use mysqli_stmt_store_result( ), and immediatley call
this function after executing a prepared statement, this function will
usually return 0 as it has no way to know how many rows are in the
result set as the result set is not saved in memory yet.
mysqli_stmt_store_result( ) saves the result set in memory thus you
can immedietly use this function after you both execute the statement
AND save the result set.
If you do not save the result set but still want to use this function
you have to actually loop through the result set one row at a time
using mysqli_stmt_fetch( ) before using this function to determine the
number of rows.
A thought though, if you want to determine the number of rows without
storing the result set and after looping through it, why not just
simply keep an internal counter in your loop every time a row is
fetched and save the function call.
In short, this function is only really useful if you save the result
set and want to determine the number of rows before looping through
it, otherwise you can pretty much recreate its use like I suggested.
I writing an accounting website which has quite a few MySQL statements in it. To prevent SQL injection I use prepared statements for any data which is put in by the user.
In order to prevent having to write the steps of preparing and binding statements I have the following function:
function executeSql($mysqli,$query_string,$params=null,$paramtypes=null){
$nr_params=strlen($paramtypes);
$query_type = substr($query_string,0,3);
$stmt = $mysqli->prepare($query_string);
$queryParams[] = $paramtypes;
$counter=1;
if($nr_params>1){
while($counter<=$nr_params){
$queryParams[$counter]=&$params[$counter-1];
$counter++;
}
} else {
$queryParams[1]=&$params;
}
// Actual binding of the statement. Taking into account a variable numbers of '?' in the query string.
call_user_func_array(array($stmt,'bind_param'),$queryParams);
// Execution of the statement
$stmt->execute();
// Part where i'd like to have a substitute for:
$result = $stmt->get_result();
return $result;
}
In the last part I'd like to return the result because then using the result I can treat each row. The problem is that the mysqlnd driver is not installed on the production server so the function $stmt->get_result() cannot be used. I tried to bind the result into variables but then again, every query returns a different number of columns.
Anyone has an idea how to tackle this?
So in summary (in response to the comments):
How can I retrieve a results object of an executed MySQLi statement while I cannot use $stmt->get_result();
Kind regards,
EJG
PS I know the code is not flawless, e.g. if strings are used as variables to bind to the statement but that is easily fixed.
UPDATE:
I came across the function $stmt->result_metadata(); Although supposedly the function name suggests only the meta data the php documentation states that:
"If a statement passed to mysqli_prepare() is one that produces a result set, mysqli_stmt_result_metadata() returns the result object"...