2

H2 database with custom function alias defined as:

create alias to_date as $$
    java.util.Date toDate(java.lang.String dateString, java.lang.String pattern) {
        try {
          return new java.text.SimpleDateFormat(javaPattern).parse(dateString);
        } catch(java.text.ParseException e) {
          throw new java.lang.RuntimeException(e);
        }
      }
$$;

H2 initialized as:

jdbc:h2:mem:testdb;INIT=runscript from 'classpath:create_alias.sql

This is used in tests, executed for multiple projects concurrently on a Jenkins instance. Sometimes such tests would fail with following error:

Could not get JDBC Connection; nested exception is org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "javac: file not found: org/h2/dynamic/TO_DATE.java
Usage: javac <options> <source files>
use -help for a list of possible options
"; SQL statement:


create alias to_date as $$
    java.util.Date toDate(java.lang.String dateString, java.lang.String pattern) {
    ....

My guess is that org.h2.util.SourceCompiler is assuming that there is only one instance of h2 running at the time and writes the generated Java source to 'java.io.tmpdir', which is shared among all processes running under same account. I propose following fix:

Index: SourceCompiler.java
===================================================================
--- SourceCompiler.java (revision 5086)
+++ SourceCompiler.java (working copy)
@@ -40,7 +40,15 @@
      */
     final HashMap<String, Class<?>> compiled = New.hashMap();

-    private final String compileDir = Utils.getProperty("java.io.tmpdir", ".");
+    private final String compileDir;
+    
+    {
+       // use random folder under java.io.tmpdir so multiple h2 could compile at the same time
+       // without overwriting each other files
+       File tmp = File.createTempFile("h2tmp", ".tmp");
+       tmp.mkdir();
+       compileDir = tmp.getAbsolutePath();
+    }

     static {
         Class<?> clazz;

Should I open the support ticket or there are workarounds for this issue?

Cœur
  • 37,241
  • 25
  • 195
  • 267
maximdim
  • 8,041
  • 3
  • 33
  • 48
  • You don't need to open a support ticket, I will apply you patch. Thanks a lot! – Thomas Mueller Sep 09 '13 at 11:57
  • Thanks Thomas. If you post it as an answer I would accept it and close the question. :) – maximdim Sep 09 '13 at 17:02
  • Hm, the patch doesn't work because the prefix `h2` is too short (it must be 3 characters at least). And as far as I see, `File.createTempFile` internally also uses the system property `java.io.tmpdir`. Are you sure `getParent()` should be used? This will basically have the same effect as accessing the system property `java.io.tmpdir` directly. Shouldn't `getParent` be removed? – Thomas Mueller Sep 09 '13 at 17:21
  • Oops, this is what happens when code if written in a rush. My bad. I have updated original question with better patch. – maximdim Sep 09 '13 at 18:59
  • Perhaps type of compileDir could better be changed to File to avoid all these getAbsolutePath() calls – maximdim Sep 09 '13 at 19:00
  • It has to be a directory... But I'm not happy with the solution, as it will create a lot of temporary directories. Maybe there is a way to avoid creating files, using the official java compiler API – Thomas Mueller Sep 11 '13 at 14:00
  • That would be even better and should work faster. – maximdim Sep 12 '13 at 13:44
  • Janino (http://docs.codehaus.org/display/JANINO/Home) has in memory compilation, as long as you don't need generics and other Java 5 stuff. – maximdim Sep 12 '13 at 14:00
  • @Thomas Mueller can you provide me the version where this is fixed? – logger May 24 '16 at 19:22
  • @user3659052 sorry I don't know, it's a long time ago. – Thomas Mueller May 25 '16 at 07:21
  • @Thomas Mueller my problem is similar to this. Except when I did it on junit test our h2 db schema was shared by all tests and whenever we run the test sometimes we would get javac not found error on the alias i have created. we use h2-1.3.160 – logger May 25 '16 at 12:38

2 Answers2

0

You can use javax.tools.JavaCompiler API and provide your own implementation for in-memory JavaFileManager to completely avoid creating those temp files.

BTW, Janino also support javax.tools.JavaCompiler API.

Eugene Kuleshov
  • 31,461
  • 5
  • 66
  • 67
0

I had the same problem running multiple Jenkins executors and having Arquillian/Wildfly/H2 integration tests configuration. I found a workaround by setting java.io.tmpdir property to the build directory in the test standalone.xml.

tibtof
  • 7,857
  • 1
  • 32
  • 49