Validation and Output

Hi,

In the old sql script we had a validation ( just check if there is any invalid object in the database ), and after the validation if there is any invalid object we were printing the result with the ones that are invalid. This was really useful when you are running the script.

I partially fixed the problem using a precondition, and if there is any invalid object i just finish the execution of the script and i print the error message. But I would like to list the invalid objects also. Any Idea or suggestion ??

Current code:

  1. <preConditions onFailMessage=“There are invalid objects in the database!!” 

    onFail=“HALT” >

    <![CDATA[

    SELECT count(1)

    FROM all_objects alo

    WHERE status = ‘INVALID’

    AND alo.owner in

    (‘CIN’,‘NOPA’,‘ORC’,‘PRV’,‘SEC’,‘TIPI_OWNER’,‘TT’,‘ZON’);

    ]]>

    <![CDATA[

    SELECT alo.owner

    , alo.object_name

    , alo.status

    , alo.last_ddl_time

    FROM all_objects alo

    WHERE status = ‘INVALID’

    AND alo.owner in

    (‘CIN’,‘NOPA’,‘ORC’,‘PRV’,‘SEC’,‘TIPI_OWNER’,‘TT’,‘ZON’);

    ]]>

Thanks in advance

To get the problem object in the output message, you’ll probably need to write a custom precondition class. There is documentation on it at http://www.liquibase.org/documentation/preconditions.html 

Within a custom precondition, you have whatever flexibility you need both in what you are checking and the output.

Nathan

Thanks for your reply Nathan!

I’m trying to make it work, and looks good so far, but I would like to enable the logger, then will be easy to see what i’m doing. But I don’t know why I can’t see the log in debug level.

This is my code: 

  1. <preConditions onFailMessage="There are invalid objects in the database!!"
  2. onFail=“HALT”>

  3. <customPrecondition

  4. className=“nl.tele2.bos.liquibase.custom.preconditions.CustomBuildCheck”>

  5. <param name=“sql”
  6. value="SELECT count(1)
  7. FROM all_objects alo
  8. WHERE status = ‘INVALID’
  9. AND alo.owner in
  10. (‘BOS_RELEASE’,‘BIL’,‘BLIS’,‘CBSMIG’,‘COJO’,‘CMD_AGENT’,‘CIN’,‘NOPA’,‘ORC’,‘PRV’,‘SEC’,‘TIPI_OWNER’,‘TT’,‘ZON’)

  11. AND alo.OBJECT_NAME not like ‘TST%’
  12. AND alo.OBJECT_NAME not like ‘TEST%’
  13. AND ALO.OBJECT_NAME <> ‘ZON_ORBIT_LOG_PCK’
  14. AND ALO.OBJECT_NAME <> ‘ZON_TESTING_PCK’
  15. AND ALO.OBJECT_NAME <> ‘ZON_MONITORING_PCK’;"/>
  16. <param name=“sqlNames” value="SELECT alo.owner
  17. , alo.object_name
  18. , alo.status
  19. ,

  20. alo.last_ddl_time

  21. FROM all_objects alo
  22. WHERE status = ‘INVALID’
  23. AND

  24. alo.owner in
  25. (‘BOS_RELEASE’,‘BIL’,‘BLIS’,‘CBSMIG’,‘COJO’,‘CMD_AGENT’,‘CIN’,‘NOPA’,‘ORC’,‘PRV’,‘SEC’,‘TIPI_OWNER’,‘TT’,‘ZON’)

  26. AND alo.OBJECT_NAME not like ‘TST%’
  27. AND alo.OBJECT_NAME not like
  28. ‘TEST%’

  29. AND ALO.OBJECT_NAME <> ‘ZON_ORBIT_LOG_PCK’
  30. AND

  31. ALO.OBJECT_NAME <> ‘ZON_TESTING_PCK’
  32. AND ALO.OBJECT_NAME <>
  33. ‘ZON_MONITORING_PCK’

  34. ORDER BY alo.owner, alo.object_name;"/>
Java class:

  1. import liquibase.database.Database;
  2. import liquibase.database.DatabaseConnection;
  3. import liquibase.exception.CustomPreconditionErrorException;
  4. import liquibase.exception.CustomPreconditionFailedException;
  5. import liquibase.exception.DatabaseException;
  6. import liquibase.executor.ExecutorService;
  7. import liquibase.logging.LogFactory;
  8. import liquibase.logging.Logger;
  9. import liquibase.precondition.CustomPrecondition;
  10. import liquibase.statement.core.RawSqlStatement;
  11. import lombok.Getter;
  12. import lombok.Setter;
  13. /**
  14.  * CustomBuildCheck Precondition
  15.  *
  16.  *
  17.  *
  18.  *
  19.  *
  20.  * 
  21.  * @author Enric Ballo 
  22.  * @since Oct 24, 2014
  23.  */
  24. public class CustomBuildCheck implements CustomPrecondition {
  25.     
  26.     private final Logger logger = LogFactory.getInstance().getLog("CustomBuildCheck");
  27.     @Getter
  28.     @Setter
  29.     private String expectedResult;
  30.     @Getter
  31.     @Setter
  32.     private String sql;
  33.     @Getter
  34.     @Setter
  35.     private String sqlNames;
  36.     @Override
  37.     public void check(final Database database) throws CustomPreconditionFailedException, CustomPreconditionErrorException {
  38.         final DatabaseConnection connection = database.getConnection();
  39.         try {
  40.             logger.debug("CustomBuildCheck is executed...");
  41.             
  42.             final String result =
  43.                     ExecutorService.getInstance().getExecutor(database).queryForObject(
  44.                             new RawSqlStatement(getSql().replaceFirst(";$", "")), String.class);
  45.             if (result == null) {
  46.                 throw new CustomPreconditionFailedException("No rows returned from SQL Precondition");
  47.             }
  48.             
  49.             logger.debug("result is :"+result);
  50.             
  51.             if (!expectedResult.equals(result)) {
  52.                 
  53.                 logger.debug("We have some errors! ");
  54.                 // final String resultNames = ExecutorService.getInstance().getExecutor(database).queryForObject(new RawSqlStatement(getSqlNames().replaceFirst(";$", "")), String.class);
  55.                 throw new CustomPreconditionFailedException("SQL Precondition failed.  Expected '" + expectedResult + "' got '" + result
  56.                     + "'");
  57.             }
  58.         } catch (final DatabaseException e) {
  59.             throw new CustomPreconditionFailedException(e.getMessage());
  60.         }
  61.     }
  62. }

Result in the console:

  1. DEBUG 10/27/14 3:27 PM: liquibase: liquibase/changelogs/bos-incremental-changelog.xml: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Computed checksum for  as d41d8cd98f00b204e9800998ecf8427e
  2. DEBUG 10/27/14 3:27 PM: liquibase: liquibase/changelogs/bos-incremental-changelog.xml: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Running Changeset:liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo
  3. DEBUG 10/27/14 3:27 PM: liquibase: liquibase/changelogs/bos-incremental-changelog.xml: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Changeset liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo
  4. DEBUG 10/27/14 3:27 PM: liquibase: liquibase/changelogs/bos-incremental-changelog.xml: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Executing QUERY database command: SELECT count(1)     FROM all_objects alo     WHERE status = 'INVALID'     AND alo.owner in     ('BOS_RELEASE','BIL','BLIS','CBSMIG','COJO','CMD_AGENT','CIN','NOPA','ORC','PRV','SEC','TIPI_OWNER','TT','ZON')     AND alo.OBJECT_NAME not like 'TST%'     AND alo.OBJECT_NAME not like 'TEST%'     AND ALO.OBJECT_NAME <> 'ZON_ORBIT_LOG_PCK'     AND ALO.OBJECT_NAME <> 'ZON_TESTING_PCK'     AND ALO.OBJECT_NAME <> 'ZON_MONITORING_PCK'
  5. SEVERE 10/27/14 3:27 PM: liquibase: liquibase/changelogs/bos-incremental-changelog.xml: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Change Set liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo failed.  Error: Migration failed for change set liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo:
  6.      Reason:
  7.           liquibase/changelogs/bos-incremental-changelog.xml : There are invalid objects in the database!!
  8. liquibase.exception.MigrationFailedException: Migration failed for change set liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo:
  9.      Reason:
  10.           liquibase/changelogs/bos-incremental-changelog.xml : There are invalid objects in the database!!
  11.         at liquibase.changelog.ChangeSet.execute(ChangeSet.java:463)
  12.         at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:43)
  13.         at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:70)
  14.         at liquibase.Liquibase.update(Liquibase.java:195)
  15.         at liquibase.Liquibase.update(Liquibase.java:174)
  16.         at liquibase.integration.commandline.Main.doMigration(Main.java:997)
  17.         at liquibase.integration.commandline.Main.run(Main.java:170)
  18.         at liquibase.integration.commandline.Main.main(Main.java:89)
  19. Caused by: liquibase.exception.PreconditionFailedException: Preconditions Failed
  20.         at liquibase.precondition.core.PreconditionContainer.check(PreconditionContainer.java:220)
  21.         at liquibase.changelog.ChangeSet.execute(ChangeSet.java:449)
  22.         ... 7 more
  23. DEBUG 10/27/14 3:27 PM: liquibase: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Release Database Lock
  24. DEBUG 10/27/14 3:27 PM: liquibase: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Executing UPDATE database command: UPDATE BOS_RELEASE.DATABASECHANGELOGLOCK SET LOCKED = 0, LOCKEDBY = NULL, LOCKGRANTED = NULL WHERE ID = 1
  25. INFO 10/27/14 3:27 PM: liquibase: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Successfully released change log lock
  26. Unexpected error running Liquibase: Preconditions Failed
How shall i use the Logger ? do am I doing something wrong ?

Thanks in advance

Ok, I just fixed

Just if someone want to know the LogFactory should be like this:

  1.     private final Logger logger = LogFactory.getInstance().getLog("liquibase");

Glad you got it figured out. Thanks for letting us know.

Nathan

The easiest way with JdbcExecutor to query is to use a queryForList() method. If you want to specify the exact SQL, use executor.queryForList(new RawSqlStatement(YOUR_SQL) which will return a List of Maps containing the data from the result set.

Nathan

Great, thanks for sharing.

Nathan

I’m almost done, but i would like to know if there is a way to execute a query and get a list of results.

I was looking into JdbcExecutor class and i don’t have a clear idea how i can do that.

I would like to do this query when I have errors, and then display in the logs as a sever the list of all the object that are not working.

  1. SELECT    alo.owner
  2. , alo.object_name
  3. , alo.status
  4. , alo.last_ddl_time
  5. FROM all_objects alo
  6. WHERE status = 'INVALID'
  7. AND alo.owner in
  8. ('BOS_RELEASE','BIL','BLIS','CBSMIG','COJO','CMD_AGENT','CIN','NOPA','ORC','PRV','SEC','TIPI_OWNER','TT','ZON')
  9. AND alo.OBJECT_NAME not like 'TST%'
  10. AND alo.OBJECT_NAME not like 'TEST%'
  11. AND ALO.OBJECT_NAME <> 'ZON_ORBIT_LOG_PCK'
  12. AND ALO.OBJECT_NAME <> 'ZON_TESTING_PCK'
  13. AND ALO.OBJECT_NAME <> 'ZON_MONITORING_PCK'
  14. ORDER BY alo.owner, alo.object_name;

Thanks in advance,

I already have a solution for that I would like to share with you guys, maybe is useful for someone.

Java Class

  1. /**
  2.  * CustomBuildCheck Precondition
  3.  *
  4.  *
  5.  *
  6.  *
  7.  * 
  8.  * @author Enric Ballo (enric.ballo@tele2.com)
  9.  * @since Oct 24, 2014
  10.  */
  11. @Getter
  12. @Setter
  13. public class CustomBuildCheck implements CustomPrecondition {
  14.     private static final String LAST_DDL_TIME = "LAST_DDL_TIME";
  15.     /** Liquibase logger */
  16.     private final Logger logger = LogFactory.getInstance().getLog("liquibase");
  17.     /** the sql to execute */
  18.     private String sql;
  19.     /** the expected result */
  20.     private String expectedResult;
  21.     @SuppressWarnings("rawtypes")
  22.     @Override
  23.     public void check(final Database database) throws CustomPreconditionFailedException, CustomPreconditionErrorException {
  24.         try {
  25.             
  26.             logger.debug("CustomBuildCheck is executed...");
  27.             final List<Map> resultQuery =
  28.                     ExecutorService.getInstance().getExecutor(database).queryForList(
  29.                             new RawSqlStatement(getSql().replaceFirst(";$", "")));
  30.             if (resultQuery == null) {
  31.                 throw new CustomPreconditionFailedException("No rows returned from SQL Precondition");
  32.             }
  33.             final int size = resultQuery.size();
  34.             
  35.             logger.debug("result is :" + size);
  36.             logger.debug("expected result is :" + expectedResult);
  37.             
  38.             final Integer resultInteger = new Integer(size);
  39.             final Integer expectIntegerResult = new Integer(expectedResult);
  40.             if (!expectIntegerResult.equals(resultInteger)) {
  41.                 logger.debug("We have some errors! displaying the result");
  42.                 final StringBuilder invalidObject = new StringBuilder();
  43.                 
  44.                 int counter = 1;
  45.                 for (final Map map : resultQuery) {
  46.                     invalidObject.append("  " + counter + " )  ");
  47.                     for (final Map.Entry entry : map.entrySet()) {
  48.                         invalidObject.append(entry.getValue());
  49.                         
  50.                         //Avoid the last -
  51.                         if (!entry.getKey().equals(LAST_DDL_TIME)) {
  52.                             invalidObject.append(" - ");
  53.                         }
  54.                     }
  55.                     invalidObject.append("\n");
  56.                     counter++;
  57.                 }
  58.                 final StringBuilder message = new StringBuilder();
  59.                 message.append("\n");
  60.                 message.append("\n");
  61.                 message.append("\n");
  62.                 message.append("--------------------------------------------------------------------------------------------- \n");
  63.                 message.append("               ERROR - There are " + size + " invalid Objects in the Database \n");
  64.                 message.append("--------------------------------------------------------------------------------------------- \n");
  65.                 message.append("      OWNER - OBJECT NAME - STATUS - LAST DDL TIME \n");
  66.                 message.append("\n");
  67.                 message.append(invalidObject.toString());
  68.                 message.append("\n");
  69.                 message.append("--------------------------------------------------------------------------------------------- \n");
  70.                 message.append("\n");
  71.                 message.append("\n");
  72.                 throw new CustomPreconditionFailedException(message.toString());
  73.             }
  74.         } catch (final DatabaseException e) {
  75.             throw new CustomPreconditionFailedException(e.getMessage());
  76.         }
  77.     }
  78. }
ChangeLog file
  1. <customPrecondition

  2. className=“nl.tele2.bos.liquibase.custom.preconditions.CustomBuildCheck”>

  3. <param name=“sql” value="SELECT alo.owner
  4.                                   ,alo.object_name

  5.                                   ,alo.status

  6.                                   ,alo.last_ddl_time

  7.                              FROM all_objects alo

  8.                             WHERE status = ‘INVALID’

  9.                               AND alo.owner in (‘BOS_RELEASE’,‘BIL’,‘BLIS’,‘CBSMIG’,‘COJO’,‘CMD_AGENT’,‘CIN’,‘NOPA’,‘ORC’,‘PRV’,‘SEC’,‘TIPI_OWNER’,‘TT’,‘ZON’)

  10.                               AND alo.OBJECT_NAME not like ‘TST%’

  11.                               AND alo.OBJECT_NAME not like ‘TEST%’

  12.                               AND ALO.OBJECT_NAME <> ‘ZON_ORBIT_LOG_PCK’

  13.                               AND ALO.OBJECT_NAME <> ‘ZON_TESTING_PCK’

  14.                               AND ALO.OBJECT_NAME <> ‘ZON_MONITORING_PCK’

  15.                          ORDER BY alo.owner, alo.object_name;"/>

Sample output:

SEVERE 10/30/14 9:52 AM: liquibase: liquibase/changelogs/bos-incremental-changelog.xml: liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo: Change Set liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo failed.  Error: Migration failed for change set liquibase/changelogs/bos-incremental-databaseCheck-changelog.xml::dataBaseCheck_v2::e-ballo:

     Reason:

          liquibase/changelogs/bos-incremental-changelog.xml : Custom Precondition Failed:

---------------------------------------------------------------------------------------------

               ERROR - There are 1 invalid Objects in the Database

---------------------------------------------------------------------------------------------

      OWNER - OBJECT NAME - STATUS - LAST DDL TIME

  1 )  ZON - T2_ORDER_ENTRY_PCK - INVALID - 2014-10-30 09:52:36.0

---------------------------------------------------------------------------------------------