/*
* Copyright (c) 2015 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.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.lang.reflect.UndeclaredThrowableException;
import org.postgresql.pljava.annotation.SQLAction;
import org.postgresql.pljava.annotation.Function;
/**
* Test control of access to 1-thread backend by n-thread JVM.
*
* The "select strictlyNestedTest()" is marked "notFromDDR" because it actually
* <em>does</em> deadlock when invoked from within install_jar, though it
* succeeds when invoked directly. The explanation may lie in the JNI spec's
* caveat that JNI MonitorEnter/MonitorExit functions must be paired with each
* other and not arbitrarily mixed with JVM monitorenter/monitorexit bytecodes.
* In the present design, that can happen (install_jar uses a synchronized
* block to call into the backend when executing DDR commands; DDR command
* calling strictlyNestedTest leads to JNI MonitorExit in BEGIN_CALL; perhaps
* that does not effectively release the lock taken by the synchronized block).
*/
@SQLAction(implementor="notFromDDR",
requires="strictlyNestedTest fn",
install="select strictlyNestedTest()"
)
public class ThreadTest implements Runnable {
/**
* Test that another thread can enter SPI while the calling thread is out.
*
* Create a thread that uses SPI to perform a query and set the value of
* {@link #result}. Start and wait for that thread (so this one is clearly
* out of the backend the whole time), then return the result.
*/
@Function(provides="strictlyNestedTest fn")
public static String strictlyNestedTest()
throws SQLException {
ThreadTest tt = new ThreadTest();
Thread t = new Thread( tt);
t.start();
while ( true )
{
try
{
t.join();
}
catch ( InterruptedException ie )
{
continue;
}
break;
}
return tt.result;
}
String result;
public void run()
{
try
{
Connection c = DriverManager.getConnection(
"jdbc:default:connection");
Statement s = c.createStatement();
ResultSet rs = s.executeQuery( "select version() as version");
rs.next();
result = rs.getString( "version");
}
catch ( Exception e )
{
if ( e instanceof RuntimeException )
throw (RuntimeException)e;
throw new UndeclaredThrowableException( e);
}
}
}