/* * Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden * Distributed under the terms shown in the file COPYRIGHT * found in the root folder of this project or at * http://eng.tada.se/osprojects/COPYRIGHT.html */ package org.postgresql.pljava.jdbc; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.logging.Logger; import org.postgresql.pljava.internal.Backend; import org.postgresql.pljava.internal.PgSavepoint; /** * @author Thomas Hallgren */ public class Invocation { /** * The current "stack" of invocations. */ private static Invocation[] s_levels = new Invocation[10]; /** * Nesting level for this invocation */ private final int m_nestingLevel; /** * Top level savepoint relative to this invocation. */ private PgSavepoint m_savepoint; private Invocation(int level) { m_nestingLevel = level; } /** * @return The nesting level of this invocation */ public int getNestingLevel() { return m_nestingLevel; } /** * @return Returns the savePoint. */ final PgSavepoint getSavepoint() { return m_savepoint; } private ArrayList m_preparedStatements; final void manageStatement(PreparedStatement statement) { if(m_preparedStatements == null) m_preparedStatements = new ArrayList(); m_preparedStatements.add(statement); } final void forgetStatement(PreparedStatement statement) { if(m_preparedStatements == null) return; int idx = m_preparedStatements.size(); while(--idx >= 0) if(m_preparedStatements.get(idx) == statement) { m_preparedStatements.remove(idx); return; } } /** * @param savepoint The savepoint to set. */ final void setSavepoint(PgSavepoint savepoint) { m_savepoint = savepoint; } /** * Called from the backend when the invokation exits. Should * not be invoked any other way. */ public void onExit() throws SQLException { try { if(m_savepoint != null) m_savepoint.onInvocationExit(SPIDriver.getDefault()); if(m_preparedStatements != null) { int idx = m_preparedStatements.size(); if(idx > 0) { Logger w = Logger.getAnonymousLogger(); w.warning( "Closing " + idx + " \"forgotten\" statement" + ((idx > 1) ? "s" : "")); while(--idx >= 0) { PreparedStatement stmt = (PreparedStatement)m_preparedStatements.get(idx); w.fine("Closed: " + stmt); stmt.close(); } } } } finally { s_levels[m_nestingLevel] = null; } } /** * @return The current invocation */ public static Invocation current() { synchronized(Backend.THREADLOCK) { Invocation curr = _getCurrent(); if(curr != null) return curr; int level = _getNestingLevel(); int top = s_levels.length; if(level < top) { curr = s_levels[level]; if(curr != null) { curr._register(); return curr; } } else { int newSize = top; do { newSize <<= 2; } while(newSize <= level); Invocation[] levels = new Invocation[newSize]; System.arraycopy(s_levels, 0, levels, 0, top); s_levels = levels; } curr = new Invocation(level); s_levels[level] = curr; curr._register(); return curr; } } static void clearErrorCondition() { synchronized(Backend.THREADLOCK) { _clearErrorCondition(); } } /** * Register this Invocation so that it receives the onExit callback */ private native void _register(); /** * Returns the current invocation or null if no invocation has been * registered yet. */ private native static Invocation _getCurrent(); /** * Returns the current nesting level */ private native static int _getNestingLevel(); /** * Clears the error condition set by elog(ERROR) */ private native static void _clearErrorCondition(); }