Populating stored procs into a HSQL DB
I recently encountered a problem trying to load stored procedures into a HSQL DB used for testing. The problem was caused by the script runner provided by spring which separates each statement to be executed in a script file by a semicolon. If a stored proc has statements inside it (which most do), then the proc isn't executed as a single statement. This is further compounded by each statement executed must be understandable by JDBC.
For example the following stored proc causes issues:
CREATE PROCEDURE MY_PROC(IN param1 VARCHAR(30), OUT out_param VARCHAR(100)) READS SQL DATA BEGIN ATOMIC SELECT the_value INTO out_param FROM my_table WHERE field = param1; END .;This problem is solved by using the script runners provided by HSQL in the "org.hsqldb:sqltool" dependency as they parse can correctly parse the scripts containing stored procedures. Here is a Spring Boot test, using an in memory database but using HSQL's script runners:
@RunWith(SpringRunner.class) @AutoConfigureJdbc @Slf4j public class MyDaoTest { @Autowired private MyDao dao; @Test public void myTest() throws Exception { String response = dao.invokeProc("1234"); assertThat(response, notNullValue()); } @Configuration @ComponentScan("net.devgrok.sample.dao") public static class Config { @Bean public EmbeddedDatabaseFactoryBean dataSource() { EmbeddedDatabaseFactoryBean factory = new EmbeddedDatabaseFactoryBean(); factory.setDatabaseType(EmbeddedDatabaseType.HSQL); factory.setDatabasePopulator(databasePopulator("./src/db/sql/stored_proc.sql")); return factory; } @Bean public HsqlDbPopulator databasePopulator(String... scripts) { return new HsqlDbPopulator(scripts); } } public static class HsqlDbPopulator implements DatabasePopulator { private final String[] scriptFiles; public HsqlDbPopulator(String[] scripts) { this.scriptFiles = scripts; } @Override public void populate(Connection connection) throws SQLException, ScriptException { FileSystemResourceLoader resourceLoader = new FileSystemResourceLoader(); for (String scriptFile : scriptFiles) { try { SqlFile file = new SqlFile(resourceLoader.getResource(scriptFile).getFile(), null, false); log.info("Running script {}", scriptFile); file.setConnection(connection); file.execute(); } catch (IOException | SqlToolError e) { log.error("Error executing script {}", scriptFile, e); throw new UncategorizedScriptException("Error executing script " + scriptFile, e); } } } } }Note: this test uses an in memory database, if you want to use another variation, you'll need to create a custom
EmbeddedDatabaseConfigurer
instance to do this which is slightly painful due to Spring's insistence on making everything either private
or final
or both.
I never comment on blogs but your article is so best that I never stop myself to say something about it. You’re amazing Man, I like it WP-Database Issues ... Keep it up
ReplyDelete