Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions CI/integration
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,29 @@ int jFeatureVersion = Runtime.version().major();

String vmopts = "-enableassertions:org.postgresql.pljava... -Xcheck:jni";

if ( 17 < jFeatureVersion )
vmopts += " -Djava.security.manager=allow";
vmopts += " --limit-modules=org.postgresql.pljava.internal";

if ( 24 <= jFeatureVersion ) {
vmopts += " -Djava.security.manager=disallow"; // JEP 486
} else if ( 18 <= jFeatureVersion )
vmopts += " -Djava.security.manager=allow"; // JEP 411

if ( 23 <= jFeatureVersion )
vmopts += " --sun-misc-unsafe-memory-access=deny"; // JEP 471

if ( 24 <= jFeatureVersion )
vmopts += " --illegal-native-access=deny"; // JEP 472

Map<String,String> serverOptions = new HashMap<>(Map.of(
"client_min_messages", "info",
"pljava.vmoptions", vmopts,
"pljava.libjvm_location", libjvm.toString()
));
if ( 24 <= jFeatureVersion ) {
serverOptions.put("pljava.allow_unenforced", "java,java_tzset");
serverOptions.put("pljava.allow_unenforced_udt", "on");
}

Node n1 = Node.get_new_node("TestNode1");

if ( s_isWindows )
Expand Down Expand Up @@ -208,11 +222,7 @@ throws Exception

try (
AutoCloseable t1 = n1.initialized_cluster(tweaks);
AutoCloseable t2 = n1.started_server(Map.of(
"client_min_messages", "info",
"pljava.vmoptions", vmopts,
"pljava.libjvm_location", libjvm.toString()
), tweaks);
AutoCloseable t2 = n1.started_server(serverOptions, tweaks);
)
{
int pgMajorVersion;
Expand Down
19 changes: 18 additions & 1 deletion pljava-api/src/main/java/org/postgresql/pljava/Session.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2022 Tada AB and other contributors, as listed below.
* Copyright (c) 2004-2025 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
Expand All @@ -17,6 +17,8 @@
import java.sql.Connection;
import java.sql.SQLException;

import java.util.Properties;

/**
* A Session brings together some useful methods and data for the current
* database session. It provides a set of attributes (a
Expand All @@ -35,6 +37,21 @@
*/
public interface Session
{
/**
* Returns an unmodifiable defensive copy of the Java
* {@link System#getProperties() system properties} taken early in PL/Java
* startup before user code has an opportunity to write them.
*<p>
* When PL/Java is running without security policy enforcement, as on stock
* Java 24 and later, using the frozen properties can simplify defensive
* coding against the possibility of arbitrary property modifications.
*
* @return a {@link Properties} object that departs from the API spec by
* throwing {@link UnsupportedOperationException} from any method if the
* properties would otherwise be modified.
*/
Properties frozenSystemProperties();

/**
* Adds the specified {@code listener} to the list of listeners that will
* receive savepoint events. An {@link AccessControlContext} saved by this
Expand Down
38 changes: 29 additions & 9 deletions pljava-api/src/main/java/org/postgresql/pljava/SessionManager.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2019 Tada AB and other contributors, as listed below.
* Copyright (c) 2004-2025 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
Expand All @@ -23,21 +23,41 @@
*/
public class SessionManager
{
private static Session s_session;

/**
* Returns the current session.
*/
public static Session current()
throws SQLException
{
if(s_session == null)
try
{
return Holder.s_session;
}
catch ( ExceptionInInitializerError e )
{
s_session = load(
Session.class.getModule().getLayer(), Session.class)
.findFirst().orElseThrow(() -> new SQLException(
"could not obtain PL/Java Session object"));
Throwable c = e.getCause();
if ( c instanceof SQLException )
throw (SQLException)c;
throw e;
}
}

private static class Holder
{
private static final Session s_session;

static {
try
{
s_session = load(
Session.class.getModule().getLayer(), Session.class)
.findFirst().orElseThrow(() -> new SQLException(
"could not obtain PL/Java Session object"));
}
catch ( SQLException e )
{
throw new ExceptionInInitializerError(e);
}
}
return s_session;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2023 Tada AB and other contributors, as listed below.
* Copyright (c) 2018-2025 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
Expand All @@ -11,6 +11,10 @@
*/
package org.postgresql.pljava.example.annotation;

import java.sql.SQLException;

import org.postgresql.pljava.SessionManager;

import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;

Expand Down Expand Up @@ -133,9 +137,10 @@ public class JDBC42_21
* recent as the argument ('1.6', '1.7', '1.8', '9', '10', '11', ...).
*/
@Function(schema="javatest", provides="javaSpecificationGE")
public static boolean javaSpecificationGE(String want)
public static boolean javaSpecificationGE(String want) throws SQLException
{
String got = System.getProperty("java.specification.version");
String got = SessionManager.current().frozenSystemProperties()
.getProperty("java.specification.version");
if ( want.startsWith("1.") )
want = want.substring(2);
if ( got.startsWith("1.") )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2025 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
* which accompanies this distribution, and is available at
* http://opensource.org/licenses/BSD-3-Clause
*
* Contributors:
* Chapman Flack
*/
package org.postgresql.pljava.example.annotation;

import java.lang.module.ModuleDescriptor;

import java.sql.ResultSet;
import java.sql.SQLException;

import java.util.Iterator;
import java.util.Objects;

import java.util.stream.Stream;

import org.postgresql.pljava.ResultSetProvider;
import org.postgresql.pljava.annotation.Function;
import static org.postgresql.pljava.annotation.Function.Effects.STABLE;

/**
* Example code to support querying for the modules in Java's boot layer.
*/
public class Modules implements ResultSetProvider.Large {
/**
* Returns information on the named modules in Java's boot module layer.
*/
@Function(
effects = STABLE,
out = {
"name pg_catalog.text",
"any_unqualified_exports boolean",
"any_unqualified_opens boolean"
}
)
public static ResultSetProvider java_modules()
{
return new Modules(
ModuleLayer.boot().modules().stream().map(Module::getDescriptor)
.filter(Objects::nonNull));
}

private final Iterator<ModuleDescriptor> iterator;
private final Runnable closer;

private Modules(Stream<ModuleDescriptor> s)
{
iterator = s.iterator();
closer = s::close;
}

@Override
public boolean assignRowValues(ResultSet receiver, long currentRow)
throws SQLException
{
if ( ! iterator.hasNext() )
return false;

ModuleDescriptor md = iterator.next();

receiver.updateString(1, md.name());

receiver.updateBoolean(2,
md.exports().stream().anyMatch(e -> ! e.isQualified()));

receiver.updateBoolean(3,
md.isOpen() ||
md.opens().stream().anyMatch(o -> ! o.isQualified()));

return true;
}

@Override
public void close()
{
closer.run();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2024 Tada AB and other contributors, as listed below.
* Copyright (c) 2018-2025 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
Expand Down Expand Up @@ -67,6 +67,7 @@

import org.postgresql.pljava.Adjusting;
import static org.postgresql.pljava.Adjusting.XML.setFirstSupported;
import org.postgresql.pljava.SessionManager;
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.MappedUDT;
import org.postgresql.pljava.annotation.SQLAction;
Expand Down Expand Up @@ -643,7 +644,8 @@ public static SQLXML transformXML(
*/
if ( rlt instanceof StreamResult )
t.setOutputProperty(ENCODING,
System.getProperty("org.postgresql.server.encoding"));
SessionManager.current().frozenSystemProperties()
.getProperty("org.postgresql.server.encoding"));
else if ( Boolean.TRUE.equals(indent) )
logMessage("WARNING",
"indent requested, but howout specifies a non-stream " +
Expand Down Expand Up @@ -712,7 +714,8 @@ private static SQLXML echoSQLXML(SQLXML sx, int howin, int howout)
*/
if ( howout < 5 )
t.setOutputProperty(ENCODING,
System.getProperty("org.postgresql.server.encoding"));
SessionManager.current().frozenSystemProperties()
.getProperty("org.postgresql.server.encoding"));
t.transform(src, rlt);
}
catch ( TransformerException te )
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2020 Tada AB and other contributors, as listed below.
* Copyright (c) 2004-2025 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
Expand Down Expand Up @@ -127,20 +127,26 @@ public static String getTimeAsString() throws SQLException {
}
}

static void log(String msg) {
static void log(String msg) throws SQLException {
// GCJ has a somewhat serious bug (reported)
//
if ("GNU libgcj".equals(System.getProperty("java.vm.name"))) {
if ("GNU libgcj"
.equals(
SessionManager.current().frozenSystemProperties()
.getProperty("java.vm.name"))) {
System.out.print("INFO: ");
System.out.println(msg);
} else
Logger.getAnonymousLogger().info(msg);
}

static void warn(String msg) {
static void warn(String msg) throws SQLException {
// GCJ has a somewhat serious bug (reported)
//
if ("GNU libgcj".equals(System.getProperty("java.vm.name"))) {
if ("GNU libgcj"
.equals(
SessionManager.current().frozenSystemProperties()
.getProperty("java.vm.name"))) {
System.out.print("WARNING: ");
System.out.println(msg);
} else
Expand Down
Loading
Loading