From d2ac82e9e912cf2a8020930dcaed26df648e2194 Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Wed, 19 Apr 2023 16:44:14 +0300 Subject: [PATCH 01/10] custom String type refactor to StringPL (fixes broken MVSC windows builds) --- pljava-so/src/main/c/type/BigDecimal.c | 4 ++-- pljava-so/src/main/c/type/String.c | 16 ++++++++-------- pljava-so/src/main/include/pljava/type/String.h | 5 +++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/pljava-so/src/main/c/type/BigDecimal.c b/pljava-so/src/main/c/type/BigDecimal.c index be01c38d1..840101765 100644 --- a/pljava-so/src/main/c/type/BigDecimal.c +++ b/pljava-so/src/main/c/type/BigDecimal.c @@ -38,9 +38,9 @@ static Datum _BigDecimal_coerceObject(Type self, jobject value) return ret; } -static Type BigDecimal_obtain(Oid typeId) +static StringPL BigDecimal_obtain(Oid typeId) { - return (Type)StringClass_obtain(s_BigDecimalClass, typeId); + return /*(Type)*/StringClass_obtain(s_BigDecimalClass, typeId); } /* Make this datatype available to the postgres system. diff --git a/pljava-so/src/main/c/type/String.c b/pljava-so/src/main/c/type/String.c index 4b58f622f..8711f1f3d 100644 --- a/pljava-so/src/main/c/type/String.c +++ b/pljava-so/src/main/c/type/String.c @@ -59,9 +59,9 @@ jvalue _String_coerceDatum(Type self, Datum arg) { jvalue result; char* tmp = DatumGetCString(FunctionCall3( - &((String)self)->textOutput, + &((StringPL)self)->textOutput, arg, - ObjectIdGetDatum(((String)self)->elementType), + ObjectIdGetDatum(((StringPL)self)->elementType), Int32GetDatum(-1))); result.l = String_createJavaStringFromNTS(tmp); pfree(tmp); @@ -83,19 +83,19 @@ Datum _String_coerceObject(Type self, jobject jstr) JNI_deleteLocalRef(jstr); ret = FunctionCall3( - &((String)self)->textInput, + &((StringPL)self)->textInput, CStringGetDatum(tmp), - ObjectIdGetDatum(((String)self)->elementType), + ObjectIdGetDatum(((StringPL)self)->elementType), Int32GetDatum(-1)); pfree(tmp); return ret; } -static String String_create(TypeClass cls, Oid typeId) +static StringPL String_create(TypeClass cls, Oid typeId) { HeapTuple typeTup = PgObject_getValidTuple(TYPEOID, typeId, "type"); Form_pg_type pgType = (Form_pg_type)GETSTRUCT(typeTup); - String self = (String)TypeClass_allocInstance(cls, typeId); + StringPL self = (StringPL)TypeClass_allocInstance(cls, typeId); MemoryContext ctx = GetMemoryChunkContext(self); fmgr_info_cxt(pgType->typoutput, &self->textOutput, ctx); fmgr_info_cxt(pgType->typinput, &self->textInput, ctx); @@ -109,7 +109,7 @@ Type String_obtain(Oid typeId) return (Type)StringClass_obtain(s_StringClass, typeId); } -String StringClass_obtain(TypeClass self, Oid typeId) +StringPL StringClass_obtain(TypeClass self, Oid typeId) { return String_create(self, typeId); } @@ -366,7 +366,7 @@ void String_initialize(void) s_Object_toString = PgObject_getJavaMethod(s_Object_class, "toString", "()Ljava/lang/String;"); s_String_class = (jclass)JNI_newGlobalRef(PgObject_getJavaClass("java/lang/String")); - s_StringClass = TypeClass_alloc2("type.String", sizeof(struct TypeClass_), sizeof(struct String_)); + s_StringClass = TypeClass_alloc2("type.StringPL", sizeof(struct TypeClass_), sizeof(struct String_)); s_StringClass->JNISignature = "Ljava/lang/String;"; s_StringClass->javaTypeName = "java.lang.String"; s_StringClass->canReplaceType = _String_canReplaceType; diff --git a/pljava-so/src/main/include/pljava/type/String.h b/pljava-so/src/main/include/pljava/type/String.h index 6abf07520..0c952ff13 100644 --- a/pljava-so/src/main/include/pljava/type/String.h +++ b/pljava-so/src/main/include/pljava/type/String.h @@ -6,6 +6,7 @@ * * @author Thomas Hallgren */ + #ifndef __pljava_type_String_h #define __pljava_type_String_h @@ -29,7 +30,7 @@ extern "C" { extern jclass s_Object_class; extern jclass s_String_class; struct String_; -typedef struct String_* String; +typedef struct String_ *StringPL; /* * Create a Java String object from a null terminated string. Conversion is @@ -73,7 +74,7 @@ extern text* String_createText(jstring javaString); extern Type String_obtain(Oid typeId); -extern String StringClass_obtain(TypeClass self, Oid typeId); +extern StringPL StringClass_obtain(TypeClass self, Oid typeId); #ifdef __cplusplus } From 47f7e2bbb1362cd267eff5f352509ba6f675353a Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Thu, 20 Apr 2023 18:41:27 +0300 Subject: [PATCH 02/10] Backend.c : support newline seperator | SPI _commit and _rollback impl ( use *_and_chain version ) --- pljava-so/src/main/c/Backend.c | 62 ++++++++++++++++- pljava-so/src/main/c/Invocation.c | 6 +- pljava-so/src/main/c/SPI.c | 67 +++++++++++++++++++ .../org/postgresql/pljava/internal/SPI.java | 16 ++++- .../postgresql/pljava/jdbc/SPIConnection.java | 8 ++- 5 files changed, 152 insertions(+), 7 deletions(-) diff --git a/pljava-so/src/main/c/Backend.c b/pljava-so/src/main/c/Backend.c index a02988b48..97eb8c6d3 100644 --- a/pljava-so/src/main/c/Backend.c +++ b/pljava-so/src/main/c/Backend.c @@ -662,6 +662,13 @@ static void initsequencer(enum initstage is, bool tolerant) #ifndef GCJ JVMOptList_add(&optList, "-Xrs", 0, true); #endif + // VISION NEEDED OPENS + JVMOptList_add(&optList, "--add-opens=java.base/java.nio=ALL-UNNAMED", 0, true); + JVMOptList_add(&optList, "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED", 0, true); + // DO NOT CREATE hs_err_pid in PGDATA directory ? + //JVMOptList_add(&optList, "-XX:+SuppressFatalErrorMessage", 0, true); + //------------------------------------------------------------------------------- + effectiveModulePath = getModulePath("--module-path="); if(effectiveModulePath != 0) { @@ -1512,9 +1519,58 @@ static void JVMOptList_addModuleMain(JVMOptList* jol) static void addUserJVMOptions(JVMOptList* optList) { const char* cp = vmoptions; - + //-------------------------------------------- + // VisionR customization : use newline separator for options, because of problems parsing arguments with space (directory paths with -D= + //-------------------------------------------- + const char* tcp = cp; + if (cp != NULL) { + char c; + for (;;) { + c = *tcp++; + if (c == 0) { + tcp=NULL; + break; + } + if (c == '\n') + break; + } + } + //-------------------------------------------- + // HAS NEWLINE IN VMOPTIONS ? + if(tcp != NULL) { + StringInfoData buf; + char quote = 0; + char c; + initStringInfo(&buf); + for(;;) + { + c = *cp++; + switch(c) + { + case 0: + break; + case '\n' : + if(buf.len > 0) { + JVMOptList_add(optList, buf.data, 0, true); + buf.len = 0; + buf.data[0] = 0; + } + continue; + default : + appendStringInfoChar(&buf, c); + continue; + } + break; + } + if(buf.len > 0) + JVMOptList_add(optList, buf.data, 0, true); + pfree(buf.data); + } else + //-------------------------------------------- + // ORIGINAL CODE + //--------------------------------------------*/ if(cp != NULL) - { + { StringInfoData buf; char quote = 0; char c; @@ -1562,7 +1618,7 @@ static void addUserJVMOptions(JVMOptList* optList) else if(buf.len > 0) { /* Whitespace followed by '-' triggers new - * option declaration. + * option declaration. */ JVMOptList_add(optList, buf.data, 0, true); buf.len = 0; diff --git a/pljava-so/src/main/c/Invocation.c b/pljava-so/src/main/c/Invocation.c index 8fe4aaff3..6bcc07d21 100644 --- a/pljava-so/src/main/c/Invocation.c +++ b/pljava-so/src/main/c/Invocation.c @@ -95,7 +95,11 @@ void Invocation_assertConnect(void) int rslt; if(!currentInvocation->hasConnected) { - rslt = SPI_connect(); + //rslt = SPI_connect(); + // VISIONR requires SPI_commit, SPI_rollback + // https://www.postgresql.org/docs/current/spi-spi-connect.html + rslt = SPI_connect_ext(SPI_OPT_NONATOMIC); + if ( SPI_OK_CONNECT != rslt ) elog(ERROR, "SPI_connect returned %s", SPI_result_code_string(rslt)); diff --git a/pljava-so/src/main/c/SPI.c b/pljava-so/src/main/c/SPI.c index ea104bd9f..8b4660f01 100644 --- a/pljava-so/src/main/c/SPI.c +++ b/pljava-so/src/main/c/SPI.c @@ -56,6 +56,19 @@ void SPI_initialize(void) "()V", Java_org_postgresql_pljava_internal_SPI__1freeTupTable }, + +{ // require by VisionR + "_commit", + "()V", + Java_org_postgresql_pljava_internal_SPI__1commit + }, +{ // require by VisionR + "_rollback", + "()V", + Java_org_postgresql_pljava_internal_SPI__1rollback + }, + + { 0, 0, 0 }}; PgObject_registerNatives("org/postgresql/pljava/internal/SPI", methods); @@ -199,3 +212,57 @@ Java_org_postgresql_pljava_internal_SPI__1freeTupTable(JNIEnv* env, jclass cls) END_NATIVE } } + + +/* + * Class: org_postgresql_pljava_internal_SPI + * Method: _commit + * Signature: ()V; + */ +JNIEXPORT void JNICALL +Java_org_postgresql_pljava_internal_SPI__1commit(JNIEnv* env, jclass cls) +{ + BEGIN_NATIVE + STACK_BASE_VARS + STACK_BASE_PUSH(env) + PG_TRY(); + { + Invocation_assertConnect(); + SPI_commit_and_chain(); + //SPI_commit(); + } + PG_CATCH(); + { + Exception_throw_ERROR("SPI_commit"); + } + PG_END_TRY(); + STACK_BASE_POP() + END_NATIVE + +} + +/* + * Class: org_postgresql_pljava_internal_SPI + * Method: _rollback + * Signature: ()V; + */ +JNIEXPORT void JNICALL +Java_org_postgresql_pljava_internal_SPI__1rollback(JNIEnv* env, jclass cls) +{ + BEGIN_NATIVE + STACK_BASE_VARS + STACK_BASE_PUSH(env) + PG_TRY(); + { + Invocation_assertConnect(); + //SPI_rollback(); + SPI_rollback_and_chain(); + } + PG_CATCH(); + { + Exception_throw_ERROR("SPI_rollback"); + } + PG_END_TRY(); + STACK_BASE_POP() + END_NATIVE +} diff --git a/pljava/src/main/java/org/postgresql/pljava/internal/SPI.java b/pljava/src/main/java/org/postgresql/pljava/internal/SPI.java index 9151ad100..6ff62f9d1 100644 --- a/pljava/src/main/java/org/postgresql/pljava/internal/SPI.java +++ b/pljava/src/main/java/org/postgresql/pljava/internal/SPI.java @@ -54,7 +54,7 @@ public class SPI public static final int OK_REL_UNREGISTER = 16; public static final int OK_TD_REGISTER = 17; - /** + /** * Execute a command using the internal SPI_exec function. * @param command The command to execute. * @param rowCount The maximum number of tuples to create. A value @@ -69,6 +69,14 @@ private static int exec(String command, int rowCount) return doInPG(() -> _exec(command, rowCount)); } + public static void commit() { + doInPG(() -> _commit()); + } + + public static void rollback() { + doInPG(() -> _rollback()); + } + public static void freeTupTable() { doInPG(SPI::_freeTupTable); @@ -156,4 +164,10 @@ public static String getResultText(int resultCode) private native static int _getResult(); private native static void _freeTupTable(); private native static TupleTable _getTupTable(TupleDesc known); + + + // required by VisionR + private native static void _commit(); + // required by VisionR + private native static void _rollback(); } diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java index ad1df5c5c..d3e506de7 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java @@ -194,7 +194,9 @@ public void close() public void commit() throws SQLException { - throw new UnsupportedFeatureException("Connection.commit"); + //throw new UnsupportedFeatureException("Connection.commit"); + // required by VisionR + SPI.commit(); } /** @@ -205,7 +207,9 @@ public void commit() public void rollback() throws SQLException { - throw new UnsupportedFeatureException("Connection.rollback"); + // throw new UnsupportedFeatureException("Connection.rollback"); + // required by VisionR + SPI.rollback(); } /** From 46317951cf2bb6445f1a9aede642cc8a1e58edf9 Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Thu, 20 Apr 2023 18:43:12 +0300 Subject: [PATCH 03/10] add missing import to SPIConnection --- .../src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java index d3e506de7..153102f4c 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java @@ -52,7 +52,7 @@ import java.util.regex.PatternSyntaxException; import org.postgresql.pljava.internal.Oid; import org.postgresql.pljava.internal.PgSavepoint; - +import org.postgresql.pljava.internal.SPI; /** * Provides access to the current connection (session) the Java stored * procedure is running in. It is returned from the driver manager From 59b80b1f06b940272e183110983d3741a4e4ef66 Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Thu, 20 Apr 2023 20:17:29 +0300 Subject: [PATCH 04/10] java_sql_Types_OTHER > UNKNOWNOID | used as unknown type setNull --- pljava-so/src/main/c/type/Oid.c | 5 ++++- .../pljava/jdbc/SPIPreparedStatement.java | 22 +++++++++++++------ .../org/postgresql/pljava/jdbc/TypeOid.java | 7 +++++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/pljava-so/src/main/c/type/Oid.c b/pljava-so/src/main/c/type/Oid.c index aecb67e01..c33b9b736 100644 --- a/pljava-so/src/main/c/type/Oid.c +++ b/pljava-so/src/main/c/type/Oid.c @@ -112,8 +112,11 @@ Oid Oid_forSqlType(int sqlType) case java_sql_Types_DATALINK: typeId = TEXTOID; break; + case java_sql_Types_OTHER: /* visionr needs other for unknown type nulls */ + typeId = UNKNOWNOID; + break; case java_sql_Types_NULL: - case java_sql_Types_OTHER: + //case java_sql_Types_OTHER: case java_sql_Types_JAVA_OBJECT: case java_sql_Types_DISTINCT: case java_sql_Types_STRUCT: diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIPreparedStatement.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIPreparedStatement.java index 02ccd4070..02874b8d6 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIPreparedStatement.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIPreparedStatement.java @@ -234,10 +234,14 @@ private void setObject( if ( null != vAlt ) id = new Oid(vAlt.defaultOid()); - else if ( sqlType != Types.OTHER ) + else if ( sqlType != Types.OTHER) id = Oid.forSqlType(sqlType); - else + else if (value == null) { + // VisionR fix : NULL value with TYPE OTHER > use PG typeoid UNKNOWN + id = org.postgresql.pljava.jdbc.TypeOid.UNKNOWN; + } else { id = Oid.forJavaObject(value); + } // Default to String. // @@ -294,12 +298,16 @@ else if ( null == vAlt && !op.equals(id) ) @Override public void setObject(int columnIndex, Object value) - throws SQLException - { - if(value == null) + throws SQLException { + /*if(value == null) throw new SQLException( - "Can't assign null unless the SQL type is known"); - + "Can't assign null unless the SQL type is known");*/ + if (value == null) { + // VisionR fix null without type + setNull(columnIndex,Types.OTHER); + return; + } + TypeBridge.Holder vAlt = TypeBridge.wrap(value); int sqlType; diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/TypeOid.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/TypeOid.java index 9112bd8bf..c84431762 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/TypeOid.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/TypeOid.java @@ -14,6 +14,8 @@ import org.postgresql.pljava.internal.Oid; +// https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat + /** * Provides constants for well-known backend OIDs for the types we commonly * use. @@ -42,7 +44,8 @@ public class TypeOid public static final int VARCHAROID = 1043; public static final int OIDOID = 26; public static final int BPCHAROID = 1042; - + public static final int UNKNOWNOID = 705; + public static final Oid INVALID = new Oid(InvalidOid); public static final Oid INT2 = new Oid(INT2OID); public static final Oid INT4 = new Oid(INT4OID); @@ -60,6 +63,8 @@ public class TypeOid public static final Oid VARCHAR = new Oid(VARCHAROID); public static final Oid OID = new Oid(OIDOID); public static final Oid BPCHAR = new Oid(BPCHAROID); + public static final Oid UNKNOWN = new Oid(UNKNOWNOID); + /* * Added in 2019. The numeric constant will be used, but no need is foreseen From 3aa5d6dcccfdf2408b870f5c980dd551f77f25b4 Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Sat, 22 Apr 2023 15:04:53 +0300 Subject: [PATCH 05/10] impl checkForInterrupt --- pljava-so/src/main/c/Backend.c | 1 + pljava-so/src/main/c/SPI.c | 29 +++++++++++++++---- .../org/postgresql/pljava/internal/SPI.java | 7 +++++ .../postgresql/pljava/jdbc/SPIConnection.java | 3 ++ 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/pljava-so/src/main/c/Backend.c b/pljava-so/src/main/c/Backend.c index 97eb8c6d3..21af3641e 100644 --- a/pljava-so/src/main/c/Backend.c +++ b/pljava-so/src/main/c/Backend.c @@ -663,6 +663,7 @@ static void initsequencer(enum initstage is, bool tolerant) JVMOptList_add(&optList, "-Xrs", 0, true); #endif // VISION NEEDED OPENS + JVMOptList_add(&optList, "--enable-preview", 0, true); // JDK 19 virtual threads JVMOptList_add(&optList, "--add-opens=java.base/java.nio=ALL-UNNAMED", 0, true); JVMOptList_add(&optList, "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED", 0, true); // DO NOT CREATE hs_err_pid in PGDATA directory ? diff --git a/pljava-so/src/main/c/SPI.c b/pljava-so/src/main/c/SPI.c index 8b4660f01..48e9520d7 100644 --- a/pljava-so/src/main/c/SPI.c +++ b/pljava-so/src/main/c/SPI.c @@ -56,19 +56,19 @@ void SPI_initialize(void) "()V", Java_org_postgresql_pljava_internal_SPI__1freeTupTable }, - -{ // require by VisionR + { // required by VisionR "_commit", "()V", Java_org_postgresql_pljava_internal_SPI__1commit }, -{ // require by VisionR + { // required by VisionR "_rollback", "()V", Java_org_postgresql_pljava_internal_SPI__1rollback }, - - + { // required by VisionR + "_checkForInterrupt", + "()V" { 0, 0, 0 }}; PgObject_registerNatives("org/postgresql/pljava/internal/SPI", methods); @@ -266,3 +266,22 @@ Java_org_postgresql_pljava_internal_SPI__1rollback(JNIEnv* env, jclass cls) STACK_BASE_POP() END_NATIVE } + +JNIEXPORT void JNICALL +Java_org_postgresql_pljava_internal_SPI__1checkForInterrupt(JNIEnv* env, jclass cls) +{ + BEGIN_NATIVE + STACK_BASE_VARS + STACK_BASE_PUSH(env) + PG_TRY(); + { + CHECK_FOR_INTERRUPTS(); + } + PG_CATCH(); + { + Exception_throw_ERROR("SPI_interrupt"); + } + PG_END_TRY(); + STACK_BASE_POP() + END_NATIVE +} diff --git a/pljava/src/main/java/org/postgresql/pljava/internal/SPI.java b/pljava/src/main/java/org/postgresql/pljava/internal/SPI.java index 6ff62f9d1..e9b00ac2c 100644 --- a/pljava/src/main/java/org/postgresql/pljava/internal/SPI.java +++ b/pljava/src/main/java/org/postgresql/pljava/internal/SPI.java @@ -77,6 +77,11 @@ public static void rollback() { doInPG(() -> _rollback()); } + public static void checkForInterrupt() { + doInPG(() -> _checkForInterrupt()); + } + + public static void freeTupTable() { doInPG(SPI::_freeTupTable); @@ -170,4 +175,6 @@ public static String getResultText(int resultCode) private native static void _commit(); // required by VisionR private native static void _rollback(); + // required by VisionR + private native static void _checkForInterrupt(); } diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java index 153102f4c..7664a5ba1 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java @@ -1077,6 +1077,9 @@ else if(value instanceof String) public boolean isValid( int timeout ) throws SQLException { + // VisionR fix : check for interrupt + SPI.checkForInterrupt(); + return true; // The connection is always alive and // ready, right? } From 59fcf98ee671f1993b6e8474b167f72217b7de71 Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Sat, 22 Apr 2023 15:09:03 +0300 Subject: [PATCH 06/10] SPI.c type error --- pljava-so/src/main/c/SPI.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pljava-so/src/main/c/SPI.c b/pljava-so/src/main/c/SPI.c index 48e9520d7..94edb97b2 100644 --- a/pljava-so/src/main/c/SPI.c +++ b/pljava-so/src/main/c/SPI.c @@ -68,7 +68,9 @@ void SPI_initialize(void) }, { // required by VisionR "_checkForInterrupt", - "()V" + "()V", + Java_org_postgresql_pljava_internal_SPI__1checkForInterrupt + }, { 0, 0, 0 }}; PgObject_registerNatives("org/postgresql/pljava/internal/SPI", methods); From 5a4264ad21d62b3395f3b308d17d1e0e1727ea3d Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Sun, 23 Apr 2023 23:47:37 +0300 Subject: [PATCH 07/10] cleanup enhancements | add clientInfo property 'SPIConnectionNonAtomic' | Backend vmoptions newline separator if first char newline --- pljava-so/src/main/c/Backend.c | 32 ++++------------- pljava-so/src/main/c/Invocation.c | 27 +++++++++++--- .../postgresql/pljava/jdbc/Invocation.java | 13 +++++++ .../postgresql/pljava/jdbc/SPIConnection.java | 35 ++++++++++++++----- 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/pljava-so/src/main/c/Backend.c b/pljava-so/src/main/c/Backend.c index 21af3641e..234493385 100644 --- a/pljava-so/src/main/c/Backend.c +++ b/pljava-so/src/main/c/Backend.c @@ -211,6 +211,7 @@ static char const visualVMprefix[] = "-Dvisualvm.display.name="; static char const moduleMainPrefix[] = "-Djdk.module.main="; static char const policyUrlsGUC[] = "pljava.policy_urls"; + /* * In a background worker, _PG_init may be called very early, before much of * the state needed during PL/Java initialization has even been set up. When @@ -662,14 +663,7 @@ static void initsequencer(enum initstage is, bool tolerant) #ifndef GCJ JVMOptList_add(&optList, "-Xrs", 0, true); #endif - // VISION NEEDED OPENS - JVMOptList_add(&optList, "--enable-preview", 0, true); // JDK 19 virtual threads - JVMOptList_add(&optList, "--add-opens=java.base/java.nio=ALL-UNNAMED", 0, true); - JVMOptList_add(&optList, "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED", 0, true); - // DO NOT CREATE hs_err_pid in PGDATA directory ? - //JVMOptList_add(&optList, "-XX:+SuppressFatalErrorMessage", 0, true); //------------------------------------------------------------------------------- - effectiveModulePath = getModulePath("--module-path="); if(effectiveModulePath != 0) { @@ -1521,24 +1515,10 @@ static void addUserJVMOptions(JVMOptList* optList) { const char* cp = vmoptions; //-------------------------------------------- - // VisionR customization : use newline separator for options, because of problems parsing arguments with space (directory paths with -D= - //-------------------------------------------- - const char* tcp = cp; - if (cp != NULL) { - char c; - for (;;) { - c = *tcp++; - if (c == 0) { - tcp=NULL; - break; - } - if (c == '\n') - break; - } - } - //-------------------------------------------- - // HAS NEWLINE IN VMOPTIONS ? - if(tcp != NULL) { + // use newline separator for options if first char in options is newline + //--------------------------------------------*/ + if(cp != NULL && *cp == '\n') + { StringInfoData buf; char quote = 0; char c; @@ -1568,7 +1548,7 @@ static void addUserJVMOptions(JVMOptList* optList) pfree(buf.data); } else //-------------------------------------------- - // ORIGINAL CODE + // original optimistic parsing //--------------------------------------------*/ if(cp != NULL) { diff --git a/pljava-so/src/main/c/Invocation.c b/pljava-so/src/main/c/Invocation.c index 6bcc07d21..6eaf086b6 100644 --- a/pljava-so/src/main/c/Invocation.c +++ b/pljava-so/src/main/c/Invocation.c @@ -26,6 +26,7 @@ static jmethodID s_Invocation_onExit; static unsigned int s_callLevel = 0; +static bool connectionModeNonAtomic; Invocation* currentInvocation; @@ -81,6 +82,11 @@ void Invocation_initialize(void) "()V", Java_org_postgresql_pljava_jdbc_Invocation__1register }, + { + "_setSPIConnectionNonAtomic", + "()V", + Java_org_postgresql_pljava_jdbc_Invocation__1setSPIConnectionNonAtomic + }, { 0, 0, 0 } }; @@ -95,11 +101,7 @@ void Invocation_assertConnect(void) int rslt; if(!currentInvocation->hasConnected) { - //rslt = SPI_connect(); - // VISIONR requires SPI_commit, SPI_rollback - // https://www.postgresql.org/docs/current/spi-spi-connect.html - rslt = SPI_connect_ext(SPI_OPT_NONATOMIC); - + rslt = SPI_connect_ext(connectionModeNonAtomic ? SPI_OPT_NONATOMIC : 0); if ( SPI_OK_CONNECT != rslt ) elog(ERROR, "SPI_connect returned %s", SPI_result_code_string(rslt)); @@ -307,3 +309,18 @@ Java_org_postgresql_pljava_jdbc_Invocation__1register(JNIEnv* env, jobject _this "mismanaged PL/Java invocation stack"); END_NATIVE } + +/* + * Class: org_postgresql_pljava_jdbc_Invocation + * Method: setSPIConnectionNonAtomic + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_org_postgresql_pljava_jdbc_Invocation__1setSPIConnectionNonAtomic(JNIEnv* env, jclass cls) +{ + BEGIN_NATIVE_NO_ERRCHECK + connectionModeNonAtomic=true; + END_NATIVE +} + + diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/Invocation.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/Invocation.java index b06e24727..597e654f0 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/Invocation.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/Invocation.java @@ -102,6 +102,14 @@ public void onExit(boolean withError) } } + public static void setSPIConnectionNonAtomic() { + doInPG(() -> + { + _setSPIConnectionNonAtomic(); + return null; + }); + } + /** * @return The current invocation */ @@ -164,4 +172,9 @@ static void clearErrorCondition() * Clears the error condition set by elog(ERROR) */ private native static void _clearErrorCondition(); + + /* set connection mode to non atomic + * https://www.postgresql.org/docs/current/spi-spi-connect.html */ + private static native void _setSPIConnectionNonAtomic(); + } diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java index 7664a5ba1..aca125f84 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java @@ -1077,11 +1077,9 @@ else if(value instanceof String) public boolean isValid( int timeout ) throws SQLException { - // VisionR fix : check for interrupt + // The connection is always alive and ready if not interrupted SPI.checkForInterrupt(); - - return true; // The connection is always alive and - // ready, right? + return true; } @Override @@ -1114,13 +1112,20 @@ public T unwrap(Class iface) public void setClientInfo(String name, String value) throws SQLClientInfoException { + // supported properties + switch (name) { + case "SPIConnectionNonAtomic" : + if ("true".equals(value.toString())) + Invocation.setSPIConnectionNonAtomic(); + return; + } + // unsupported Map failures = new HashMap<>(); failures.put(name, ClientInfoStatus.REASON_UNKNOWN_PROPERTY); throw new SQLClientInfoException( "ClientInfo property not supported.", failures); } - @Override public void setClientInfo(Properties properties) throws SQLClientInfoException @@ -1129,13 +1134,25 @@ public void setClientInfo(Properties properties) return; Map failures = new HashMap<>(); - Iterator i = properties.stringPropertyNames().iterator(); while (i.hasNext()) { - failures.put(i.next(), ClientInfoStatus.REASON_UNKNOWN_PROPERTY); + String key = i.next(); + switch (key) { + // supported properties + case "SPIConnectionNonAtomic" : { + Object value = properties.get(key); + if ("true".equals(value.toString())) + Invocation.setSPIConnectionNonAtomic(); + break; + } + // unsupported + default : + failures.put(i.next(), ClientInfoStatus.REASON_UNKNOWN_PROPERTY); + } } - throw new SQLClientInfoException( - "ClientInfo property not supported.", failures); + if (!failures.isEmpty()) + throw new SQLClientInfoException( + "ClientInfo property not supported.", failures); } @Override From f3229029334dc5ba36a6821af300165e2215a7fd Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Sun, 23 Apr 2023 23:55:13 +0300 Subject: [PATCH 08/10] SPIConnection commit & rollback throw error if not spiConnectionNonAtomic --- .../postgresql/pljava/jdbc/SPIConnection.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java index aca125f84..4d62aa03b 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java @@ -91,6 +91,9 @@ public class SPIConnection implements Connection private static final HashMap,Integer> s_class2sqlType = new HashMap<>(30); + /* if client info option SPIConnectionNonAtomic is true */ + private boolean spiConnectionNonAtomic; + static { addType(String.class, Types.VARCHAR); @@ -194,9 +197,10 @@ public void close() public void commit() throws SQLException { - //throw new UnsupportedFeatureException("Connection.commit"); - // required by VisionR - SPI.commit(); + if (spiConnectionNonAtomic) + SPI.commit(); + else + throw new UnsupportedFeatureException("Connection.commit"); } /** @@ -207,9 +211,10 @@ public void commit() public void rollback() throws SQLException { - // throw new UnsupportedFeatureException("Connection.rollback"); - // required by VisionR - SPI.rollback(); + if (spiConnectionNonAtomic) + SPI.rollback(); + else + throw new UnsupportedFeatureException("Connection.rollback"); } /** @@ -1115,8 +1120,13 @@ public void setClientInfo(String name, String value) // supported properties switch (name) { case "SPIConnectionNonAtomic" : - if ("true".equals(value.toString())) + if ("true".equals(value.toString())) { + spiConnectionNonAtomic=true; Invocation.setSPIConnectionNonAtomic(); + } + try { + getClientInfo().put(name, value); + } catch (SQLException e) {} return; } // unsupported @@ -1153,6 +1163,7 @@ public void setClientInfo(Properties properties) if (!failures.isEmpty()) throw new SQLClientInfoException( "ClientInfo property not supported.", failures); + this._clientInfo=properties; } @Override From b9e07c107362b640ff6874260d17e1c9d0895a5d Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Wed, 17 May 2023 15:36:38 +0300 Subject: [PATCH 09/10] SPIConnection fix prepared statement parsing --- .cproject | 78 +++++++++++++++++++ .../postgresql/pljava/jdbc/SPIConnection.java | 23 +++++- 2 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 .cproject diff --git a/.cproject b/.cproject new file mode 100644 index 000000000..36957c490 --- /dev/null +++ b/.cproject @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + make + -e /bin/make + test_all + false + true + + + c:/msys/bin/rxvt + -e /bin/make + clean + false + true + + + c:/msys/bin/rxvt + -e /bin/make + all + false + true + + + c:/msys/bin/rxvt + -e /bin/make + release + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java index 4d62aa03b..f698c519f 100644 --- a/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java +++ b/pljava/src/main/java/org/postgresql/pljava/jdbc/SPIConnection.java @@ -467,30 +467,45 @@ public String nativeSQL(String sql, int[] paramCountRet) int len = sql.length(); char inQuote = 0; int paramIndex = 1; + boolean inSingleQuoteEncoded=false; for(int idx = 0; idx < len; ++idx) { char c = sql.charAt(idx); switch(c) { case '\\': + buf.append(c); + // inside encoded string ? + if (!inSingleQuoteEncoded) + continue; // Next character is escaped. Keep both // escape and the character. // - buf.append(c); if(++idx == len) break; c = sql.charAt(idx); break; - - case '\'': + case '"': + // Strings within quotes should not be subject + // to "?" -> "$n" substitution. + // + if(inQuote == c) + inQuote = 0; + else if(inQuote == 0) + inQuote = c; + break; + case '\'': // Strings within quotes should not be subject // to '?' -> '$n' substitution. // if(inQuote == c) inQuote = 0; - else if(inQuote == 0) + else if(inQuote == 0) { inQuote = c; + char p = idx == 0 ? 0 : sql.charAt(idx-1); + inSingleQuoteEncoded=(p == 'e' || p == 'E'); // inside quoted text + } break; case '?': From 53dbe3e3de2836d647497cfcd7b83289282002ab Mon Sep 17 00:00:00 2001 From: Martin Hristov Date: Fri, 29 Mar 2024 08:34:04 +0200 Subject: [PATCH 10/10] upd --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 480957b02..f1b69e1b5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ target/staging target/javadoc-bundle-options pljava-so/pgsql.properties pljava-so/target/ +target \ No newline at end of file