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
84 changes: 54 additions & 30 deletions pljava/src/main/java/org/postgresql/pljava/management/Commands.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2023 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 @@ -43,6 +43,7 @@
import java.text.ParseException;
import java.util.ArrayList;
import static java.util.Arrays.fill;
import static java.util.Objects.requireNonNullElse;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
Expand All @@ -68,6 +69,7 @@
import static org.postgresql.pljava.internal.Privilege.doPrivileged;
import static org.postgresql.pljava.jdbc.SQLUtils.getDefaultConnection;
import org.postgresql.pljava.sqlj.Loader;
import static org.postgresql.pljava.sqlj.Loader.PUBLIC_SCHEMA;

import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;
Expand Down Expand Up @@ -934,7 +936,8 @@ public static void replaceJar(String urlString, String jarName,
*
* @param schemaName Name of the schema for which this path is valid.
* @param path Colon separated list of names. Each name must denote the name
* of a jar that is present in the jar repository.
* of a jar that is present in the jar repository. An empty
* string or null equivalently set no class path for the schema.
* @throws SQLException If no schema can be found with the givene name, or
* if one or several names of the path denotes a nonexistant jar
* file.
Expand Down Expand Up @@ -1022,7 +1025,6 @@ public static void setClassPath(Identifier.Simple schema, String path)
{
// Insert the new path.
//
;
try(PreparedStatement stmt = getDefaultConnection()
.prepareStatement(
"INSERT INTO sqlj.classpath_entry("+
Expand All @@ -1042,41 +1044,60 @@ public static void setClassPath(Identifier.Simple schema, String path)
Loader.clearSchemaLoaders();
}

/**
* Run <var>runnable</var> while a temporary class path including
* <var>jarName</var>, if needed, is imposed on the current
* (head-of-{@code search_path}) schema.
*<p>
* The temporary class path is imposed if <var>jarName</var> is not already
* included in the current schema's class path, and also not in the public
* schema's class path if the current schema is not the public one.
*
* @param jarName Caller must have checked (as with {@code assertJarName})
* that this is a sensible jar name, in particular without the colons that
* separate a PL/Java class path.
* @param schemaMayVanish Caller passes true if this is a {@code remove_jar}
* action, when it should not be surprising if undoing the temporary class
* path fails because the schema is gone after the undeploy steps.
* @param runnable The deploy/undeploy actions to take while the temporary
* class path is possibly imposed.
*/
private static void withJarInPath(String jarName, boolean schemaMayVanish,
Checked.Runnable<SQLException> runnable) throws SQLException
{
String jarNameX = ':' + jarName + ':';
Identifier.Simple originalSchema = getCurrentSchema();
String originalClasspath = getClassPath(originalSchema);
boolean changed;
if(originalClasspath == null)
String originalClasspath =
requireNonNullElse(getClassPath(originalSchema), "");

boolean found = false;

if ( ! originalClasspath.isEmpty() )
found = (':'+originalClasspath+':').contains(jarNameX);
else if ( ! PUBLIC_SCHEMA.equals(originalSchema) )
{
setClassPath(originalSchema, jarName);
changed = true;
String fallbackClasspath =
requireNonNullElse(getClassPath(PUBLIC_SCHEMA), "");
found = (':'+fallbackClasspath+':').contains(jarNameX);
}
else
{
String[] elems = originalClasspath.split(":");
int idx = elems.length;
boolean found = false;
while(--idx >= 0)
if(elems[idx].equals(jarName))
{
found = true;
break;
}

if(found)
changed = false;
else
{
setClassPath(originalSchema, jarName + ':' + originalClasspath);
changed = true;
}
if ( ! found )
{
String newPath = jarName;
if ( ! originalClasspath.isEmpty() )
newPath += ':' + originalClasspath;
setClassPath(originalSchema, newPath);
}

runnable.run();

if ( changed )
/*
* This is not a finally, because if something went wrong PostgreSQL
* won't allow the SPI operations in setClassPath anyway, and that's
* also ok, because if something went wrong PostgreSQL will roll back
* the transaction.
*/
if ( ! found )
{
try
{
Expand Down Expand Up @@ -1453,17 +1474,20 @@ private static void installJar(String urlString, String jarName,
try
{
deployInstall(jarId, jarName);
deploy = false; // flag that deployInstall completed
}
catch ( Error | RuntimeException | SQLException e )
finally
{
Loader.clearSchemaLoaders();
throw e;
if ( deploy ) // or in case it didn't complete ...
Loader.clearSchemaLoaders();
}
}

private static void replaceJar(String urlString, String jarName,
boolean redeploy, byte[] image) throws SQLException
{
assertJarName(jarName);

AclId[] ownerRet = new AclId[1];
int jarId = getJarId(jarName, ownerRet);
if(jarId < 0)
Expand Down
4 changes: 2 additions & 2 deletions pljava/src/main/java/org/postgresql/pljava/sqlj/Loader.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2021 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 @@ -130,7 +130,7 @@ public URL nextElement()
return entryURL(m_entryIds[m_top++]);
}
}
private static final Identifier.Simple PUBLIC_SCHEMA =
public static final Identifier.Simple PUBLIC_SCHEMA =
Identifier.Simple.fromCatalog("public");

private static final Map<Identifier.Simple, ClassLoader>
Expand Down
Loading