First release of the PL/Java.

With this release you can call functions and triggers in Java. At present the implementation uses a very simple classloader mechanism (the CLASSPATH must be set prior to starting postmaster) and there's no support for passing or returning sets. The plan is to build the lacking functionality so that it conforms as close as possible to the SQL-2003 standard and to make use of java.sql interfaces.

The intended road map looks like this:

1.      Wrap the Relation/TupleDesc/Tuple code in the interfaces ResultSet and ResultSetMetaData (java.sql package) and change so that complex types and sets are passed as ResultSet.

2.      Far better packaging, more generic makefile, and more elaborated instructions on how to build.

3.      Implement java.sql interfaces on top of SPI functions (SPI_prepare, SPI_cursor_open, etc.).

4.      Enable the SQLJ schema with functions like INSTALL_JAR, REPLACE_JAR, REMOVE_JAR, and ALTER_JAVA_PATH (this is according to SQL-2003 standard).

5.      Documentation, both API and User Guide.

6.      If possible, add transaction support so that interfaces like javax.transaction.Synchronization can be used.

 

Further steps aimed to bring the PL/Java more closely to the standard will be dependent on some additions to the Postgres SQL parser. User Defined Java types in particular needs to be addressed. The ability to write "EXTERNAL NAME '...'" instead of just "AS '...'" in CREATE FUNCTION is another issue. There's more...

How to get started

See to that you have Java 1.4 installed on your machine.

 

This project has been written using Linux 9.0 on an Intel box and Eclipse 3.0 with CDT 2.0. The pljava CVS contains the some Eclipse specific files. They are there for convenience only and there’s absolutely no requirement to use Eclipse (nor of course to use Linux and Intel). You must at least have Ant (look at the apache.org website) in order to build the Java stuff and to generate the JNI headers.

 

Install the source of postgresql-7.4. Place it adjacent to the org.postgresql.pljava directory (the makefiles uses ../postgresql-7.4 to get to the Postgres source).

 

In order to run the test code you will also need the Postgres JDBC driver.

 

Once everything compile, you must do the following:

-         The postgresql.conf dynamic_library_path variable must be set so that postmaster can find the libpljava.so file.

-         The CLASSPATH environment variable seen by postmaster must point to the pljava.jar and the examples.jar (the latter only required for the samples and test of course). This is a temporary kludge (see road map).

-         The LD_LIBRARY_PATH environment variable must be set so that the loader finds the shared libraries used by the JVM. A standard install on an Intel Linux box will need LD_LIBRARY_PATH=$JAVA_HOME/jre/lib/i386:$JAVA_HOME/jre/lib/i386/client.

Run the tests.

Once the postmaster is running with the above configuration, you should be able to run the test code found in org.postgresql.pljava.test.Tester. It contains some rudimentary tests for primitive parameter passing and the client side of a Java version of a couple of triggers originally from the postgres source distribution (under contrib/spi). Look at the code first. It’s not very scientific.

Known issues

Makefiles

The makefiles of this project should be improved (need better way to find the postgres include files for instance). Help and ideas in this area are greatly appreciated.

Obsolete jni.h

On a Linux 9 system, there is a jni.h file that apparently is bundled with the GNU compiler. The GNU jni.h file has no support for JNI 1.4 and cannot be used. An error like “JNI_1_4 undefined” indicates that the compiler uses an incorrect file.

Loader semantics

Java and JNI will use the following naming scheme when finding the shared library on a Unix box:

Prepend the name with “lib” and then append “.so”. Find the resulting file using the LD_LIBRARY_PATH.

 

On a Windows box it does like this:

Append “.dll” (nothing is prepended) and then use PATH to find the resulting file.

 

Postgres have a scheme of its own. Apparently it doesn’t prepend the “lib” on a Unix box and it uses the Dynamic_library_path instead of the LD_LIBRARY_PATH/PATH to find the module.  Unfortunately, the Dynamic_library_path is not seen by the loader so if a module needs to load other dynamic libraries it will fail unless LD_LIBRARY_PATH/PATH is set correctly.

 

At present, I merge the Dynamic_library_path and the LD_LIBRARY_PATH and use the result in the JVM. That seems to work fine (the JVM will attempt to load the shared library too and unless it finds the already loaded one, it will fail). I think that it would be great if PostgreSQL could do the merge and set the correct LD_LIBRARY_PATH/PATH in the environment used by the forked backend processes. That way, the system loader would function correctly and PostgreSQL would not need any specific code to handle module loading.

Java Garbage Collector versus PostgreSQL palloc.

Primitive types will be passed by value always. This includes the String type (this is a must since Java uses double byte characters). Complex types and the TriggerData structure are however passed by reference. In essence, a Java object will contain a pointer to a palloc’ed memory and use native JNI calls to extract and manipulate data. Such data will become “stale” once a call has ended and code is present to ensure that such pointers are cleared. Any attempt to access instances of the following classes after the called where they where obtain has ended will yield a “closed native handle” exception:

 

org.postgresql.pljava.Relation

org.postgresql.pljava.TriggerData

org.postgresql.pljava.Tuple

org.postgresql.pljava.TupleDesc

And…

You will most likely find more issues.