4

Maybe this question has already been asked, but I don't really know how to search for it:

I have the postgres-table "customers", and each customer has it's own unique name. In order to achieve this, I added an unique-constraint to this column.

I access the table with php.

When the user now tries to create a new customer, with a name that has already been taken, the database says "Integrity Constraint Violation", and php throws an error.

What I want to do is to show an error in the html-input-field: "Customer-Name already taken" when this happens.

My question is how I should do this.

Should I catch the PDO-Exception, check if the error-Code is "UNIQUE VIOLATION", and than display a message according to the Exception-Message, or should I check for duplicate names with an additional statement before I even try to insert a new row?

What is better practice? Making a further sql-statement, or catching and analyzing error-codes.

EDIT: I'm using transactions, and I'm catching any exception in order to rollback. The question is, if I should filter out Unique-violations so they don't lead to a rollback.

EDIT2: If I'm using the exception-method, I would have to analyse the exception-message in order to ensure that the unique-constraint really belongs to the "name"-column.

This is everything I get from the exception:

["23505",7,"FEHLER: doppelter Schlüsselwert verletzt Unique-Constraint <customers_name_unique>\nDETAIL: Schlüssel <(name)=(test)> existiert bereits."]

The only way to get information about the column is to check if "customers_name_unique" exists (it's the name of the unique-constraint).

But as you can also see, the message is in german, so the output depends on the system / might be able to change.

maja
  • 17,250
  • 17
  • 82
  • 125
  • Maybe you should look at: http://stackoverflow.com/questions/7719039/php-duplicate-checking-before-insert – jmarceli Jul 16 '13 at 12:24

5 Answers5

7

You should catch the PDO exception.

It quicker to let the database fail, than to look up and see if the record already exists.

This also makes the application "less aware" of the business logic in the database. When you tell the database about the unique index that's really a business logic, and since the database is handling that particular logic it's better to skip the same check in the other layers (the application).

Also when the database layer is handling the exception you avoid race conditions. If your application is checking for consistency then you may risk that another user adds the same record after the first application has checked that it's available.

Sven Tore
  • 967
  • 6
  • 29
  • The consistency-problem can't appear, as I won't remove the check-constraint from the database. The only problem would be, that in the rare case of a race-condition, the user would only get the Message "Unknown Error" instead of "Duplicate Customer Name" – maja Jul 16 '13 at 12:28
  • this one is good saves one `count(*)` but i have a doubt since he is using a transnational storage engine a rollback action may take which has a cost is it lesser than a `count(*)` earlier? – Arun Killu Jul 16 '13 at 12:31
  • the "check-constraint" is really just a workaround (unless you are using if for something else) for part of the problem. But I would suggest to implement as much logic as possible on the error handling, and then talk to the database as few times as possible (e.g. skip the statement to check for unique index) – Sven Tore Jul 16 '13 at 12:32
  • 1
    This answer makes no sense. Check http://stackoverflow.com/questions/935490/why-and-how-would-you-use-exceptions-in-this-sample-php-code Exceptions are for **EXCEPTIONAL** code that may happen which shouldn't normally occur. – Robert Jul 16 '13 at 13:39
2

The question doesn't really belong here but I'll answer you.

Exceptions are situations when something exceptional happens. It means that you shouldn't use them to handle situation that may happen oftenly. If you do it then it's like GOTO code. The better solution is to check previosly if there is any duplicate row. However, the solution with exceptions is easier so you need to decide if you want something to work or if you want to have something that works written as it should be.

Robert
  • 19,800
  • 5
  • 55
  • 85
  • 1
    I disagree. It's better to have a normal flow at the "higher" level and then catch exceptions. This will make quicker code, since if you don't the lower level will have to do the same check again. If that verification is cpu heavy you can make a really inefficient app if you have several levels (services/storage/classes all count as levels in this case) – Sven Tore Jul 16 '13 at 12:26
  • 1
    Exceptions may cause a lot of problems in debugging. Moreover, exceptions leave objects in an inconsistent state. If you use them too often you can have a lot errors that are hard to track. Obviosly you can use finally block which was made to handle such situations but not everyone knows about it. Even famous Linus Torvalds said that exceptions are crap. Moreover, google in google go resigned from using exceptions check in google why. Exceptions can be also very expensive in terms of perfomace if you don't use them wisely. It's your right to disagree but it doesn't mean you're right ;P – Robert Jul 16 '13 at 13:29
1

I would catch the exception, because (thanks to concurrency) that can happen anyway, even if you check with an extra query beforehand.

Thilo
  • 257,207
  • 101
  • 511
  • 656
0

Errors are bad, I'd rather check if name does not exist before adding it. Well you should still check if no errors on insert, to avoid situation when concurrent scripts are trying to insert same name (there is a little time between checking for existance and insert, since its not a transaction).

mr. Pavlikov
  • 982
  • 5
  • 7
0

On SAVE check if Exists (by a simple field, in your case: the Constraint column). If affirmative - show notification to the user about duplication. But don't force the DB server to return you exceptions.

mihai
  • 2,746
  • 3
  • 35
  • 56