I have a simple program that should fire two exceptions, the second being a rethrow of the first. However, only the first exception is being thrown.
This is my code:
In dao.php
function executeSQLC($cn, $sql) {
$rs = odbc_exec($cn, $sql);
if($rs == false) {
throw new Exception("ex1: ".odbc_error());
}
return $rs;
}
In bean.php
include("dao.php");
$conn = odbc_connect("xxx", "xxxx", "xxxx");
odbc_autocommit($conn, FALSE);
$sql ="invalid sql";
try {
executeSQLC($conn, $sql);
odbc_commit($conn);
odbc_close($conn);
} catch(Exception $e) {
odbc_rollback($conn);
throw new Exception("ex2: ".$e->getMessage(). " " .$sql);
}
I see "ex1", so i think the first exception, at the dao, is being thrown, however, i can't see "ex2" and the connection never gets rollbacked.
Thanks
Ok, some other code was calling/messing with the $sql variable, not sure that this was the cause, but things seem to be working now. Thanks folks.
Related
when executing the form, the data is not inserting. I have activated SQLITE3 and I am not skipping any type of error.
The echo of the try is to see what was wrong but nothing. I see everything right.
Does anyone help me?
$username = $_POST['nombre'];
$clave = $_POST['clave'];
$apenom = $_POST['apenom'];
try {
$bd = new SQLite3("test");
//preparamos la sentencia
echo "INSERT INTO usuarios (username,clave,apenom) VALUES ('$username','$clave','$apenom')";
$bd->exec("INSERT INTO usuarios (username,clave,apenom) VALUES ('$username','$clave','$apenom')");
/* while ($row = $resultado->fetchArray()) {
echo "{$row['username']} {$row['clave']} {$row['apenom']} \n";
} */
} catch (\Throwable $th) {
echo $th;
}
Do take the advice from the comments into account, database security is not something you should 'wing'...
As for a little help on setting up a connection and importantly debugging if anything goes wrong so you know what to fix, the following 'skeleton' might help:
<?php
try {
// connect to your database
$sqlite = new SQLite3('test.db');
}
catch (Exception $e) {
// if no connection could be established a exception is thrown
echo $e->getMessage();
}
// your query
$query = '...';
$result = $sqlite->query($query); // result object (FALSE on error)
if (!$result) {
// query failed for some reason...
echo $sqlite->lastErrorMsg();
} else {
// do something with result
}
If I have multiple queries on chain, on a structure based on IFs, like this:
$query1 = mysqli_query("query here");
if(!query1){
//display error
} else {
$query2 = mysqli_query("another query here");
if(!query2){
//display error
//rollback the query1
} else {
query3 = mysqli_query("yet again another query");
if(!query3) {
//display error
//rollback the query2
//rollback the query1
} else {
query4 = mysqli_query("eh.. another one");
if(!query4){
//display error
//rollback the query3
//rollback the query2
//rollback the query1
} else {
return success;
}
}
}
}
Is there a best way to rollback the previous query, if the next one fails?
Otherwise I'm gonna have the first 2 query successfull, which edited the database, but the 3° failed, so 3° and 4° didn't edit the dabatase, with the result of having it corrupted.
I thought about something like:
...
$query2 = mysqli_query("another query here");
if(!query2){
//display error
$rollback = mysqli_query("query to rollback query1");
} else {
query3 = mysqli_query("yet again another query");
if(!query3) {
//display error
$rollback = mysqli_query("query to rollback query2");
$rollback = mysqli_query("query to rollback query1");
} else {
...
But the above method grants even more chances to fail more queries.
Is there any other more effective methods?
This is how i would do it with mysqli:
Configure mysqli (somewehere at the begining of your application) to throw exceptions when a query fails.
mysqli_report(MYSQLI_REPORT_STRICT);
This way you will not need all the if .. elseif .. else.
$connection->begin_transaction();
try {
$result1 = $connection->query("query 1");
// do something with $result1
$result2 = $connection->query("query 2");
// do something with $result2
$result3 = $connection->query("query 3");
// do something with $result3
// you will not get here if any of the queries fails
$connection->commit();
} catch (Exception $e) {
// if any of the queries fails, the following code will be executed
$connection->rollback(); // roll back everything to the point of begin_transaction()
// do other stuff to handle the error
}
Update
Usually the user don't care about, why his action failed. If a query fails, it's never the users fault. It's either the fault of the developer or of the environment. So there shouldn't be a reason to render an error message depending on which query failed.
Note that if the users intput is the source of the failed query, then
you didn't validate the input properly
your queries are not injection safe (If the input can cause an SQL error it can also be used to compromise your DB.)
However - I don't say there can't be reasons - I just don't know any. So if you want your error message depend on which query failed, you can do the following:
$error = null;
$connection->begin_transaction();
try {
try {
$result1 = $connection->query("query 1");
} catch (Exception $e) {
$error = 'query 1 failed';
throw $e;
}
// do something with $result1
try {
$result2 = $connection->query("query 2");
} catch (Exception $e) {
$error = 'query 2 failed';
throw $e;
}
// do something with $result2
// execute more queries the same way
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
// use $error to find out which query failed
// do other stuff to handle the error
}
I have 2 DBs: 1 in MySQL and the other one on SQLite3.
I need to insert the same data into both. To achieve this by a Form, I'm making a PHP script, that has some issue.
Here below the code then the explanation on what's going on:
// MySQL
try {
$sql = new PDO($pdo_servername, $username, $password, $pdo_options);
$sql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$ret = $sql->exec($query);
if(!$ret){
echo $sql->lastErrorMsg();
} else {
echo "New record created successfully on MySQL DB";
}
} catch (PDOException $e) {
echo $sql . "<br>" . $e->getMessage();
}
$sql->close();
// SQLite
try {
$sqlite = new PDO($pdo_servername_sqlite3);
$sqlite->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$retlite = $sqlite->exec($query);
if(!$retlite){
echo $sqlite->lastErrorMsg();
} else {
echo "New record created successfully on SQLite3 DB";
}
} catch (PDOException $e) {
echo $sqlite . "<br>" . $e->getMessage();
}
$sqlite->close();
The MySQL works fine, while the SQLite3 doesn't even start.
Inverting the blocks, thus first SQLite3 then MySQL, the issue is inverted: the SQLite3 works fine and MySQL doesn't start.
I have not any error returned
I tried also to avoid any try-catch-finally, and I just wrote the code as simple it is, and I got the same identical situation.
Is it forbidden to open 2 PDO connections, to 2 different DBs?
Where is my mistake please?
Try this way, that is the only breakpoint where you really need try...catch:
// MySQL
try {
$sql = new PDO($pdo_servername, $username, $password, $pdo_options);
} catch (PDOException $e) {
echo 'MySQL connection failed: ' . "<br>" . $e->getMessage();
$sql = false;
}
// SQLite
try {
$sqlite = new PDO($pdo_servername_sqlite3);
} catch (PDOException $e) {
echo 'SQLite connection failed: '. "<br>" . $e->getMessage();
$sqlite = false;
}
if ($sql != false) {
$ret = $sql->exec($query);
if(!$ret){
echo $sql->lastErrorMsg();
} else {
echo "New record created successfully on MySQL DB";
}
$sql->close();
}
if ($sqlite != false) {
$retlite = $sqlite->exec($query);
if(!$retlite){
echo $sqlite->lastErrorMsg();
} else {
echo "New record created successfully on SQLite3 DB";
}
$sqlite->close();
}
First of all I want to thank everybody contributed here :)
I would like to post the definitive working code, because some line, should also be changed, respect the above code.
Indeed the PDO method lastErrorMsg(); seems don't exist, and the same for the PDO method close(); It should be used errorInfo()in place of lastErrorMsg();and it's an array. While to close the DB connection: I read somewhere here on Stackoverflow that when the script execution ends, automatically PDO closes it, OR you need to destroy the object assign a null.
Because finally the code suggested by #Alex, with these small changes, was working, I was able to get the errors from PHP highlighting the above details.
Please here below the final working code, hoping that can be useful to any other had my same issue:
/**
* MySQL - try to open it. If it fails,
* it returns which error and continues the execution of the script
*/
try {
$sql = new PDO($pdo_servername, $username, $password, $pdo_options);
} catch (PDOException $e) {
echo 'MySQL connection failed: ' . "<br>" . $e->getMessage();
$sql = false;
}
/**
* SQLite - try to open it. If it fails,
* it returns which error and continues the execution of the script
*/
try {
$sqlite = new PDO($pdo_servername_sqlite3);
} catch (PDOException $e) {
echo 'SQLite connection failed: '. "<br>" . $e->getMessage();
$sqlite = false;
}
/**
* If the connection is made, it executes the Query
* If anything wrong with the Query insertion, an error is returned.
* The script continues
*/
if ($sql != false) {
$ret = $sql->exec($query);
if(!$ret){
print_r($sql->errorInfo()); // THIS is the valid method for PDO Exec and returns an array
} else {
echo "New record created successfully on MySQL DB";
}
}
if ($sqlite != false) {
$retlite = $sqlite->exec($query);
if(!$retlite){
print_r($sqlite->errorInfo()); // THIS is the valid method for PDO Exec and returns an array
} else {
echo "New record created successfully on SQLite3 DB";
}
}
/**
* Closes the DB Connections
*/
$sql = null;
$sqlite = null;
Thanks to all of you for your valid help. I very much appreciated it :)
I just switched to PDO from mySQLi (from mySQL) and it's so far good and easy, especially regarding prepared statements
This is what I have for a select with prepared statement
Main DB file (included in all pages):
class DBi {
public static $conn;
// this I need to make the connection "global"
}
try {
DBi::$conn = new PDO("mysql:host=$dbhost;dbname=$dbname;charset=utf8", $dbuname, $dbpass);
DBi::$conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
DBi::$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
echo '<p class="error">Database error!</p>';
}
And in my page:
try {
$sql = 'SELECT pagetitle, pagecontent FROM mypages WHERE pageid = ? LIMIT 1';
$STH = DBi::$conn->prepare($sql);
$STH->execute(array($thispageid)); // $thispageid is from a GET var
}
catch(PDOException $e) {
echo '<p class="error">Database query error!</p>';
}
if ($STH) { // does this really need an if clause for it self?
$row = $STH->fetch();
if (!empty($row)) { // was there found a row with content?
echo '<h1>'.$row['pagetitle'].'</h1>
<p>'.$row['pagecontent'].'</p>';
}
}
It all works. But am I doing it right? Or can I make it more simple some places?
Is using if (!empty($row)) {} an ok solution to check if there was a result row with content? Can't find other decent way to check for numrows on a prepared narrowed select
catch(PDOException $e) {
echo '<p class="error">Database query error!</p>';
}
I would use the opportunity to log which database query error occurred.
See example here: http://php.net/manual/en/pdostatement.errorinfo.php
Also if you catch an error, you should probably return from the function or the script.
if ($STH) { // does this really need an if clause for it self?
If $STH isn't valid, then it should have generated an exception and been caught previously. And if you had returned from the function in that catch block, then you wouldn't get to this point in the code, so there's no need to test $STH for being non-null again. Just start fetching from it.
$row = $STH->fetch();
if (!empty($row)) { // was there found a row with content?
I would write it this way:
$found_one = false;
while ($row = $STH->fetch()) {
$found_one = true;
. . . do other stuff with data . . .
}
if (!$found_one) {
echo "Sorry! Nothing found. Here's some default info:";
. . . output default info here . . .
}
No need to test if it's empty, because if it were, the loop would exit.
this ought to be simple, but it doesn't seem to be working for me. i have tested it with good and bad passwords. no matter what, it will not go into the else statement. i am not sure what i am missing
my code:
$mysqli = mysqli_connect("localhost", "joeuser", "somepass", "testDB");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
} else {
$sql = "SELECT * FROM login_info";
$res = mysqli_query($mysqli, $sql);
if ($res) {
while ($newArray = mysqli_fetch_array($res, MYSQLI_ASSOC)) {
$id = $newArray['first_name'];
$testField = $newArray['last_name'];
echo "The ID is ".$id." and the text is ".$testField."<br/>";
}
} else {
printf("Could not retrieve records: %s\n", mysqli_error($mysqli));
}
mysqli_free_result($res);
mysqli_close($mysqli);
}
If i send it a user and password that do exist it does the if statement fine, but if i send it a test for one that is not in the db it still won't do the else? why?
For successful SELECT, SHOW, DESCRIBE or EXPLAIN queries mysqli_query() will return a MySQLi_Result object.
A query is only not successful if some serious error occurred. Simply because a SELECT query didn't match any rows doesn't make the query unsuccessful. You'll still get a MySQLi_Result object back. You'll want to check with mysqli_num_rows whether the result set contains any rows.
BTW, save yourself some nesting:
if (!$something) {
exit;
}
// continue as usual
No need for an else here, since you're exiting anyway. Makes things simpler.
Like this:
if ($res) {
while ($newArray = mysqli_fetch_array($res, MYSQLI_ASSOC)) {
$id = $newArray['first_name'];
$testField = $newArray['last_name'];
echo "The ID is ".$id." and the text is ".$testField."<br/>";
}
}
if (!isset($id)) {
printf("Could not retrieve records: %s\n", mysqli_error($mysqli));
}