how to execute multiple statements in loop - php

Hallo I have several queries to execute, all returning independent resultsets:
select * from table;
call procedureA(par1);
call procedureB(par2);
I would like to execute them within a loop to perform other operations:
$queries = array("select * from table;", "call procedureA(par1);", "call procedureB(par2);");
foreach($queries as $query) {
$res=$db->query($query);
// do something here with the query result
someFunction($res);
}
The first statement runs fine; at the second iteration, it stops stating that $res is a non object:
Call to a member function ... on a non-object
Apart from using mysqli_multi_query(), in which way could I loop execute multiple queries?
UPDATE I removed $res->close(); from the code sample since it was misleading and ininfluent for the issue.
UPDATE2 - SOLUTION
For anyone's sake, here is a complete working code:
$queries = array(
"CALL procedureA(par1)"
,"CALL procedureB()"
, "Select * from tableC"
);
// Open connection
$db = new mysqli(
$config['host']
,$config['user']
,$config['pwd']
,$config['dbname']
);
foreach($queries as $query) {
if ($res instanceof mysqli_result) {
$res->free();
}
$res=$db->query($query);
// do something with the query
echo getHtmlTable($res);
// free current result
$res->free();
// free subsequent resultset (es. the one with OK/ERR sp call status)
while ($db->next_result()) {
//free each result.
$res = $db->use_result();
if ($res instanceof mysqli_result) {
$res->free();
}
}
}

There is nothing special in running queries in a loop.
There will be no difference, either if you write two queries just one after another, or run them in a loop. So, generally speaking, a couple of queries run in a loop is no different from a couple of queries run in order just like in all our scripts.
The only possible problem a query itself. Say, a stored procedure call always return at least two resultsets. And no other query can be run until all resultsets get retrieved.
So, as a quick-and-dirty solution a line like this could be added
while ($db->next_result()) {}
at the bottom of the loop to clean up all the resultsets possibly remained in a queue after the query execution.
It qould be also highly convenient to turn on error reporting for mysqli, to make you aware of all the mysql error occurred. Having that, you would have added such error message to your question (Which is "Commands out of sync"). To do so, add this line before mysqli connect:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

$r->close();
should be
$res->close();
You are referencing a non existent object ($r).
The execution of multiple queries depends of a server configuration. But aside from thas. This would be better to use transactions (that depending of the effect of those stored procedures, of course)

Related

Checking if sql query has any results in PHP

I'm trying to check if an sql query brings back any results in PHP, I've tried using mysql_num_rows($res) but I keep getting an error saying that the function expected parameter to be a resource but it is instead getting an object.
I've attached the relevant code here
$dsn = "mysql://$username:$password#$host/$dbName";
require_once('MDB2.php');
$db =& MDB2::connect($dsn);
if(PEAR::isError($db)){
    die($db->getMessage());
}
$sql=//sql query
$res =& $db->query($sql);
if(PEAR::isError($res)){
    die($res->getMessage());
}
$resultsFound = false;
if (mysql_num_rows($res)>0){
while($row=$res->fetchRow()){
//insert results here
}
} else {
echo "<br><h2>Sorry, invalid input</h2>";
}
I'm sure the solution is fiendlishly simple but I'm new to php and sql and would really appreciate your help!
Maybe this one helps?
https://pear.php.net/manual/en/package.database.mdb2.intro-fetch.php
You could use fetchAll() to fetch all results - count() on the response of fetchAll() should do the trick for you.
After you've built up your functionality, I suggest you migrate to some newer stuff, you should not use MDB2 anymore - it's deprecated stuff.
https://www.php.net/manual/en/pdo.query.php may be the more modern way to use PHP with mysql.
Otherwise use https://www.php.net/manual/en/mysqli.query.php - you can also retrieve the number of datasets in there.

How does MySQL transaction works and When to rollback?

i wonder how does transaction work.
Question is do I need to rollback if any error/exception occurs, where the Exception will be thrown and never reach the commit() call? If so why and how? and what rollback does exactly?
consider the followings PHP code (some Java code does similar things like so):
public function deleteAll():void{
$stmt = $this->con->prepare(
'DELETE FROM dd WHERE 1'
);
$this->con->begin_transaction();
if(!$stmt->execute()){
throw new Exception($stmt->error);
}
$this->con->commit();
}
public function insert(array $list):void{
$stmt = $this->con->prepare(
'INSERT INTO dd(cc) VALUES(?)'
);
$stmt->bind_param('s', $v);
$this->con->begin_transaction();
foreach($list as $v){
if(!$stmt->execute()){
throw new Exception($stmt->error);
}
}
$this->con->commit();
}
Note:
$this->con is the mysqli connection object (not using PDO, although different but PDO and mysqli will do similar thing like above).
database is MySQL, table using InnoDB engine.
Some people code shows they catch the Exception and do rollback. But I did not since the commit() is never executed if Exception is thrown. Then this let me wonder why does it need to rollback at all.
My assumption is if there are multiple queries to perform at once like the following:
public function replaceAllWith(array $list):void{
$this->con->begin_transaction();
try{
//do both previous queries at once
$this->deleteAll();
$this->insert($list);
$this->con->commit();
}catch(Exception $e){
//error
$this->con->rollback();
}
}
but then it still cannot rollback because each method/function is done and committed by different method and different transaction.
Second Question: Do I do each transaction in each method call, or only invoke transaction in the 'boss/parent' function which only call and coordinate 'subordinate/helper' functions to do work?
Not sure if I'm asking the right questions.
Database Transaction is confusing, many online resources show only the procedural process (commit only or then immediately rollback which make no differences to normal direct query) without OO concepts involved. Please any pros guide and give some advice. tq.

PDO - Catch if any of these queries returns an empty result

I am using Medoo (a PHP DB framework using PDO) with PDO::ERRMODE_EXCEPTION enabled. I have some queries in a try and catch block and I want to throw an exception if any of those queries return an empty result.
PS: $database->get() is a simple PDO SELECT returning a single row. I don't think it's relevant and I think my example applies also to PDO without frameworks.
try {
$q1 = $database->get(..);
$q2 = $database->get(..);
$q3 = $database->get(..);
$q4 = $database->get(..);
} catch (PDOException $e) {
die ("There was an error in a query.");
}
Right now I get into the catch block only if there is an error in the query, like I try to select a table that doesn't exist. I want to find the optimal way to avoid checking if every single query doesn't return an empty result manually, like I don't want to do this:
if (!$q1) { echo "No result"; }
if (!$q2) { echo "No result"; }
...
Is there a more generic approach?
Your logic is wrong, an Exception is an event that occurs during program execution that disrupts normal flow.
Query that returns an empty result set is not disrupting normal flow of your program, because that query executed successfully.
If you think that it's a good idea to use exceptions in order to signal that an empty result is returned, you have to throw that exception.
Eloquent, which is an ORM used by Laravel contains a method called firstOrFail and findOrFail which perform what you're after.
Your option is to either create such a method for Medoo or use a proper ORM such as Doctrine or Eloquent that can help you achieve such behavior out of the box.

Stored procedure errors in CakePHP

Any idea how to call a stored procedure in CakePHP?
$results = $this->query('call p2');
echo $results;
I keep getting this error though:
Error: 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.
I've done this within a transaction to ensure that no other instance of the procedure is called inbetween:
$this->begin();
$this->query("CALL procedure();");
$result = $this->query("SELECT something");
$this->commit();
Your problem may be that you're calling:
$this->query('call p2');
Where you should be calling:
$this->query('call p2()');
as procedures are much like functions.
you should you open and close parentheses
$results = $this->query('call p2()');
echo $results;

How to properly handle errors from PDO fetch()?

The doc for error handling for fetch() seems unclear and I haven't found an answer anywhere after a lot of searching. A common usage model for fetch as shown in the doc is:
while ( $row = $stmt->fetch() ) {
// do something with $row
}
The PHP doc at http://www.php.net/manual/en/pdostatement.fetch.php says:
In all cases, FALSE is returned on failure.
What does "failure" mean? An error? A failure to fetch more rows? My question is: when fetch() returns FALSE, what is best practice to detect errors? It seems like after the loop I need to distinguish between an error case and the "no more rows" case.
Should I call $stmt->errorCode() and see if it's '00000' ?
To handle query errors (sql errors not occurs on fetch) and more generaly PDO error you should try using PDO::ERRMODE_EXCEPTION.
Moreover the PdoStatement returned by query() implement Traversable , so you can skip the use of fetch() for simple query :
try {
$db = new PDO('sqlite:mydb.db');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Set Errorhandling to Exception
foreach($db->query("SELECT...") as $row)
{
//Do domething
}
$db = null; // "Disconnect"
}
catch (PDOException $err) {
//Handling query/error
}
An execption will be thrown if query encounter an error (not fetch()).
Fetch will always return false when it reach the end of your result set.
fetch() will return false when there's no more data to be fetched. There could also be other case where there truly is a failure, e.g. mysql died or the connection was lost while doing the fetch loop. But generally speaking, that sort of "real" failure is fairly rare, and you'll most often get "false because there's no more data available".
If you're truly paranoid about writing error handling, then by all means, put an sql error code check after the while loop to catch the cases when something really did blow up.

Categories