tags:

views:

45

answers:

2

I know that SchemaExport should be my friend. But I am using liquibase and want to execute the DDL - pure sql statements - generated from liquibase to recreate the database before every test method.

Do you see problems with the following code? I wonder that this seems to be so complicated ...

public static int executeScript(String sqlFileOnClasspath) {
    Session sess = getSessionFactory().openSession();
    Transaction ta = sess.beginTransaction();
    int sqlCmd = 0;

    try {
        BufferedReader bReader = new BufferedReader(new InputStreamReader(
                  Util.class.getResourceAsStream(sqlFileOnClasspath), "UTF-8"));
        String line;
        while ((line = bReader.readLine()) != null) {
            if (line.startsWith("--") || line.trim().isEmpty())
                continue;

            final String tmp = line;
            sess.doWork(new Work() {

                @Override
                public void execute(Connection connection) throws SQLException {
                    connection.createStatement().execute(tmp);
                }
            });
            sqlCmd++;
        }
    } catch (Exception ex) {
        log.error("Couldn't execute " + sqlFileOnClasspath, ex);
    } finally {
        ta.commit();
        sess.close();
    }

    return sqlCmd;
}

BTW: For liquibase you will need to do:

    // remove all hibernate managed tables
    SchemaExport schemaTool = new SchemaExport(getConfiguration()); 
    schemaTool.drop(false, true);

    // DROP TABLE DATABASECHANGELOGLOCK;
    // DROP TABLE DATABASECHANGELOG;
    executeScript("/drop-none-hib.sql");

    // now execute the DDL statements from liquibase
    int sqlCmd = executeScript("/schema.sql");
    log.info("Executed " + sqlCmd + " sql commands");
A: 

Why don't you simply use the hbm2ddl.auto configuration?

Or use transactional tests that roll the database back to its original state after each and every test?

duffymo
uses SchemaExport under the hood I think => as I said: liquibase create + manages the DDL for me.
Karussell
yes, I thought about "transactional tests", but I frequently commit things in my tests e.g. to test if some exception will be thrown (uniqueconstraint or optimistic locking etc.)
Karussell
+1  A: 

Security

Directly executing unprepared statements may lead to SQL injection. However, you seem to read DDL statements from a static file, so this shouldn't be a problem, just wanted to note that.

Exception Handling

Missing entirely, e.g. properly closing the input streams, the connections etc. Also, it misses having detailed information on which of the statements failed if any of the SQLExceptions are being thrown. sqlCmd variable also counts failed statements, so I doubt the usefulness of this counter.

Parsing SQL/DDL

You're testing for -- style comments, but not for /* */ comments. That'll bite you some day. Also, the parser assumes a SQL statement per line. Longer statements may be multiline and end with semicolons which need to be trimmed. Not sure about how liquibase generates the statements though, so this may not be a real problem.

Transaction Handling

DDL statements cannot be rolled back anyway, so not sure about the transactions being helpful. Please correct me if i'm wrong.

Otherwise, as it's for testing, i looks fine to me too.

mhaller
cool, thanks a lot! For the TA handling: I hoped you know it ;-)
Karussell
When a DDL executes successfully, a COMMIT is implicitly executed, so you cannot roll back manually. However, if a DDL errors, it's rolled back automatically (e.g. a DROP TABLE will either execute successful and the table is gone forever, or it wont work an the table exists and is in a consistent state) http://searchoracle.techtarget.com/answer/Do-DDL-statements-roll-back-and-why
mhaller
thanks again! (at the moment the link is not working :-()
Karussell