Nested prepared statements and free_result - php

Can someone explain why free_result after a while loop on a nested prepared statement causes bind_result to not update values as intended?
$stmt = $mysqli -> prepare("select col1 from table1 inner join ...");
$stmt -> bind_param("i", $id);
$stmt -> bind_result($col1);
$stmt -> execute() or die();
$stmt -> store_result();
$stmt2 = $mysqli -> prepare("select col2, col3 from table2 where col4 = ?");
$stmt2 -> bind_param("i", $col1);
$stmt2 -> bind_result($col2, $col3);
while ($stmt -> fetch()) {
$stmt2 -> execute() or die();
$stmt2 -> store_result();
while ($stmt2 -> fetch()) {
echo $col2 .",";
}
$stmt2 -> free_result(); // <== Works fine without this line
echo "---";
}
$stmt -> close();
$stmt2 -> close();
If I remove free_result, I get the expected output, let's say:
1,2,---3,4,5,---6,7,---
If I leave it, the last result of the first run on the parent loop repeats like so:
1,2,---2,2,2,---2,2,---
I can't find the answer in the docs ... It seems counter-intuitive since the results are retained instead of being freed.
Here's an executable example

As stated in the documentation for bind_result():
All columns must be bound after mysqli_stmt_execute() and prior to calling mysqli_stmt_fetch().
If you move the bind_result() call to the appropriate place it will work:
$stmt = $mysqli->prepare("select col1 from table1");
$stmt->execute();
$stmt->bind_result($col1);
$stmt->store_result();
$stmt2 = $mysqli->prepare("select col2, col3 from table2 where col4 = ?");
$stmt2->bind_param("i", $col1);
while ($stmt->fetch()) {
$stmt2->execute();
$stmt2->bind_result($col2, $col3);
$stmt2->store_result();
while ($stmt2->fetch()) {
echo $col2 .",";
}
$stmt2->free_result();
echo "---";
}
$stmt->close();
$stmt2->close();
The reason for this is that mysqli_stmt::free_result() asks mysqlnd to free up all result variables. The references are released, but neither the variables nor their values are not destroyed by PHP. They are just unbound.
You can either stop using mysqli_stmt::free_result() (which you probably should do anyway) or bind the result variables after every execution.

Related

Getting zero back using count in SQL with prepared statement

I am working on the following script. Why am I always getting 0 using the COUNT(*) in my query against MySQL using prepared statement?
$num_query = "SELECT COUNT(*) FROM $tbl WHERE `tdisplay` = 1";
$stmt2 = $conn-> prepare($num_query);
$stmt2 -> execute();
$stmt2 -> store_result();
$rows = $stmt2->num_rows;

Multiple mysqli prepared statements not working together

A lot has changed in the PHP world since the last time I was using it (few years back). Now it seems I need to learn again everything, which takes me to my current problem.
/* Create a prepared statement */
$stmt1 = $mysqli -> prepare("SELECT channel FROM channel WHERE barcode=?");
$stmt2 = $mysqli -> prepare("SELECT action FROM action WHERE barcode=?");
$stmt3 = $mysqli -> prepare("SELECT reason FROM reason WHERE barcode=?");
$stmt4 = $mysqli -> prepare("SELECT supplier_name FROM suppliers WHERE barcode=?");
/* Bind parameters */
$stmt1 -> bind_param("s", $_POST['channel']);
$stmt2 -> bind_param("s", $_POST['action']);
$stmt3 -> bind_param("s", $_POST['reason']);
$stmt4 -> bind_param("s", $_POST['supplier']);
/* Execute it */
$stmt1 -> execute();
$stmt2 -> execute();
$stmt3 -> execute();
$stmt4 -> execute();
/* Bind results */
$stmt1 -> bind_result($channel1);
$stmt2 -> bind_result($action1);
$stmt3 -> bind_result($reason1);
$stmt4 -> bind_result($supplier1);
/* Fetch the value */
$stmt1 -> fetch();
$stmt2 -> fetch();
$stmt3 -> fetch();
$stmt4 -> fetch();
echo "Channel ".$channel1."; Action: ".$action1."; Reason: ".$reason1."; Supplier: ".$supplier1;
Eeverything works just fine one by one, but when it's all combined... nothing. Only the first statement will work. What am I doing wrong???
This happen because:
mysqli_stmt::execute:
Note:
When using mysqli_stmt_execute(), the mysqli_stmt_fetch() function must be used to fetch the data prior to performing any additional queries.
mysqli_stmt::close:
Closes a prepared statement. mysqli_stmt_close() also deallocates the statement handle. If the current statement has pending or unread results, this function cancels them so that the next query can be executed.
The binding (for params and results) can be done before execution... just excludes execute(), fetch() and close() for each statment in one separate block each.
Also take in mind the use of trigger_error($mysqli->error); to check possible errors while using prepare().

OOP Mysqli num_rows allways return 0

I'm trying to count the rows returned from the database. When i run this code this will give me return of 1 row which contains a username and password but when i try to count the rows it allways give back zero even tho database is actually returning rows.
$row_count =$stmt -> num_rows only returns 0.
$stmt = $mysqli -> prepare
("SELECT username, password FROM members WHERE username=? AND password=?");
$stmt -> bind_param("ss", $username, $password);
$stmt -> execute();
$stmt -> bind_result($returned_username, $returned_password);
$stmt->fetch();
$row_count = $stmt -> num_rows;
echo $row_count;
echo $returned_username;
echo "<br />";
echo $returned_password;
$stmt -> close();
$mysqli ->close();
Use $stmt->store_result(); before getting the num_rows.
More info: http://php.net/manual/en/mysqli-stmt.num-rows.php
Try this:
$stmt = $mysqli -> prepare
("SELECT username, password FROM members WHERE username=? AND password=?");
$stmt -> bind_param("ss", $username, $password);
$stmt -> execute();
$stmt -> store_result(); //You need to store the results first
$stmt -> bind_result($returned_username, $returned_password);
$stmt->fetch();
$row_count = $stmt -> num_rows;
echo $row_count;
echo $returned_username;
echo "<br />";
echo $returned_password;
$stmt -> close();
$mysqli ->close();

Prepared statement is returning empty results, possible syntax error

When I execute the prepared statement the results are returned empty. If I copy and paste the statement into phpMyAdmin it executes properly. $_SESSION['userGroup'] has been checked and confirmed to contain the proper value but $systems remains undefined.
Am I missing something?
$stmt = $mysqli -> prepare("SELECT `Systems` FROM `groups` WHERE `GroupID` = ?");
echo $mysqli -> error;
$stmt -> bind_param('i', $_SESSION['userGroup']);
$stmt -> execute();
$stmt -> store_result();
$stmt -> bind_result($systems);
Am I missing something?
you are missing documentation and/or tutorial to learn from.
Where you can learn the proper syntax that should include
$stmt -> fetch();
Just try
$stmt -> bind_param('i', $_SESSION['userGroup']);
$stmt -> execute();
$stmt -> bind_result($systems);
$stmt -> fetch();

Prepared Statements - Number of Rows

I'm just trying to figure out how to determine the number of rows and then make that number display in the HTML.
My prepared statement looks like this:
if($stmt = $mysqli -> prepare("SELECT field1, field2, field3 FROM table WHERE id= ?ORDER BY id ASC"))
{
/* Bind parameters, s - string, b - blob, i - int, etc */
$stmt -> bind_param("i", $id);
$stmt -> execute();
/* Bind results */
$stmt -> bind_result($testfield1, $testfield2, $testfield3);
/* Fetch the value */
$stmt -> fetch();
/* Close statement */
$stmt -> close();
}
I understand that I'm supposed to first save the results, then use num_rows, like this:
$stmt->store_result();
$stmt->num_rows;
However, I'm running, and issue with the page bugging out when I put that code in there. I haven't even been able to get to the next step of how to display the number of rows
What am I missing in terms of calculating the number of rows inside the prepared statement, then how would I display it with a <?php echo '# rows: '.$WHATGOESHERE;?>
num_rows returns the number, you have to store it in a variable.
/*.....other code...*/
$numberofrows = $stmt->num_rows;
/*.....other code...*/
echo '# rows: '.$numberofrows;
So full code should be something like this:
$stmt = $mysqli -> prepare("SELECT field1, field2, field3 FROM table WHERE id= ? ORDER BY id ASC");
/* Bind parameters, s - string, b - blob, i - int, etc */
$stmt -> bind_param("i", $id);
$stmt -> execute();
$stmt -> store_result();
/* Bind results */
$stmt -> bind_result($testfield1, $testfield2, $testfield3);
/* Fetch the value */
$stmt -> fetch();
$numberofrows = $stmt->num_rows;
/* Close statement */
$stmt -> close();
echo '# rows: '.$numberofrows;
If you are only interested in the row count instead of the actual rows of data, here is a complete query block with a COUNT(*) call in the SELECT clause.
$conn = new mysqli("host", "user", "pass", "db");
$stmt = $conn->prepare("SELECT COUNT(*) FROM `table` WHERE id= ?");
$stmt->bind_param("s", $id);
$stmt->execute();
$stmt->bind_result($num_rows);
$stmt->fetch();
echo $num_rows;
Or if you want to know the row count before iterating/processing the rows, one way is to lump the entire resultset (multi-dimensional array) into a variable and call count() before iterating.
$conn = new mysqli("host", "user", "pass", "db");
$sql = "SELECT field1, field2, field3
FROM table
WHERE id= ?
ORDER BY id";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$result = $stmt->get_result();
$resultset = $result->fetch_all(MYSQLI_ASSOC);
echo "<div>Num: " , count($resultset) , "</div>";
foreach ($resultset as $row) {
echo "<div>Row: {$row['field1']} & {$row['field2']} & {$row['field3']}</div>";
}
*I have tested both of the above snippets to be successful on my localhost.
This works as of Feb 2020:
$number_of_records = $stmt->rowCount();
echo $number_of_records;
From php.net manual:
PDOStatement::rowCount() returns the number of rows affected by a
DELETE, INSERT, or UPDATE statement.
Here is an example from their website:
<?php
/* Delete all rows from the FRUIT table */
$del = $dbh->prepare('DELETE FROM fruit');
$del->execute();
/* Return number of rows that were deleted */
print("Return number of rows that were deleted:\n");
$count = $del->rowCount();
print("Deleted $count rows.\n");
?>
The above example will output:
Return number of rows that were deleted:
Deleted 9 rows.
Check out the example #2 here:
PHP.net
Use PDO::query() to issue a SELECT COUNT(*) statement with the same predicates as your intended SELECT statement, then use PDOStatement::fetchColumn() to retrieve the number of rows that will be returned. Your application can then perform the correct action.

Categories