I've got a (example) Oracle Stored Procedure:
CREATE OR REPLACE FUNCTION EXCEPTION_TEST
RETURN NUMBER
AS
BEGIN
raise_application_error(-20500, 'This is the exception text I want to print.');
END;
and I call it in PHP with PDO with the following code:
$statement = $conn->prepare('SELECT exception_test() FROM dual');
$statement->execute();
The call of the function works perfectly fine, but now I want to print the Exception text only.
I read somewhere, that you should not use try and catch with PDO. How can I do this?
You have read that you shouldn't catch an error to report it.
However, if you want to handle it somehow, it's all right to catch it.
Based on the example from my article on handling exception in PDO,
try {
$statement = $conn->prepare('SELECT exception_test() FROM dual');
$statement->execute();
} catch (PDOException $e) {
if ($e->getCode() == 20500 ) {
echo $e->getmessage();
} else {
throw $e;
}
}
Here you are either getting your particular error or re-throwing the exception back to make it handled the usual way
You check the execute response and get the error, for example, like this:
if ($statement->execute() != true) {
echo $statement->errorCode();
echo $statement->errorInfo();
}
You can find more options at the PDO manual.
Related
I perfectly understand the nuances of the (try/throw/catch) block.
What I don't understand is:
If we gonna use an IF (or any control structure) inside our try block anyway in order to test if a condition is met, only then, 'throw' an exception if the results of that test is false, then... in my opinion: throw/generate an exception is useles; because if a condition is not met, we can simply print an error message, call a function, instantiate a class, redirect to another location, etc.
Another story would be, if for instance, a variable was not initialized, we enclose that variable inside a try{} block, echo the variable, and from that point onward, everything will be handle by the catch() block because the try block raises an error; and since the try/catch blocks talk each other, the catch block will catch every error that was originated from his corresponding try block. However, you can set a custom error message inside yout try block (optional).
What I've read so far:
every results from searching: if vs. try
I do see the difference.
But I can not understand why some people choose try/throw/catch over if...else...switch...while... etc.
As far I can see, try/throw/catch can be used for debugging, though.
One benefit of exceptions over if/then is that you can wrap try/catch around a large block of code. It will be triggered if an error happens anywhere in the block.
try {
$db = db_open();
$statement = $db->prepare($sql);
$result = $statement->execute($params);
} catch (Exception $e) {
die($e->getMessage());
}
With if/then, you would have to perform a test at each step.
$db = db_open();
if (!$db) {
die(db_connect_error());
}
$statement = $db->prepare($sql);
if (!$statement) {
die(db_error($db));
}
$result = $statement->execute($params);
if (!$result) {
die(db_error($db));
}
As you said, it's a lot of overhead to throw an exception inside a try/catch block and catch it immediately.
try {
if (...) {
// good, do no throw
} else {
throw new Exception();
}
} catch ($e) {
// handle exception
}
This should be replaced by:
if (...) {
// good
} else {
// handle error, no exception
}
Exceptions are useful because they bubble up. So imagine if you have this code instead:
function bla() {
try {
tryToDoSomething();
} catch ($e) {
// handle error
}
}
function tryToDoSomething() {
if ($somethingNotAvailable) {
throw new Exception();
}
doSomething();
}
In this case, the function that defines the try/catch is NOT the one throwing the exception. tryToDoSomething() does not know how to handle the errors so it will let parent methods to take care of it. The exception can bubble up the call stack until someone catches it and handles the error. That's how exceptions can actually be useful :)
I am connecting to MySQL through PDO with Zend\Db from ZF2. How can I report the last errorInfo()?
Here's what I have:
$sqlWriter = new Sql($this->getAdapter());
$insert = $sqlWriter->insert('table_name')->columns(array_keys($data))->values($data);
$stmt = $sqlWriter->prepareStatementForSqlObject($insert);
try {
$stmt->execute();
$object->id = $this->getAdapter()->driver->getLastGeneratedValue();
} catch (\Exception $e) {
//
// HOW CAN I display errorInfo() here?
//
throw new Exception\Exception('Unable to insert record...');
}
I have tried calling methods on the adapter, driver, statement, platform, result, etc... But all to no avail...
EDIT: I found that I can get the info I am looking for by posting the following at the top of the catch block:
$pdoException = $e->getPrevious();
var_dump($pdoException);
I'll leave the question open however since it would be good to know how to execute PDO::errorInfo() directly.
This question already has answers here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(2 answers)
Closed 2 years ago.
I started using OO-MySQLi after procedural MySQL and I have a problem.
In production environment my system displays all errors as a custom page.
MySQLi errors is an "error" too and I want catch them, but in documentation described only one way to do this:
if (!$mysqli->query("SET a=1")) {
exit('An error occurred: ' . $mysqli->error);
}
(just for example).
This is a very bad way, because in my system I'm doing many things when error occurred, like logging, calling events, etc.
Of course, I can extend mysqli class, for example:
class myMysqli {
public function __construct(/* ... */)
{
parent::__construct(/* ... */);
}
public function query(/* .. */)
{
parent::query(/* ... */);
if($this->errno !== 0)
{
// An error occurred
}
}
}
$mysqli = new myMysqli(/* ... */);
$mysqli->query(/* ... */);
But this way I need to extend almost ALL methods where error can occur.
Moreover, MySQLi provides prepared statements (mysqli_stmt class) that has its own errors!
Can you know a better way to handle MySQLi errors?
Thank you in advance.
Added
About exceptions:
Do I understand correctly that with exceptions I need do something like this:
try {
$mysqli->query(/* ... */);
} catch (Exception $e) {
// An error occurred
}
But this is similar to
if(!$mysqli->query(/* ... */))
{
// An error occured
}
What a difference?
First of all, your old approach was wrong.
exit('An error occurred: ' . $mysqli->error);
is a bad practice in general and shouldn't be used with mysqli as well.
What you really want is error/exception handler. Where you can do whatever things like logging, calling events, showing pages.
Exception is better than regular error - so, set your mysqli in exception mode as shown in other answer, and then catch all the errors in error handler. While try..catch have to be used only when you have a distinct particular action to handle the error.
I use the try...catch method like this...
try {
// get result of record from 'id'
$query = "SELECT * FROM models WHERE id =$id";
$result = $mysqli->query($query);
if (!$result) {
throw new Exception($mysqli->error());
}
$row = $result->fetch_array();
}
catch (Exception $e)
{
echo "We are currently experiencing issues. Please try again later.";
echo $e->getMessage();
}
finally
{
$result->free();
}
Does that help at all?
You use 'try' to test a condition and throw an exception if it returns true (!$result). And use 'catch' to catch everything else that might just happen!
I am trying to implement transactions to Kohana but it seems to be not so easy as in Spring/Java.
So far I found this code to try but I don't know how to replace the part (no errors)
DB::query('START TRANSACTION');
// sql queries with query builder..
if (no errors)
DB::query('COMMIT');
else
DB::query('ROLLBACK');
How do I make the if clause?
Normally transactions are handled as such:
DB::query('START TRANSACTION');
try {
//do something
DB::query('COMMIT');
} catch (Exception $e) {
DB::query('ROLLBACK');
}
What this means is if everything succeeds within the try block, great. If any part of it fails then it won't reach the commit and will jump to the catch block, which contains the rollback. You can add more error handling within the catch if you wish, even throw a new exception of your own or throw the same exception you caught.
Just wrap everything in a try/catch block:
DB::query('START TRANSACTION');
try {
// sql queries with query builder..
DB::query('COMMIT');
} catch (Database_Exception $e) {
DB::query('ROLLBACK');
}
DB errors are converted to exceptions:
DB::query('START TRANSACTION');
try {
// sql queries with query builder..
DB::query('COMMIT');
}
catch($e)
{
$this->template->body = new View('db_error');
$this->template->body->error = 'An error occurred ...';
DB::query('ROLLBACK');
}
If you're using Kohana 3:
$db = Database::instance();
$db->begin();
try
{
// Do your queries here
$db->commit();
}
catch (Database_Exception $e)
{
$db->rollback();
}
I have a page on my website (high traffic) that does an insert on every page load.
I am curious of the fastest and safest way to (catch an error) and continue if the system is not able to do the insert into MySQL. Should I use try/catch or die or something else. I want to make sure the insert happens but if for some reason it can't I want the page to continue to load anyway.
...
$db = mysql_select_db('mobile', $conn);
mysql_query("INSERT INTO redirects SET ua_string = '$ua_string'") or die('Error #10');
mysql_close($conn);
...
Checking the documentation shows that its returns false on an error. So use the return status rather than or die(). It will return false if it fails, which you can log (or whatever you want to do) and then continue.
$rv = mysql_query("INSERT INTO redirects SET ua_string = '$ua_string'");
if ( $rv === false ){
//handle the error here
}
//page continues loading
This can do the trick,
function createLog($data){
$file = "Your path/incompletejobs.txt";
$fh = fopen($file, 'a') or die("can't open file");
fwrite($fh,$data);
fclose($fh);
}
$qry="INSERT INTO redirects SET ua_string = '$ua_string'"
$result=mysql_query($qry);
if(!$result){
createLog(mysql_error());
}
You can implement throwing exceptions on mysql query fail on your own. What you need is to write a wrapper for mysql_query function, e.g.:
// user defined. corresponding MySQL errno for duplicate key entry
const MYSQL_DUPLICATE_KEY_ENTRY = 1022;
// user defined MySQL exceptions
class MySQLException extends Exception {}
class MySQLDuplicateKeyException extends MySQLException {}
function my_mysql_query($query, $conn=false) {
$res = mysql_query($query, $conn);
if (!$res) {
$errno = mysql_errno($conn);
$error = mysql_error($conn);
switch ($errno) {
case MYSQL_DUPLICATE_KEY_ENTRY:
throw new MySQLDuplicateKeyException($error, $errno);
break;
default:
throw MySQLException($error, $errno);
break;
}
}
// ...
// doing something
// ...
if ($something_is_wrong) {
throw new Exception("Logic exception while performing query result processing");
}
}
try {
mysql_query("INSERT INTO redirects SET ua_string = '$ua_string'")
}
catch (MySQLDuplicateKeyException $e) {
// duplicate entry exception
$e->getMessage();
}
catch (MySQLException $e) {
// other mysql exception (not duplicate key entry)
$e->getMessage();
}
catch (Exception $e) {
// not a MySQL exception
$e->getMessage();
}
if you want to log the error etc you should use try/catch, if you dont; just put # before mysql_query
edit :
you can use try catch like this; so you can log the error and let the page continue to load
function throw_ex($er){
throw new Exception($er);
}
try {
mysql_connect(localhost,'user','pass');
mysql_select_db('test');
$q = mysql_query('select * from asdasda') or throw_ex(mysql_error());
}
catch(exception $e) {
echo "ex: ".$e;
}
Elaborating on yasaluyari's answer I would stick with something like this:
We can just modify our mysql_query as follows:
function mysql_catchquery($query,$emsg='Error submitting the query'){
if ($result=mysql_query($query)) return $result;
else throw new Exception($emsg);
}
Now we can simply use it like this, some good example:
try {
mysql_catchquery('CREATE TEMPORARY TABLE a (ID int(6))');
mysql_catchquery('insert into a values(666),(418),(93)');
mysql_catchquery('insert into b(ID, name) select a.ID, c.name from a join c on a.ID=c.ID');
$result=mysql_catchquery('select * from d where ID=7777777');
while ($tmp=mysql_fetch_assoc($result)) { ... }
} catch (Exception $e) {
echo $e->getMessage();
}
Note how beautiful it is. Whenever any of the qq fails we gtfo with our errors. And you can also note that we don't need now to store the state of the writing queries into a $result variable for verification, because our function now handles it by itself. And the same way it handles the selects, it just assigns the result to a variable as does the normal function, yet handles the errors within itself.
Also note, we don't need to show the actual errors since they bear huge security risk, especially so with this outdated extension. That is why our default will be just fine most of the time. Yet, if we do want to notify the user for some particular query error, we can always pass the second parameter to display our custom error message.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
I am not sure if there is a mysql version of this but adding this line of code allows throwing mysqli_sql_exception.
I know, passed a lot of time and the question is already checked answered but I got a different answer and it may be helpful.
$sql = "INSERT INTO customer(FIELDS)VALUES(VALUES)";
mysql_query($sql);
if (mysql_errno())
{
echo "<script>alert('License already registered');location.replace('customerform.html');</script>";
}
To catch specific error in Mysqli
$conn = ...;
$q = "INSERT INTO redirects (ua_string) VALUES ('$ua_string')";
if (mysqli_query($conn, $q)) {
// Successful
}
else {
die('Mysqli Error: '.$conn->error); // Show Error Complete Description
}
mysqli_close($conn);
Use any method described in the previous post to somehow catch the mysql error.
Most common is:
$res = mysql_query('bla');
if ($res===false) {
//error
die();
}
//normal page
This would also work:
function error() {
//error
die()
}
$res = mysql_query('bla') or error();
//normal page
try { ... } catch {Exception $e) { .... } will not work!
Note: Not directly related to you question but I think it would much more better if you display something usefull to the user. I would never revisit a website that just displays a blank screen or any mysterious error message.
$new_user = new User($user);
$mapper = $this->spot->mapper("App\User");
try{
$id = $mapper->save($new_user);
}catch(Exception $exception){
$data["error"] = true;
$data["message"] = "Error while insertion. Erron in the query";
$data["data"] = $exception->getMessage();
return $response->withStatus(409)
->withHeader("Content-Type", "application/json")
->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}
if error occurs, you will get something like this->
{
"error": true,
"message": "Error while insertion. Erron in the query",
"data": "An exception occurred while executing 'INSERT INTO \"user\" (...) VALUES (...)' with params [...]:\n\nSQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: \"default\"" }
with status code:409.