From a practical view there are two types of error messages when using transactions:
-"Normal" errors: in this case, the application should stop the current process and show an error message to the user.
-Deadlock errors. This shows that the deadlock detection process of PostgreSQL found a circle of dependency, and broke it by rolling back the transaction in one of the processes, which gets this error msg. In this case, the application should not stop, but repeat the transaction.
I found no discrete way to find out which case are we dealing with. This interface doesn't support error codes, so we have to search for patterns in the message text.
Here is an example for PostgreSQL database connection class. It throws a PostgresException on "normal" errors, and DependencyException in the case of a broken deadlock, when we have to repeat the transaction.
postgres.php:
function__construct($msg) {parent::__construct($msg); }
}
classDependencyExceptionextendsPostgresException{
function__construct() {parent::__construct("deadlock"); }
}
classpg{
public static$connection;
private static functionconnect() {self::$connection= @pg_connect("dbname=foodb user=foouser password=foopasswd");
if (self::$connection===FALSE) {
throw(newPostgresException("Can't connect to database server."));
}
}
public static functionquery($sql) {
if (!isset(self::$connection)) {self::connect();
}$result= @pg_query(self::$connection,$sql);
if ($result===FALSE) {$error=pg_last_error(self::$connection);
if (stripos($error,"deadlock detected") !==false) throw(newDependencyException());
throw(newPostgresException($error.": ".$sql));
}$out= array();
while ( ($d=pg_fetch_assoc($result)) !==FALSE) {$out[] =$d;
}
return$out;
}
}?>
It should be used in this way:
test.php:
do {$repeat=false;
try {pg::query("begin");
...$result=pg::query("SELECT * FROM public.kitten");
...pg::query("commit");
}
catch (DependencyException $e) {pg::query("rollback");$repeat=true;
}
} while ($repeat);?>
The normal errors should be caught at the frontend.
Tamas