Is it possible to get cause of error from CDbException?

Assume the following exception arising due to an INSERT INTO that violated a constraint:

CDbException Object


    [message:protected] => CDbCommand failed to execute the SQL statement: SQLSTATE[23505]: Unique violation: 7 ERROR:  duplicate key value violates unique constraint "location__region_location_id_key"

    [string:private] => 

    [code:protected] => 0

    [file:protected] => /Users/rawtaz/Sites/.../library/yii-1.1.3.r2247/framework/db/CDbCommand.php

    [line:protected] => 228

    [trace:private] => ...


I would like to be able to handle this situation gracefully by trapping the exception, checking if the problem is a duplicate key violation, and if so either fire off another query or simply just ignore the conflict.

So my question is; Is there a cleaner way to inspect the exception and retrieve some kind of code for what the actual/detailed cause of the exception is, other than to parse the error message? Indeed the message contains an error code, but parsing it isn’t the cleanest and most reliable way of doing this.

I do know that MySQL have INSERT IGNORE INTO and REPLACE INTO, but they are not of interest whatsoever because they are MySQL-specific and thereby does not work with other databases.

Obviously I can do a SELECT before this query and fire the insert only if there was no result from the select, but that’s another story. For now I would like to do this insert first of all, and then handle any problems that arise during the query.



   // Try to insert


catch (CDbException $e)


  // Do something else (eg update record)


This does nothing to examine what the cause of the error was/what type of error the exception is wraps, which is what my post is all about. But thanks anyway!

Here’s a little follow-up in case anyone is interested. I didn’t find that I could get anything out of CDbException, but the following is close to it:

$insertCommand = $model->getCommandBuilder()->createSqlCommand($sql,$baseParams+$relParams);

try {


} catch(CDbException $e) {

	// Here's a way to get to the error code for the statement in question.

	// These codes are standardized ANSI SQL "SQLSTATE" error codes.

	$sqlErrorCode = $insertCommand->pdoStatement->errorCode();

	// And to get to the class part of it, simple grab the two first characters.

	// The class should be the same regardless of DB vendor, while the rest of the code can differ.

	// For example one particular error was reported by PostgreSQL as 23505 but MySQL only said 23000.

	$sqlErrorCodeClass = substr($sqlErrorCode, 0, 2);


I see, I thought the CDbExcpetion object would be enough. Maybe it should be extended in order to get the pdo error code?

// I created a ticket for this issue.

echo $e->errorInfo[1];

//this will dispay error code