That's not PDO's fault, it's inherent to PostgreSQL's transaction management. See:
PostgreSQL doesn't roll the transaction back, but it sets it to an aborted state where it can only roll back, and where all statements except ROLLBACK
report an error:
ERROR: current transaction is aborted, commands ignored until end of transaction block
(I'm surprised not to find this referred to in the official documentation; think I'll need to write a patch to improve that.)
So. When you try/catch and swallow the exception in PDO, you're trapping a PHP-side exception, but you're not changing the fact that the PostgreSQL transaction is in an aborted state.
If you wanted to be able to swallow exceptions and keep on using the transaction, you must create a SAVEPOINT
before each statement that might fail. If it fails, you must ROLLBACK TO SAVEPOINT ...;
. If it succeeds you may RELEASE SAVEPOINT ...;
. This imposes extra overhead on the database for transaction management, adds round-trips, and burns through transaction IDs faster (which means PostgreSQL has to do more background cleanup work).
It is generally preferable to instead design your SQL so it won't fail under normal circumstances. For example, you can validate most constraints client-side, treating the server side constraints as a second level of assurance while trapping most errors client-side.
Where that's impractical, make your application fault tolerant, so it can retry a failed transaction. Sometimes this is necessary anyway - for example, you can't generally use savepoints to recover from deadlocks transaction aborts or serialization failures. It can also be useful to keep failure-prone transactions as short as possible, doing just the minimum work required, so you have less to keep track of and repeat.
So: Where possible, instead of swallowing an exception, run failure-prone database code in a retry loop. Make sure your code keeps a record of the information it needs to retry the whole transaction on error, not just the most recent statement.
Remember, any transaction can fail: The DBA might restart the database to apply a patch, the system might run out of RAM due to a runaway cron job, etc. So failure tolerant apps are a good design anyway.
Props to you for at least using PDO exceptions and handling exceptions - you're way ahead of most devs already.