I have built a class which leverages the abilities of PHP's built-in MySQLi class, and it is intended to simplify database interaction. However, using an OOP approach, I am having a difficult time with the num_rows instance variable returning the correct number of rows after a query is run. Take a look at a snapshot of my class...
class Database {
//Connect to the database, all goes well ...
//Run a basic query on the database
public function query($query) {
//Run a query on the database an make sure is executed successfully
try {
//$this->connection->query uses MySQLi's built-in query method, not this one
if ($result = $this->connection->query($query, MYSQLI_USE_RESULT)) {
return $result;
} else {
$error = debug_backtrace();
throw new Exception(/* A long error message is thrown here */);
}
} catch (Exception $e) {
$this->connection->close();
die($e->getMessage());
}
}
//More methods, nothing of interest ...
}
Here is a sample usage:
$db = new Database();
$result = $db->query("SELECT * FROM `pages`"); //Contains at least one entry
echo $result->num_rows; //Returns "0"
exit;
How come this is not accurate? Other values from result object are accurate, such as "field_count".
Possible Bug: http://www.php.net/manual/en/mysqli-result.num-rows.php#104630
Code is from source above (Johan Abildskov):
$sql = "valid select statement that yields results";
if($result = mysqli-connection->query($sql, MYSQLI_USE_RESULT))
{
echo $result->num_rows; //zero
while($row = $result->fetch_row())
{
echo $result->num_rows; //incrementing by one each time
}
echo $result->num_rows; // Finally the total count
}
Could also validate with the Procedural style:
/* determine number of rows result set */
$row_cnt = mysqli_num_rows($result);
I had the same problem and found the solution was to put:
$result->store_result();
..after the execution of the $query and before
echo $result->num_rows;
This could be normal behavior when you disable buffering of the result rows with MYSQLI_USE_RESULT
Disabling the buffer means that it`s up to you to fetch, store and COUNT the rows.
You should use the default flag
$this->connection->query($query, MYSQLI_STORE_RESULT);
Equivalent of
$this->connection->query($query)
Related
I'm stuck on this problem for a while now and looking for helpful suggestions.
$resultset = $connection->multi_query($sql);
pseudo:
IF $resultset > 0 (--> if the sql query returned at least one result) {
// do something
}
now the problem is with the pseudo part, i have tried to the follows:
if($resultset > 0) // takes no effect
if($resultset->num_rows > 0) // Notice: Trying to get property of non-object
I have to use multi_query so mysqli_query/mysqli_fetch_array is not a solution
thanks for the hints....
Please try:
if($connection->multi_query($sql))
{
//sample query taken from php manual, see link below
do {
/* store first result set */
if ($result = $connection->store_result()) {
while ($row = $result->fetch_row()) {
printf("%s\n", $row[0]);
}
$result->free();
}
/* print divider */
if ($connection->more_results()) {
printf("-----------------\n");
}
} while ($connection->next_result());
}
else
{
//handle error
echo mysqli_error ( $connection );
}
If you check out the documentation of multi query (here), you will see that the function returns a boolean.
Source code also taken from php manual.
multi_query() returns a boolean that indicates whether the first query was successful, it doesn't return a mysqli_result object.
You have to call the store_result() method to get the first result set.
$resultset = $connection->store_result();
To get subsequent result sets you use more_results() and next_result().
See the examples in the documentation.
What's the best way to verify mysql executed successfully and then returned a result when you CANNOT use the following code:
$db = dbConnect();
//begin prepared statements to search db
$stmt = $db->prepare("SELECT email,authentication,email_confirm,externalid,password,id, admin FROM users WHERE email=?");
$stmt->bind_param('s',$email);
$stmt->execute();
$result = $stmt->get_result();
if (!$result){
//error statement
} if (!(mysqli_num_rows($result)==0)){
//action to perform
} else {
// no result returned
}
I was using get_result numerous times in my scripts, and my hosting provider doesn't have mysqlnd driver so I have to rewrite a lot of code. I know I am limited to bind_result and fetch(), but I need a little help rewriting the code since my mindset is stuck in the way I first did it.
I'm also using mysqli and not PDO.
The Mysqli fetch() function will return one of 3 values:
TRUE - Success. Data has been fetched
FALSE - Error occurred
NULL - No more rows/data exists or data truncation occurred
This means you can set your query like this:
$db = dbConnect();
$query = "SELECT email,authentication,email_confirm,externalid,password,id, admin FROM users WHERE email=?";
$stmt = $db->prepare();
$stmt->bind_param('s',$email);
$stmt->execute();
$stmt->bind_result($email,$auth,$email_confirm,$externalid,$password,$id,$admin);
// Will only execute loop if returns true
$record_count = 0;
while($result = $stmt->fetch())
{
// Increment counter
$record_count++;
// Do something with bound result variables
echo("Email is $email");
}
// After the loop we either ran out of results or had an error
if($result === FALSE)
{
echo("An error occurred: " . $db->error());
}
elseif($record_count == 0)
{
echo("No records exist.");
}
I've used PDO in my PHP application. But I have problem with fetch() function. Whenever I count the result of fetch(), it tells me there is something in resultset. But when I want to show them, it has nothing to show.
try
{
$sql = "SELECT id,salt FROM tbl_admin WHERE username = ? AND password = ? LIMIT 1";
$q = $db->prepare($sql);
$q->execute(array($username,$password));
$rows = $q->columnCount();
if ($rows > 0)
{
$r = $q->fetch(PDO::FETCH_BOTH);
echo(count($r).'<br />'); // Prints 1
print_r($r); // Nothing to print ...
die();
}
else
{
die('error');
}
}
catch(PDOException $e)
{
echo $e->getMessage();
}
May you help me please?
You're counting the number of columns, not the number of rows.
$rows = $q->columnCount();
This should be
$rows = $q->rowCount();
That said, rowCount is for UPDATE, INSERT, or DELETE queries. So that isn't the problem here.
Firstly should also be checking if $q->execute returns true or false.
Secondly you should be checking if $q->fetch returns true or false.
Given your code
$r = $q->fetch(PDO::FETCH_BOTH);
echo(count($r).'<br />'); // Prints 1
Try the following.
echo(count(false));
You'll notice that this also outputs 1.
So the solution is, that you need to check the return value of $q->fetch before assuming it returned a valid row.
So, I've been learning PDO. So far, I am not at all impressed, honestly, due to the large amount of code needed to do small tasks. However, I am willing to convert nonetheless if I can get my code to be efficient and reusable.
My question is this: can I make this code any more efficient? By efficient, I mean both A) take up less lines, and B) run faster. I am worried that I am going about this all wrong. However, due to the lack of a num_rows() function, I can't think of a better way.
try
{
$sth = $dbh->prepare("SELECT * FROM table_name");
$sth->execute();
if (count($result = $sth->fetchAll()))
{
foreach ($result as $value)
{
// Rows returned! Loop through them.
}
}
else
{
// No rows returned!
}
}
catch (PDOException $e)
{
// Exception!
}
Is this written properly?
As far as my research has shown, no. There is no way to rewrite this code more concisely or logically--the way it stands is entirely optimized. :) It's easy to use, so that's definitely not a bad thing!
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
$sql = "SELECT COUNT(*) FROM table_name";
if ($res = $conn->query($sql))
{
/* Check the number of rows that match the SELECT statement */
$res->fetchColumn(); //This will give you the number of rows selected//
}
Make a general function that does that, and all you need to do is send a select count based on your needs. You can make in more general by dividing the $select to more variables.
function countRows($select)
{
if ($res = $conn->query($select))
{
/* Check the number of rows that match the SELECT statement */
return $res->fetchColumn(); //This will give you the number of rows selected//
}
}
No, you need to use PDO's rowCount method.
try
{
$sth = $dbh->prepare("SELECT * FROM table_name");
$sth->execute();
if ($sth->rowCount() > 0)
{
while ($result = $sth->fetch())
{
// Rows returned! Loop through them.
}
}
else
{
// No rows returned!
}
}
catch (PDOException $e)
{
// Exception!
}
I'm using this code:
$mysqli = new mysqli(...);
$sql = file_get_contents("my_sql_file.sql");
$result = $mysqli->multi_query($sql);
if (!$result)
report_error(); //my function
while ($mysqli->more_results()) {
$result = $mysqli->next_result();
if (!$result)
report_error();
}
However the 'while' loop in the code above turned out to be an infinite loop. Anything wrong?
Actually your code doesn't really make sense. The proper way to handle multiqueries is the following (see php manual)
if ($mysqli->multi_query($query)) {
do {
// store first result set
if ($result = $mysqli->store_result()) {
while ($row = $result->fetch_row()) {
// do something with the row
}
$result->free();
}
else { error_report(); }
} while ($mysqli->next_result());
}
else { error_report(); }
The code provided in the question reaches to an infitie loop because "If your second or late query returns no result or even if your query is not a valid SQL query, more_results(); returns true in any case.", see this note on php.net: http://us3.php.net/manual/en/mysqli.multi-query.php#104076
And further more, mysqli_more_results always returns true in the code because the results are not discarded, must call mysqli_store_results to discard result after each call to mysqli_next_result. See: http://us3.php.net/manual/en/mysqli.multi-query.php#91677
There is no official way to catch all errors when executing MySQL text (multi-commands separated by semicolons) by mysqli_multi_query. The function mysqli_multi_query will stop execution when it faces a bad SQL command, so it is only possible to catch the first error (no matter where the error occurs, in the first SQL command or any other SQL command in the SQL text).
Related to Jon's answer to this question: When does mysqli_multi_query stop execution?
And as noted in http://www.php.net/manual/en/mysqli.multi-query.php#106126 The first error can be catched by scanning mysqli_next_result coz: $mysqli->next_result() will return false if it runs out of statements OR if the next statement has an error.
Finally the answer is that results must be discarded after calling to mysqli_next_result using mysqli_store_result:
$mysqli = new mysqli(...);
$sql = file_get_contents("my_sql_file.sql");
$result = $mysqli->multi_query($sql);
if (!$result)
report_error(); //my function
while ($mysqli->more_results()) {
$result = $mysqli->next_result();
//important to make mysqli_more_results false:
$discard = $mysqli->store_result();
if (!$result)
report_error();
}