-
Notifications
You must be signed in to change notification settings - Fork 77
Description
We have been using PL/Java for a couple of years now and created our extension initially with 1.5.6 on Postgres 13. Over the years we have migrated to Postgres 15 then 16 and now 17.2. Until recently, we haven't had any serious issues. Our extension is fairly simple and provides XML and JSON validation services to SQL for generated data from business processes. We use install_jar to create entries in SQLJ for our extension JAR and GSON 2.10.1. We run set_classpath for each of our client schemas.
This has all worked well until 17.2 (using PL/Java 1.6.8). Now we are getting ClassNotFoundException on a static class deep within the extension inner workings.
Our SQL calls runPublishValidation(3 parameters) which uses PL/Java to call Publish.validatte(...). Within the extension Publish.validate creates an instance of the non-static class Validation and calls it's run() method. The run() method performs 10 distinct validation checks, think of them as steps. There are several static helper classes for XML and JSON handling, think of them as utility classes. These static utility classes are used extensively in each of the 10 steps.
What we are seeing is that on the 10th step, PL/Java is reporting ClassNotFoundException on Helpers.processSubstitution(). Again, this class method will have been called dozens of times prior to the 10th step invocation.
This is the call stack I get:
25 Mar 25 14:28:16 org.postgresql.pljava.sqlj.Loader Failed to load class
java.sql.SQLException: An attempt was made to call a PostgreSQL backend function after an elog(ERROR) had been issued
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.Oid._forSqlType(Native Method)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.Oid.lambda$forSqlType$1(Oid.java:68)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.Backend.doInPG(Backend.java:89)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.Oid.forSqlType(Oid.java:68)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.jdbc.SPIPreparedStatement.setObject(SPIPreparedStatement.java:238)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.jdbc.SPIPreparedStatement.setObject(SPIPreparedStatement.java:223)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.jdbc.SPIPreparedStatement.setInt(SPIPreparedStatement.java:124)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.sqlj.Loader.lambda$findClass$5(Loader.java:462)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.sqlj.Loader.findClass(Loader.java:464)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:592)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
at schema:dimbuild_sprvl//com.iri.udb.pljava.publish.Validation.checkAttrSpecMeta(Validation.java:211)
at schema:dimbuild_sprvl//com.iri.udb.pljava.publish.Validation.run(Validation.java:159)
at schema:dimbuild_sprvl//com.iri.udb.pljava.Publish.validate(Publish.java:75)
at schema:dimbuild_sprvl//com.iri.udb.pljava.Publish.validate(Publish.java:48)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.EntryPoints.lambda$invocable$0(EntryPoints.java:130)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.EntryPoints.doPrivilegedAndUnwrap(EntryPoints.java:312)
at org.postgresql.pljava.internal@1.6.8/org.postgresql.pljava.internal.EntryPoints.invoke(EntryPoints.java:158)
Exception mv_spec_extract_data ERROR: java.lang.NoClassDefFoundError: com/iri/udb/pljava/common/Helpers
We have tried many different approaches to narrow down what is happening from pljava setting changes in the postgresql.conf file to flatten away the static class into the Validation class implementation to use Class.forName to dynamically load the class. Nothing helped. Then we decided to add -Djava.class.path={our jars} to pljava.vmoptions and this seems to have corrected the problem, although introduces another problem for us. We run in many different environments, on many database servers and this will be a maintenance and setup nightmare for us. We like using the SQLJ tables to manage the distribution of the extension.
As this point, I will stop typing and let you digest (and/or figure out) what I've said and ask questions.