I have a query to a program that I am running on my iSeries. I understand that sometimes this query will fill occasionally because there are no records to select. Every time the query fails, it logs to php.log as:
PHP Warning: db2_fetch_assoc(): Fetch Failure in /www/zendsvr6/htdocs/views/hp1110.php on line 82
I am looking for a solution to prevent this error from logging. I know that I can disable PHP error logging already. I do not want to disable the logging.
Here is a sample of the code:
$stmt = db2_prepare($conn, $sql);
if (!$stmt) {
$code = db2_stmt_error();
$msg = db2_stmt_errormsg();
// TODO in production do not display SQL. Log it instead.
die("Failed to prepare $sql. Reason: $code $msg");
} //(if (!$result))
$bound1 = db2_bind_param($stmt, 1, "item", DB2_PARAM_IN);
$bound2 = db2_bind_param($stmt, 2, "house", DB2_PARAM_IN);
$bound3 = db2_bind_param($stmt, 3, "counter", DB2_PARAM_INOUT);
if (!$bound1 || !$bound2 || !$bound3) {
die("Failed to bind one or more parameters.");
} //(if (!$bound1 || !$bound2 || !$bound3) )
// execute with bound parameters.
$result = db2_execute($stmt);
if (!$result) {
$code = db2_stmt_error();
$msg = db2_stmt_errormsg();
// TODO in production do not display SQL. Log it instead.
die("Failed to execute $sql. Reason: $code $msg");
} //(if (!$result))
if (!$counter) {
return array();//
} //(if (!$counter))
// success. create array to return to caller.
$rows = array();
while (($row = db2_fetch_assoc($stmt)) != false) {
$rows[] = $row;
} //(while...)
// this returns it to the caller.
return $rows;
} //(getParts)
Thanks!
If the db2 driver logs that every time you try to fetch from a result which has no(more) rows available, then you can avoid it by fetching only exactly the number of rows returned:
$total_rows = db2_num_rows($stmt);
for ($i = 0; $i < $total_rows; $i++) {
$row = db2_fetch_assoc($stmt);
... do stuff ...
}
I really haven't found normal example of PHP file where MySQL transactions are being used. Can you show me simple example of that?
And one more question. I've already done a lot of programming and didn't use transactions. Can I put a PHP function or something in header.php that if one mysql_query fails, then the others fail too?
I think I have figured it out, is it right?:
mysql_query("SET AUTOCOMMIT=0");
mysql_query("START TRANSACTION");
$a1 = mysql_query("INSERT INTO rarara (l_id) VALUES('1')");
$a2 = mysql_query("INSERT INTO rarara (l_id) VALUES('2')");
if ($a1 and $a2) {
mysql_query("COMMIT");
} else {
mysql_query("ROLLBACK");
}
The idea I generally use when working with transactions looks like this (semi-pseudo-code):
try {
// First of all, let's begin a transaction
$db->beginTransaction();
// A set of queries; if one fails, an exception should be thrown
$db->query('first query');
$db->query('second query');
$db->query('third query');
// If we arrive here, it means that no exception was thrown
// i.e. no query has failed, and we can commit the transaction
$db->commit();
} catch (\Throwable $e) {
// An exception has been thrown
// We must rollback the transaction
$db->rollback();
throw $e; // but the error must be handled anyway
}
Note that, with this idea, if a query fails, an Exception must be thrown:
PDO can do that, depending on how you configure it
See PDO::setAttribute
and PDO::ATTR_ERRMODE and PDO::ERRMODE_EXCEPTION
else, with some other API, you might have to test the result of the function used to execute a query, and throw an exception yourself.
Unfortunately, there is no magic involved. You cannot just put an instruction somewhere and have transactions done automatically: you still have to specific which group of queries must be executed in a transaction.
For example, quite often you'll have a couple of queries before the transaction (before the begin) and another couple of queries after the transaction (after either commit or rollback) and you'll want those queries executed no matter what happened (or not) in the transaction.
I think I have figured it out, is it right?:
mysql_query("START TRANSACTION");
$a1 = mysql_query("INSERT INTO rarara (l_id) VALUES('1')");
$a2 = mysql_query("INSERT INTO rarara (l_id) VALUES('2')");
if ($a1 and $a2) {
mysql_query("COMMIT");
} else {
mysql_query("ROLLBACK");
}
<?php
// trans.php
function begin(){
mysql_query("BEGIN");
}
function commit(){
mysql_query("COMMIT");
}
function rollback(){
mysql_query("ROLLBACK");
}
mysql_connect("localhost","Dude1", "SuperSecret") or die(mysql_error());
mysql_select_db("bedrock") or die(mysql_error());
$query = "INSERT INTO employee (ssn,name,phone) values ('123-45-6789','Matt','1-800-555-1212')";
begin(); // transaction begins
$result = mysql_query($query);
if(!$result){
rollback(); // transaction rolls back
echo "transaction rolled back";
exit;
}else{
commit(); // transaction is committed
echo "Database transaction was successful";
}
?>
As this is the first result on google for "php mysql transaction", I thought I'd add an answer that explicitly demonstrates how to do this with mysqli (as the original author wanted examples). Here's a simplified example of transactions with PHP/mysqli:
// let's pretend that a user wants to create a new "group". we will do so
// while at the same time creating a "membership" for the group which
// consists solely of the user themselves (at first). accordingly, the group
// and membership records should be created together, or not at all.
// this sounds like a job for: TRANSACTIONS! (*cue music*)
$group_name = "The Thursday Thumpers";
$member_name = "EleventyOne";
$conn = new mysqli($db_host,$db_user,$db_passwd,$db_name); // error-check this
// note: this is meant for InnoDB tables. won't work with MyISAM tables.
try {
$conn->autocommit(FALSE); // i.e., start transaction
// assume that the TABLE groups has an auto_increment id field
$query = "INSERT INTO groups (name) ";
$query .= "VALUES ('$group_name')";
$result = $conn->query($query);
if ( !$result ) {
$result->free();
throw new Exception($conn->error);
}
$group_id = $conn->insert_id; // last auto_inc id from *this* connection
$query = "INSERT INTO group_membership (group_id,name) ";
$query .= "VALUES ('$group_id','$member_name')";
$result = $conn->query($query);
if ( !$result ) {
$result->free();
throw new Exception($conn->error);
}
// our SQL queries have been successful. commit them
// and go back to non-transaction mode.
$conn->commit();
$conn->autocommit(TRUE); // i.e., end transaction
}
catch ( Exception $e ) {
// before rolling back the transaction, you'd want
// to make sure that the exception was db-related
$conn->rollback();
$conn->autocommit(TRUE); // i.e., end transaction
}
Also, keep in mind that PHP 5.5 has a new method mysqli::begin_transaction. However, this has not been documented yet by the PHP team, and I'm still stuck in PHP 5.3, so I can't comment on it.
Please check which storage engine you are using. If it is MyISAM, then Transaction('COMMIT','ROLLBACK') will not be supported because only the InnoDB storage engine, not MyISAM, supports transactions.
When using PDO connection:
$pdo = new PDO('mysql:host=localhost;dbname=mydb;charset=utf8', $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // this is important
]);
I often use the following code for transaction management:
function transaction(Closure $callback)
{
global $pdo; // let's assume our PDO connection is in a global var
// start the transaction outside of the try block, because
// you don't want to rollback a transaction that failed to start
$pdo->beginTransaction();
try
{
$callback();
$pdo->commit();
}
catch (Exception $e) // it's better to replace this with Throwable on PHP 7+
{
$pdo->rollBack();
throw $e; // we still have to complain about the exception
}
}
Usage example:
transaction(function()
{
global $pdo;
$pdo->query('first query');
$pdo->query('second query');
$pdo->query('third query');
});
This way the transaction-management code is not duplicated across the project. Which is a good thing, because, judging from other PDO-ralated answers in this thread, it's easy to make mistakes in it. The most common ones being forgetting to rethrow the exception and starting the transaction inside the try block.
I made a function to get a vector of queries and do a transaction, maybe someone will find out it useful:
function transaction ($con, $Q){
mysqli_query($con, "START TRANSACTION");
for ($i = 0; $i < count ($Q); $i++){
if (!mysqli_query ($con, $Q[$i])){
echo 'Error! Info: <' . mysqli_error ($con) . '> Query: <' . $Q[$i] . '>';
break;
}
}
if ($i == count ($Q)){
mysqli_query($con, "COMMIT");
return 1;
}
else {
mysqli_query($con, "ROLLBACK");
return 0;
}
}
I had this, but not sure if this is correct. Could try this out also.
mysql_query("START TRANSACTION");
$flag = true;
$query = "INSERT INTO testing (myid) VALUES ('test')";
$query2 = "INSERT INTO testing2 (myid2) VALUES ('test2')";
$result = mysql_query($query) or trigger_error(mysql_error(), E_USER_ERROR);
if (!$result) {
$flag = false;
}
$result = mysql_query($query2) or trigger_error(mysql_error(), E_USER_ERROR);
if (!$result) {
$flag = false;
}
if ($flag) {
mysql_query("COMMIT");
} else {
mysql_query("ROLLBACK");
}
Idea from here: http://www.phpknowhow.com/mysql/transactions/
One more procedural style example with mysqli_multi_query, assumes $query is filled with semicolon-separated statements.
mysqli_begin_transaction ($link);
for (mysqli_multi_query ($link, $query);
mysqli_more_results ($link);
mysqli_next_result ($link) );
! mysqli_errno ($link) ?
mysqli_commit ($link) : mysqli_rollback ($link);
I'm quite new with PHP and need help coding an add script for my web site. I have coded the delete and update side and they are working perfectly. Basically, on secdtions of my web site you can add values to several text boxes and what I want is that when you click on 'Add' this will add the details from the textboxes to the database. To do this I am using PHP, Jquery and Ajax.
This is the code I have for the update script:
public function update($tableName,$fieldArray,$fieldValues,$rowId,$updateCondition)
{
// Get PDO handle
$PDO = new SQL();
$dbh = $PDO->connect(Database::$serverIP, Database::$serverPort, Database::$dbName, Database::$user, Database::$pass);
// Build query
$this->sql = 'UPDATE '.$tableName.' SET ';
$fieldCount = count($fieldArray);
for ($i = 0; $i < $fieldCount; $i++){
// If the index is at the last field...
$lastRow = $fieldCount - 1;
if ($i != $lastRow) {
// Add a comma
$this->sql .= $fieldArray[$i].'=:'.$fieldArray[$i].', ';
} else {
// Dont add a comma
$this->sql .= $fieldArray[$i].'=:'.$fieldArray[$i].' ';
}
}
// If row id is null (if we don't know the row id)...
if ($rowId == null || $rowId == "null") {
// Then use the update condition in it's place
$this->sql .= 'WHERE '.$updateCondition.' ';
} else {
// Use the ID
$this->sql .= 'WHERE Id = '.$rowId.' ';
}
try {
// Query
$stmt = $dbh->prepare($this->sql);
// Bind parameters
for ($i = 0; $i < $fieldCount; $i++){
$stmt->bindParam(':'.$fieldArray[$i].'', $fieldValues[$i]);
}
$stmt->execute();
$count = $stmt->rowCount();
echo $count.' row(s) affected by SQL: '.$stmt->queryString;
$stmt->closeCursor();
}
catch (PDOException $pe) {
echo 'Error: ' .$pe->getMessage(). 'SQL: '.$stmt->queryString;
die();
}
// Close connection
$dbh = null;
}
This is the part I am struggling to code, if you look at the code I have used for my update script.. I basically need something similiar to use for my 'add' script.
Any help will be much appreciated!!
Welcome to PHP! It is really a wonderful language :)
Try this:
<?php
public function insert($tableName,$fieldArray,$fieldValues)
{
$sql = "INSERT INTO " . $tableName . " (".implode(',', $fieldArray).") VALUES (".implode(',', $fieldValues).")";
// TODO: Execute $sql query
}
You should basically write out your functions and then at the end print out the resulting SQL statements it creates. Once you're able to see them from that level, you can try them in a query browser to see if you're constructing them correctly.
Can somebody help me in converting the following code written using if-else to try/catch. Also let me know is trycatch needed in this case or if-else is apt
$results = mysql_query($query);
if(mysql_num_rows($results)!=0)
{
while(($result = mysql_fetch_row($results))!=FALSE)
{
$res ="DELETE FROM table1 WHERE id ='".$result['id']."'";
if(mysql_query($res)==false)
{
echo mysql_error();
exit;
}
}
echo $res ="DELETE FROM table2 WHERE id ='".$id."'";
if(mysql_query($res)!==false)
{
header("Location:list.php?m=4");
}
else
{
echo mysql_error();
exit;
}
}
else
{
echo "Error";
}
try...catch only makes any sense if your functions are throwing exceptions. If they don't, there's nothing to catch. I'd start with this as a refactoring:
$results = mysql_query($query);
if (!mysql_num_rows($results)) {
echo 'No results!';
exit;
}
$ids = array();
while (($result = mysql_fetch_row($results)) !== false) {
$ids[] = $result['id'];
}
$ids = array_map('mysql_real_escape_string', $ids);
$query = "DELETE FROM table1 WHERE id IN ('" . join("','", $ids) . "')";
if (!mysql_query($query)) {
echo mysql_error();
exit;
}
$query = "DELETE FROM table2 WHERE id = '$id'";
if (!mysql_query($query)) {
echo mysql_error();
exit;
}
header("Location: list.php?m=4");
exit;
This can still be improved a lot, but it's already an improvement over your spaghetti logic. If you're seriously interested in properly using exceptions, you should first move on to properly using functions for repetitive tasks (like the error, exit parts), then possibly restructure the whole thing into classes and objects, and lastly use exceptions to communicate between the now nested layers. Maybe start using a PHP framework to get a feeling for the whole thing.
Putting exceptions into the above code would be hardly more than a goto, but just for illustrative purposes:
try {
$results = mysql_query($query);
if (!mysql_num_rows($results)) {
throw new Exception('No results!');
}
$ids = array();
while (($result = mysql_fetch_row($results)) !== false) {
$ids[] = $result['id'];
}
$ids = array_map('mysql_real_escape_string', $ids);
$query = "DELETE FROM table1 WHERE id IN ('" . join("','", $ids) . "')";
if (!mysql_query($query)) {
throw new Exception(mysql_error());
}
$query = "DELETE FROM table2 WHERE id = '$id'";
if (!mysql_query($query)) {
throw new Exception(mysql_error());
}
header("Location: list.php?m=4");
exit;
} catch (Exception $e) {
echo 'ERROR: ' . $e->getMessage();
exit;
}
from the sound of it, it seems you think try/catch and if-else as the same behaviour. That is not the case. Try catch is used to prevent an exception from making the application crash or to handle exceptions gracefully, and to perform logging and giving user feedback. If-else (else if) is used to check the internal state of your application, and perform different actions accordingly.
Generally, a try-catch is less efficient than if there is a switch-case or else-if approach to the problem.
function get_total_adults()
{
$sql = "SELECT SUM(number_adults_attending) as number_of_adults FROM is_nfo_rsvp";
$result = mysql_query($sql) or die(mysql_error());
$array = mysql_fetch_assoc($result);
return $array['number_of_adults'];
}
I know there is a way to write this with less code. I'm just looking for the best way (without using something like ezSQL).
function get_total_adults() {
$sql = 'SELECT SUM(number_adults_attending) FROM is_nfo_rsvp';
$result = mysql_query($sql) or die(mysql_error());
// I'd throw a catchable exception (see below) rather than die with a MySQl error
return mysql_result($result, 0);
}
As to how I'd rather handle errors:
function get_total_adults() {
$sql = 'SELECT SUM(number_adults_attending) FROM is_nfo_rsvp';
$result = mysql_query($sql);
if (!$result) {
throw new Exception('Failed to get total number of adults attending');
}
return mysql_result($result, 0);
}
try {
$total_adults = get_total_adults();
} catch(Exception $ex) {
die('Whoops! An error occurred: ' . $ex->getMessage());
// or even better, add to your template and dump the template at this point
}
// continue code
You can drop the "as number_of_adults" part of the query and use mysql_result.
You could also try refactormycode.com