/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2010-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2010-2012, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.internal.sql.table; import java.sql.Connection; import java.sql.SQLException; import java.sql.PreparedStatement; import org.geotoolkit.internal.sql.StatementPool; import org.geotoolkit.internal.sql.StatementEntry; /** * A thread-local pool of {@linkplain PreparedStatement prepared statements}. Every {@link Table} * instances created by the same {@link Database} will share the same cache when executed in the * same thread. However if more than one thread is using the same {@code Table} then each thread * will have its own {@code LocalCache}. With this approach, we guaranteed that a JDBC connection * is used only from the same thread. * * {@section Synchronization} * Every access to a method in this interface must be synchronized on {@code this}. This * synchronization is necessary for preventing the {@link StatementPool} cleaner background * thread to close a statement before the caller finished to use it. The lock shall be * released only when the statement is no longer needed, as below: * * {@preformat java * LocalCache cache = database.getLocalCache(); * synchronized (cache) { * LocalCache.Stmt ce = cache.prepareStatement(table, query); * PreparedStatement statement = ce.statement; * // Use the statement, but don't close it. * release(ce); * } * } * * Note that this is <strong>not</strong> a synchronization mechanism for {@link Table}. * The synchronization on {@code this} is only for blocking the cleaner thread; it has * no impact on other threads. * * @author Martin Desruisseaux (Geomatys) * @version 3.09 * * @since 3.09 * @module */ public interface LocalCache { /** * Returns the connection to the database. Use as below: * * {@preformat java * LocalCache cache = database.getLocalCache(); * synchronized (cache) { * Connection c = cache.connection(); * // Use the connection inside the synchronized block, but don't close it. * } * } * * @return The connection to the database. * @throws SQLException if an error occurred while fetching the connection. */ Connection connection() throws SQLException; /** * Returns a prepared statement for the given SQL query. Every call to this method * shall be performed inside a synchronized block as documented in the class javadoc. * * @param creator The table which is invoking this method. * @param sql The SQL query. * @return The prepared statement. * @throws SQLException if an error occurred while creating the statement. */ Stmt prepareStatement(Table creator, String sql) throws SQLException; /** * The {@link StatementEntry} implementation used in this module. Each instance of this * class shall be used in a single thread only. See the {@link LocalCache} javadoc for * more information. * * @author Martin Desruisseaux (Geomatys) * @version 3.10 * * @since 3.09 * @module */ final class Stmt extends StatementEntry { /** * Special value for {@link #stamp} meaning that the prepared statement * has not yet been initialized. */ static final int UNINITIALIZED = -1; /** * The SQL query used for creating the statement. They are used as keys in the * {@link org.geotoolkit.internal.sql.StatementPool}, and sometime for logging. */ final String sql; /** * A value used by {@link Table} in order to determine if the {@link #statement} * parameters need to be modified. */ int stamp = UNINITIALIZED; /** * The execution start time in nanoseconds, used for logging purpose only. * * @since 3.16 */ long startTime; /** * Constructs a metadata result for the specified statement. * * @param statement The prepared statement. * @param sql The SQL query used for creating the statement. */ Stmt(final PreparedStatement statement, final String sql) { super(statement); this.sql = sql; } /** * Formats this statement. Some implementations (e.g. the PostgreSQL driver) format the * SQL statement together with the parameter values. If it seems to be the case (we check * that by searching for the first word, typically {@code SELECT} or {@code INSERT}), then * returns the string formatted by the driver. Otherwise conservatively returns the value * of the {@link #sql} field, but the later doesn't have the parameter values. * <p> * This method is used only for logging or debugging purpose. */ @Override public String toString() { String keyword = sql.trim(); final int length = keyword.length(); for (int i=0; i<length; i++) { if (Character.isWhitespace(keyword.charAt(i))) { keyword = keyword.substring(0, i); break; } } String s = statement.toString(); final int i = s.indexOf(keyword); if (i >= 0) { s = s.substring(i); } else { s = sql; } return s; } } }