@Test(expectedExceptions = RuntimeException.class)
 public void translateNotNullViolationBadMessage() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getSQLState()).thenReturn("23502");
   when(serverErrorMessage.getTable()).thenReturn("mytable");
   when(serverErrorMessage.getMessage()).thenReturn("xxxyyyzzzz");
   //noinspection ThrowableResultOfMethodCallIgnored
   PostgreSqlExceptionTranslator.translateNotNullViolation(new PSQLException(serverErrorMessage));
 }
 @Test
 public void translateCheckConstraintViolation() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getTable()).thenReturn("entity");
   when(serverErrorMessage.getConstraint()).thenReturn("entity_column_chk");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateCheckConstraintViolation(
           new PSQLException(serverErrorMessage));
   assertEquals(e.getMessage(), "Unknown enum value for attribute 'column' of entity 'entity'.");
 }
 @Test
 public void translateInvalidIntegerExceptionDate() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getMessage())
       .thenReturn("invalid input syntax for type date: \"str1\"");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateInvalidIntegerException(
           new PSQLException(serverErrorMessage));
   assertEquals(e.getMessage(), "Value [str1] of this entity attribute is not of type [DATE].");
 }
 @Test
 public void translateDependentObjectsStillExistNoDoubleQuotes() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getSQLState()).thenReturn("2BP01");
   when(serverErrorMessage.getDetail())
       .thenReturn("constraint my_foreign_key_constraint on table xxx depends on table yyy");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateDependentObjectsStillExist(
           new PSQLException(serverErrorMessage));
   assertEquals(e.getMessage(), "Cannot delete entity 'xxx' because entity 'yyy' depends on it.");
 }
 @Test
 public void translateUndefinedColumnException() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getSQLState()).thenReturn("42703");
   when(serverErrorMessage.getMessage())
       .thenReturn("Undefined column: 7 ERROR: column \"test\" does not exist");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateUndefinedColumnException(
           new PSQLException(serverErrorMessage));
   assertEquals(e.getMessage(), "Undefined column: 7 ERROR: column \"test\" does not exist");
 }
 @Test
 public void translateReadonlyViolationNoDoubleQuotes() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getMessage())
       .thenReturn("Updating read-only column attr of table entity with id [abc] is not allowed");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateReadonlyViolation(
           new PSQLException(serverErrorMessage));
   assertEquals(
       e.getMessage(),
       "Updating read-only attribute 'attr' of entity 'entity' with id 'abc' is not allowed.");
 }
 @Test
 public void translateNotNullViolationNoDoubleQuotes() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getSQLState()).thenReturn("23502");
   when(serverErrorMessage.getTable()).thenReturn("xxx");
   when(serverErrorMessage.getMessage())
       .thenReturn("null value in column yyy violates not-null constraint");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateNotNullViolation(
           new PSQLException(serverErrorMessage));
   assertEquals(e.getMessage(), "The attribute 'yyy' of entity 'xxx' can not be null.");
 }
 @Test
 public void translateUniqueKeyViolation() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getSQLState()).thenReturn("23505");
   when(serverErrorMessage.getTable()).thenReturn("mytable");
   when(serverErrorMessage.getDetail()).thenReturn("Key (mycolumn)=(myvalue) already exists.");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateUniqueKeyViolation(
           new PSQLException(serverErrorMessage));
   assertEquals(
       e.getMessage(),
       "Duplicate value 'myvalue' for unique attribute 'mycolumn' from entity 'mytable'.");
 }
 @Test
 public void translateForeignKeyViolation() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getSQLState()).thenReturn("23503");
   when(serverErrorMessage.getTable()).thenReturn("mytable");
   when(serverErrorMessage.getDetail()).thenReturn("... (mycolumn) ... (myvalue) ...");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateForeignKeyViolation(
           new PSQLException(serverErrorMessage));
   assertEquals(
       e.getMessage(),
       "Unknown xref value 'myvalue' for attribute 'mycolumn' of entity 'mytable'.");
 }
 @Test
 public void translateDependentObjectsStillExistMultipleDependentTables() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getSQLState()).thenReturn("2BP01");
   when(serverErrorMessage.getDetail())
       .thenReturn(
           "constraint my_foreign_key_constraint on table \"myTable\" depends on table \"myDependentTable\"\nconstraint myOther_foreign_key_constraint on table \"myTable\" depends on table \"myOtherDependentTable\"");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateDependentObjectsStillExist(
           new PSQLException(serverErrorMessage));
   assertEquals(
       e.getMessage(),
       "Cannot delete entity 'myTable' because entities 'myDependentTable, myOtherDependentTable' depend on it.");
 }
 @Test
 public void translateForeignKeyViolationStillReferenced() {
   ServerErrorMessage serverErrorMessage = mock(ServerErrorMessage.class);
   when(serverErrorMessage.getSQLState()).thenReturn("23503");
   when(serverErrorMessage.getTable()).thenReturn("mytable");
   when(serverErrorMessage.getDetail())
       .thenReturn("Key (mycolumn)=(myvalue) is still referenced from table \"mytable\"");
   //noinspection ThrowableResultOfMethodCallIgnored
   MolgenisValidationException e =
       PostgreSqlExceptionTranslator.translateForeignKeyViolation(
           new PSQLException(serverErrorMessage));
   assertEquals(
       e.getMessage(),
       "Value 'myvalue' for attribute 'mycolumn' is referenced by entity 'mytable'.");
 }
  @Override
  public DBException wrapIfNeededOrReturnNull(final Throwable t) {
    final Boolean referencingTableHasDLMLevel;

    if (DBException.isSQLState(t, PG_SQLSTATE_Referencing_Record_Has_Wrong_DLM_Level)) {
      referencingTableHasDLMLevel = true;
    } else if (DBException.isSQLState(t, PG_SQLSTATE_Referencing_Table_Has_No_DLM_LEvel)) {
      referencingTableHasDLMLevel = false;
    } else {
      return null;
    }

    //
    // parse the exception detail and extract the infos
    final SQLException sqlException = DBException.extractSQLExceptionOrNull(t);
    Check.errorUnless(
        sqlException instanceof PSQLException,
        "exception={} needs to be a PSQLExcetion",
        sqlException);

    final PSQLException psqlException = (PSQLException) sqlException;
    final ServerErrorMessage serverErrorMessage = psqlException.getServerErrorMessage();
    Check.errorIf(
        serverErrorMessage == null,
        "ServerErrorMessage of PSQLException={} may not be null",
        psqlException);

    final String detail = serverErrorMessage.getDetail();
    Check.errorIf(
        Check.isEmpty(detail, true),
        "DETAIL ServerErrorMessage={} from of PSQLException={} may not be null",
        serverErrorMessage,
        psqlException);

    final String[] infos = extractInfos(detail);

    //
    // the the "real" tables and column from the extracted lowercase infos
    final IADTableDAO adTableDAO = Services.get(IADTableDAO.class);

    final I_AD_Table referencedTable = adTableDAO.retrieveTable(infos[0]);
    Check.errorIf(
        referencedTable == null,
        "Unable to retrieve an AD_Table for referencedTable name={}",
        infos[0]);

    final I_AD_Table referencingTable = adTableDAO.retrieveTable(infos[2]);
    Check.errorIf(
        referencingTable == null,
        "Unable to retrieve an AD_Table for referencingTable name={}",
        infos[2]);

    final I_AD_Column referencingColumn =
        adTableDAO.retrieveColumn(referencingTable.getTableName(), infos[3]);
    Check.errorIf(
        referencingTable == null,
        "Unable to retrieve an AD_Column for referencingTable name={} and referencingColumn name={}",
        infos[2],
        infos[3]);

    return new DLMReferenceException(
        t,
        TableReferenceDescriptor.of(
            referencingTable.getTableName(),
            referencingColumn.getColumnName(),
            referencedTable.getTableName(),
            Integer.parseInt(infos[1])),
        referencingTableHasDLMLevel);
  }