mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	missed a few files
This commit is contained in:
		
							parent
							
								
									2a9bf5b33d
								
							
						
					
					
						commit
						b195c10df7
					
				| @ -1,6 +0,0 @@ | |||||||
| .classpath |  | ||||||
| .project |  | ||||||
| .externalToolBuilders |  | ||||||
| build |  | ||||||
| build.properties |  | ||||||
| jars |  | ||||||
| @ -1 +0,0 @@ | |||||||
| Driver.java |  | ||||||
| @ -1,265 +0,0 @@ | |||||||
| package org.postgresql.jdbc2.optional; |  | ||||||
| 
 |  | ||||||
| import javax.naming.*; |  | ||||||
| import java.io.PrintWriter; |  | ||||||
| import java.sql.*; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Base class for data sources and related classes. |  | ||||||
|  * |  | ||||||
|  * @author Aaron Mulder (ammulder@chariotsolutions.com) |  | ||||||
|  * @version $Revision: 1.3 $ |  | ||||||
|  */ |  | ||||||
| public abstract class BaseDataSource implements Referenceable |  | ||||||
| { |  | ||||||
| 	// Load the normal driver, since we'll use it to actually connect to the |  | ||||||
| 	// database.  That way we don't have to maintain the connecting code in |  | ||||||
| 	// multiple places. |  | ||||||
| 	static { |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			Class.forName("org.postgresql.Driver"); |  | ||||||
| 		} |  | ||||||
| 		catch (ClassNotFoundException e) |  | ||||||
| 		{ |  | ||||||
| 			System.err.println("PostgreSQL DataSource unable to load PostgreSQL JDBC Driver"); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Needed to implement the DataSource/ConnectionPoolDataSource interfaces |  | ||||||
| 	private transient PrintWriter logger; |  | ||||||
| 	// Don't track loginTimeout, since we'd just ignore it anyway |  | ||||||
| 
 |  | ||||||
| 	// Standard properties, defined in the JDBC 2.0 Optional Package spec |  | ||||||
| 	private String serverName = "localhost"; |  | ||||||
| 	private String databaseName; |  | ||||||
| 	private String user; |  | ||||||
| 	private String password; |  | ||||||
| 	private int portNumber; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a connection to the PostgreSQL database.  The database is identified by the |  | ||||||
| 	 * DataSource properties serverName, databaseName, and portNumber.	The user to |  | ||||||
| 	 * connect as is identified by the DataSource properties user and password. |  | ||||||
| 	 * |  | ||||||
| 	 * @return A valid database connection. |  | ||||||
| 	 * @throws SQLException |  | ||||||
| 	 *		   Occurs when the database connection cannot be established. |  | ||||||
| 	 */ |  | ||||||
| 	public Connection getConnection() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		return getConnection(user, password); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a connection to the PostgreSQL database.  The database is identified by the |  | ||||||
| 	 * DataAource properties serverName, databaseName, and portNumber.	The user to |  | ||||||
| 	 * connect as is identified by the arguments user and password, which override |  | ||||||
| 	 * the DataSource properties by the same name. |  | ||||||
| 	 * |  | ||||||
| 	 * @return A valid database connection. |  | ||||||
| 	 * @throws SQLException |  | ||||||
| 	 *		   Occurs when the database connection cannot be established. |  | ||||||
| 	 */ |  | ||||||
| 	public Connection getConnection(String user, String password) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			Connection con = DriverManager.getConnection(getUrl(), user, password); |  | ||||||
| 			if (logger != null) |  | ||||||
| 			{ |  | ||||||
| 				logger.println("Created a non-pooled connection for " + user + " at " + getUrl()); |  | ||||||
| 			} |  | ||||||
| 			return con; |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException e) |  | ||||||
| 		{ |  | ||||||
| 			if (logger != null) |  | ||||||
| 			{ |  | ||||||
| 				logger.println("Failed to create a non-pooled connection for " + user + " at " + getUrl() + ": " + e); |  | ||||||
| 			} |  | ||||||
| 			throw e; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * This DataSource does not support a configurable login timeout. |  | ||||||
| 	 * @return 0 |  | ||||||
| 	 */ |  | ||||||
| 	public int getLoginTimeout() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * This DataSource does not support a configurable login timeout.  Any value |  | ||||||
| 	 * provided here will be ignored. |  | ||||||
| 	 */ |  | ||||||
| 	public void setLoginTimeout(int i) throws SQLException |  | ||||||
| 		{} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the log writer used to log connections opened. |  | ||||||
| 	 */ |  | ||||||
| 	public PrintWriter getLogWriter() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		return logger; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * The DataSource will note every connection opened to the provided log writer. |  | ||||||
| 	 */ |  | ||||||
| 	public void setLogWriter(PrintWriter printWriter) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		logger = printWriter; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the name of the host the PostgreSQL database is running on. |  | ||||||
| 	 */ |  | ||||||
| 	public String getServerName() |  | ||||||
| 	{ |  | ||||||
| 		return serverName; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Sets the name of the host the PostgreSQL database is running on.  If this |  | ||||||
| 	 * is changed, it will only affect future calls to getConnection.  The default |  | ||||||
| 	 * value is <tt>localhost</tt>. |  | ||||||
| 	 */ |  | ||||||
| 	public void setServerName(String serverName) |  | ||||||
| 	{ |  | ||||||
| 		if (serverName == null || serverName.equals("")) |  | ||||||
| 		{ |  | ||||||
| 			this.serverName = "localhost"; |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			this.serverName = serverName; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the name of the PostgreSQL database, running on the server identified |  | ||||||
| 	 * by the serverName property. |  | ||||||
| 	 */ |  | ||||||
| 	public String getDatabaseName() |  | ||||||
| 	{ |  | ||||||
| 		return databaseName; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Sets the name of the PostgreSQL database, running on the server identified |  | ||||||
| 	 * by the serverName property.	If this is changed, it will only affect |  | ||||||
| 	 * future calls to getConnection. |  | ||||||
| 	 */ |  | ||||||
| 	public void setDatabaseName(String databaseName) |  | ||||||
| 	{ |  | ||||||
| 		this.databaseName = databaseName; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a description of this DataSource-ish thing.  Must be customized by |  | ||||||
| 	 * subclasses. |  | ||||||
| 	 */ |  | ||||||
| 	public abstract String getDescription(); |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the user to connect as by default.	If this is not specified, you must |  | ||||||
| 	 * use the getConnection method which takes a user and password as parameters. |  | ||||||
| 	 */ |  | ||||||
| 	public String getUser() |  | ||||||
| 	{ |  | ||||||
| 		return user; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Sets the user to connect as by default.	If this is not specified, you must |  | ||||||
| 	 * use the getConnection method which takes a user and password as parameters. |  | ||||||
| 	 * If this is changed, it will only affect future calls to getConnection. |  | ||||||
| 	 */ |  | ||||||
| 	public void setUser(String user) |  | ||||||
| 	{ |  | ||||||
| 		this.user = user; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the password to connect with by default.  If this is not specified but a |  | ||||||
| 	 * password is needed to log in, you must use the getConnection method which takes |  | ||||||
| 	 * a user and password as parameters. |  | ||||||
| 	 */ |  | ||||||
| 	public String getPassword() |  | ||||||
| 	{ |  | ||||||
| 		return password; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Sets the password to connect with by default.  If this is not specified but a |  | ||||||
| 	 * password is needed to log in, you must use the getConnection method which takes |  | ||||||
| 	 * a user and password as parameters.  If this is changed, it will only affect |  | ||||||
| 	 * future calls to getConnection. |  | ||||||
| 	 */ |  | ||||||
| 	public void setPassword(String password) |  | ||||||
| 	{ |  | ||||||
| 		this.password = password; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the port which the PostgreSQL server is listening on for TCP/IP |  | ||||||
| 	 * connections. |  | ||||||
| 	 * |  | ||||||
| 	 * @return The port, or 0 if the default port will be used. |  | ||||||
| 	 */ |  | ||||||
| 	public int getPortNumber() |  | ||||||
| 	{ |  | ||||||
| 		return portNumber; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the port which the PostgreSQL server is listening on for TCP/IP |  | ||||||
| 	 * connections.  Be sure the -i flag is passed to postmaster when PostgreSQL |  | ||||||
| 	 * is started.	If this is not set, or set to 0, the default port will be used. |  | ||||||
| 	 */ |  | ||||||
| 	public void setPortNumber(int portNumber) |  | ||||||
| 	{ |  | ||||||
| 		this.portNumber = portNumber; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Generates a DriverManager URL from the other properties supplied. |  | ||||||
| 	 */ |  | ||||||
| 	private String getUrl() |  | ||||||
| 	{ |  | ||||||
| 		return "jdbc:postgresql://" + serverName + (portNumber == 0 ? "" : ":" + portNumber) + "/" + databaseName; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Generates a reference using the appropriate object factory.  This |  | ||||||
|      * implementation uses the JDBC 2 optional package object factory. |  | ||||||
|      */ |  | ||||||
|     protected Reference createReference() |  | ||||||
|     { |  | ||||||
|         return new Reference(getClass().getName(), PGObjectFactory.class.getName(), null); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 	public Reference getReference() throws NamingException |  | ||||||
| 	{ |  | ||||||
| 		Reference ref = createReference(); |  | ||||||
| 		ref.add(new StringRefAddr("serverName", serverName)); |  | ||||||
| 		if (portNumber != 0) |  | ||||||
| 		{ |  | ||||||
| 			ref.add(new StringRefAddr("portNumber", Integer.toString(portNumber))); |  | ||||||
| 		} |  | ||||||
| 		ref.add(new StringRefAddr("databaseName", databaseName)); |  | ||||||
| 		if (user != null) |  | ||||||
| 		{ |  | ||||||
| 			ref.add(new StringRefAddr("user", user)); |  | ||||||
| 		} |  | ||||||
| 		if (password != null) |  | ||||||
| 		{ |  | ||||||
| 			ref.add(new StringRefAddr("password", password)); |  | ||||||
| 		} |  | ||||||
| 		return ref; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,82 +0,0 @@ | |||||||
| package org.postgresql.jdbc2.optional; |  | ||||||
| 
 |  | ||||||
| import javax.sql.ConnectionPoolDataSource; |  | ||||||
| import javax.sql.PooledConnection; |  | ||||||
| import java.sql.SQLException; |  | ||||||
| import java.io.Serializable; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * PostgreSQL implementation of ConnectionPoolDataSource.  The app server or |  | ||||||
|  * middleware vendor should provide a DataSource implementation that takes advantage |  | ||||||
|  * of this ConnectionPoolDataSource.  If not, you can use the PostgreSQL implementation |  | ||||||
|  * known as PoolingDataSource, but that should only be used if your server or middleware |  | ||||||
|  * vendor does not provide their own.  Why? The server may want to reuse the same |  | ||||||
|  * Connection across all EJBs requesting a Connection within the same Transaction, or |  | ||||||
|  * provide other similar advanced features. |  | ||||||
|  * |  | ||||||
|  * <p>In any case, in order to use this ConnectionPoolDataSource, you must set the property |  | ||||||
|  * databaseName.  The settings for serverName, portNumber, user, and password are |  | ||||||
|  * optional.  Note: these properties are declared in the superclass.</p> |  | ||||||
|  * |  | ||||||
|  * <p>This implementation supports JDK 1.3 and higher.</p> |  | ||||||
|  * |  | ||||||
|  * @author Aaron Mulder (ammulder@chariotsolutions.com) |  | ||||||
|  * @version $Revision: 1.2 $ |  | ||||||
|  */ |  | ||||||
| public class ConnectionPool extends BaseDataSource implements Serializable, ConnectionPoolDataSource |  | ||||||
| { |  | ||||||
| 	private boolean defaultAutoCommit = false; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a description of this DataSource. |  | ||||||
| 	 */ |  | ||||||
| 	public String getDescription() |  | ||||||
| 	{ |  | ||||||
| 		return "ConnectionPoolDataSource from " + org.postgresql.Driver.getVersion(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a connection which may be pooled by the app server or middleware |  | ||||||
| 	 * implementation of DataSource. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.sql.SQLException |  | ||||||
| 	 *		   Occurs when the physical database connection cannot be established. |  | ||||||
| 	 */ |  | ||||||
| 	public PooledConnection getPooledConnection() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		return new PooledConnectionImpl(getConnection(), defaultAutoCommit); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a connection which may be pooled by the app server or middleware |  | ||||||
| 	 * implementation of DataSource. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.sql.SQLException |  | ||||||
| 	 *		   Occurs when the physical database connection cannot be established. |  | ||||||
| 	 */ |  | ||||||
| 	public PooledConnection getPooledConnection(String user, String password) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		return new PooledConnectionImpl(getConnection(user, password), defaultAutoCommit); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets whether connections supplied by this pool will have autoCommit |  | ||||||
| 	 * turned on by default.  The default value is <tt>false</tt>, so that |  | ||||||
| 	 * autoCommit will be turned off by default. |  | ||||||
| 	 */ |  | ||||||
| 	public boolean isDefaultAutoCommit() |  | ||||||
| 	{ |  | ||||||
| 		return defaultAutoCommit; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Sets whether connections supplied by this pool will have autoCommit |  | ||||||
| 	 * turned on by default.  The default value is <tt>false</tt>, so that |  | ||||||
| 	 * autoCommit will be turned off by default. |  | ||||||
| 	 */ |  | ||||||
| 	public void setDefaultAutoCommit(boolean defaultAutoCommit) |  | ||||||
| 	{ |  | ||||||
| 		this.defaultAutoCommit = defaultAutoCommit; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,108 +0,0 @@ | |||||||
| package org.postgresql.jdbc2.optional; |  | ||||||
| 
 |  | ||||||
| import javax.naming.spi.ObjectFactory; |  | ||||||
| import javax.naming.*; |  | ||||||
| import java.util.Hashtable; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Returns a DataSource-ish thing based on a JNDI reference.  In the case of a |  | ||||||
|  * SimpleDataSource or ConnectionPool, a new instance is created each time, as |  | ||||||
|  * there is no connection state to maintain. In the case of a PoolingDataSource, |  | ||||||
|  * the same DataSource will be returned for every invocation within the same |  | ||||||
|  * VM/ClassLoader, so that the state of the connections in the pool will be |  | ||||||
|  * consistent. |  | ||||||
|  * |  | ||||||
|  * @author Aaron Mulder (ammulder@chariotsolutions.com) |  | ||||||
|  * @version $Revision: 1.3 $ |  | ||||||
|  */ |  | ||||||
| public class PGObjectFactory implements ObjectFactory |  | ||||||
| { |  | ||||||
| 	/** |  | ||||||
| 	 * Dereferences a PostgreSQL DataSource.  Other types of references are |  | ||||||
| 	 * ignored. |  | ||||||
| 	 */ |  | ||||||
| 	public Object getObjectInstance(Object obj, Name name, Context nameCtx, |  | ||||||
| 									Hashtable environment) throws Exception |  | ||||||
| 	{ |  | ||||||
| 		Reference ref = (Reference)obj; |  | ||||||
| 		if (ref.getClassName().equals(SimpleDataSource.class.getName())) |  | ||||||
| 		{ |  | ||||||
| 			return loadSimpleDataSource(ref); |  | ||||||
| 		} |  | ||||||
| 		else if (ref.getClassName().equals(ConnectionPool.class.getName())) |  | ||||||
| 		{ |  | ||||||
| 			return loadConnectionPool(ref); |  | ||||||
| 		} |  | ||||||
| 		else if (ref.getClassName().equals(PoolingDataSource.class.getName())) |  | ||||||
| 		{ |  | ||||||
| 			return loadPoolingDataSource(ref); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			return null; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private Object loadPoolingDataSource(Reference ref) |  | ||||||
| 	{ |  | ||||||
| 		// If DataSource exists, return it |  | ||||||
| 		String name = getProperty(ref, "dataSourceName"); |  | ||||||
| 		PoolingDataSource pds = PoolingDataSource.getDataSource(name); |  | ||||||
| 		if (pds != null) |  | ||||||
| 		{ |  | ||||||
| 			return pds; |  | ||||||
| 		} |  | ||||||
| 		// Otherwise, create a new one |  | ||||||
| 		pds = new PoolingDataSource(); |  | ||||||
| 		pds.setDataSourceName(name); |  | ||||||
| 		loadBaseDataSource(pds, ref); |  | ||||||
| 		String min = getProperty(ref, "initialConnections"); |  | ||||||
| 		if (min != null) |  | ||||||
| 		{ |  | ||||||
| 			pds.setInitialConnections(Integer.parseInt(min)); |  | ||||||
| 		} |  | ||||||
| 		String max = getProperty(ref, "maxConnections"); |  | ||||||
| 		if (max != null) |  | ||||||
| 		{ |  | ||||||
| 			pds.setMaxConnections(Integer.parseInt(max)); |  | ||||||
| 		} |  | ||||||
| 		return pds; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private Object loadSimpleDataSource(Reference ref) |  | ||||||
| 	{ |  | ||||||
| 		SimpleDataSource ds = new SimpleDataSource(); |  | ||||||
| 		return loadBaseDataSource(ds, ref); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private Object loadConnectionPool(Reference ref) |  | ||||||
| 	{ |  | ||||||
| 		ConnectionPool cp = new ConnectionPool(); |  | ||||||
| 		return loadBaseDataSource(cp, ref); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	protected Object loadBaseDataSource(BaseDataSource ds, Reference ref) |  | ||||||
| 	{ |  | ||||||
| 		ds.setDatabaseName(getProperty(ref, "databaseName")); |  | ||||||
| 		ds.setPassword(getProperty(ref, "password")); |  | ||||||
| 		String port = getProperty(ref, "portNumber"); |  | ||||||
| 		if (port != null) |  | ||||||
| 		{ |  | ||||||
| 			ds.setPortNumber(Integer.parseInt(port)); |  | ||||||
| 		} |  | ||||||
| 		ds.setServerName(getProperty(ref, "serverName")); |  | ||||||
| 		ds.setUser(getProperty(ref, "user")); |  | ||||||
| 		return ds; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
|     protected String getProperty(Reference ref, String s) |  | ||||||
| 	{ |  | ||||||
| 		RefAddr addr = ref.get(s); |  | ||||||
| 		if (addr == null) |  | ||||||
| 		{ |  | ||||||
| 			return null; |  | ||||||
| 		} |  | ||||||
| 		return (String)addr.getContent(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,392 +0,0 @@ | |||||||
| package org.postgresql.jdbc2.optional; |  | ||||||
| 
 |  | ||||||
| import javax.sql.*; |  | ||||||
| import java.sql.*; |  | ||||||
| import java.util.*; |  | ||||||
| import java.lang.reflect.*; |  | ||||||
| import org.postgresql.PGConnection; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * PostgreSQL implementation of the PooledConnection interface.  This shouldn't |  | ||||||
|  * be used directly, as the pooling client should just interact with the |  | ||||||
|  * ConnectionPool instead. |  | ||||||
|  * @see ConnectionPool |  | ||||||
|  * |  | ||||||
|  * @author Aaron Mulder (ammulder@chariotsolutions.com) |  | ||||||
|  * @author Csaba Nagy (ncsaba@yahoo.com) |  | ||||||
|  * @version $Revision: 1.8 $ |  | ||||||
|  */ |  | ||||||
| public class PooledConnectionImpl implements PooledConnection |  | ||||||
| { |  | ||||||
| 	private List listeners = new LinkedList(); |  | ||||||
| 	private Connection con; |  | ||||||
| 	private ConnectionHandler last; |  | ||||||
| 	private boolean autoCommit; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Creates a new PooledConnection representing the specified physical |  | ||||||
| 	 * connection. |  | ||||||
| 	 */ |  | ||||||
| 	protected PooledConnectionImpl(Connection con, boolean autoCommit) |  | ||||||
| 	{ |  | ||||||
| 		this.con = con; |  | ||||||
| 		this.autoCommit = autoCommit; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Adds a listener for close or fatal error events on the connection |  | ||||||
| 	 * handed out to a client. |  | ||||||
| 	 */ |  | ||||||
| 	public void addConnectionEventListener(ConnectionEventListener connectionEventListener) |  | ||||||
| 	{ |  | ||||||
| 		listeners.add(connectionEventListener); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Removes a listener for close or fatal error events on the connection |  | ||||||
| 	 * handed out to a client. |  | ||||||
| 	 */ |  | ||||||
| 	public void removeConnectionEventListener(ConnectionEventListener connectionEventListener) |  | ||||||
| 	{ |  | ||||||
| 		listeners.remove(connectionEventListener); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Closes the physical database connection represented by this |  | ||||||
| 	 * PooledConnection.  If any client has a connection based on |  | ||||||
| 	 * this PooledConnection, it is forcibly closed as well. |  | ||||||
| 	 */ |  | ||||||
| 	public void close() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		if (last != null) |  | ||||||
| 		{ |  | ||||||
| 			last.close(); |  | ||||||
| 			if (!con.getAutoCommit()) |  | ||||||
| 			{ |  | ||||||
| 				try |  | ||||||
| 				{ |  | ||||||
| 					con.rollback(); |  | ||||||
| 				} |  | ||||||
| 				catch (SQLException e) |  | ||||||
| 				{} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			con.close(); |  | ||||||
| 		} |  | ||||||
| 		finally |  | ||||||
| 		{ |  | ||||||
| 			con = null; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a handle for a client to use.  This is a wrapper around the |  | ||||||
| 	 * physical connection, so the client can call close and it will just |  | ||||||
| 	 * return the connection to the pool without really closing the |  | ||||||
| 	 * pgysical connection. |  | ||||||
| 	 * |  | ||||||
| 	 * <p>According to the JDBC 2.0 Optional Package spec (6.2.3), only one |  | ||||||
| 	 * client may have an active handle to the connection at a time, so if |  | ||||||
| 	 * there is a previous handle active when this is called, the previous |  | ||||||
| 	 * one is forcibly closed and its work rolled back.</p> |  | ||||||
| 	 */ |  | ||||||
| 	public Connection getConnection() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		if (con == null) |  | ||||||
| 		{ |  | ||||||
| 			// Before throwing the exception, let's notify the registered listeners about the error |  | ||||||
| 			final SQLException sqlException = new SQLException("This PooledConnection has already been closed!"); |  | ||||||
| 			fireConnectionFatalError(sqlException); |  | ||||||
| 			throw sqlException; |  | ||||||
| 		} |  | ||||||
| 		// If any error occures while opening a new connection, the listeners |  | ||||||
| 		// have to be notified. This gives a chance to connection pools to |  | ||||||
| 		// elliminate bad pooled connections. |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			// Only one connection can be open at a time from this PooledConnection.  See JDBC 2.0 Optional Package spec section 6.2.3 |  | ||||||
| 			if (last != null) |  | ||||||
| 			{ |  | ||||||
| 				last.close(); |  | ||||||
| 				if (!con.getAutoCommit()) |  | ||||||
| 				{ |  | ||||||
| 					try |  | ||||||
| 					{ |  | ||||||
| 						con.rollback(); |  | ||||||
| 					} |  | ||||||
| 					catch (SQLException e) |  | ||||||
| 					{} |  | ||||||
| 				} |  | ||||||
| 				con.clearWarnings(); |  | ||||||
| 			} |  | ||||||
| 			con.setAutoCommit(autoCommit); |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException sqlException) |  | ||||||
| 		{ |  | ||||||
| 			fireConnectionFatalError(sqlException); |  | ||||||
| 			throw (SQLException)sqlException.fillInStackTrace(); |  | ||||||
| 		} |  | ||||||
| 		ConnectionHandler handler = new ConnectionHandler(con); |  | ||||||
| 		last = handler; |  | ||||||
| 		Connection con = (Connection)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Connection.class, PGConnection.class}, handler); |  | ||||||
| 		last.setProxy(con); |  | ||||||
| 		return con; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Used to fire a connection closed event to all listeners. |  | ||||||
| 	 */ |  | ||||||
| 	void fireConnectionClosed() |  | ||||||
| 	{ |  | ||||||
| 		ConnectionEvent evt = null; |  | ||||||
| 		// Copy the listener list so the listener can remove itself during this method call |  | ||||||
| 		ConnectionEventListener[] local = (ConnectionEventListener[]) listeners.toArray(new ConnectionEventListener[listeners.size()]); |  | ||||||
| 		for (int i = 0; i < local.length; i++) |  | ||||||
| 		{ |  | ||||||
| 			ConnectionEventListener listener = local[i]; |  | ||||||
| 			if (evt == null) |  | ||||||
| 			{ |  | ||||||
| 				evt = new ConnectionEvent(this); |  | ||||||
| 			} |  | ||||||
| 			listener.connectionClosed(evt); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Used to fire a connection error event to all listeners. |  | ||||||
| 	 */ |  | ||||||
| 	void fireConnectionFatalError(SQLException e) |  | ||||||
| 	{ |  | ||||||
| 		ConnectionEvent evt = null; |  | ||||||
| 		// Copy the listener list so the listener can remove itself during this method call |  | ||||||
| 		ConnectionEventListener[] local = (ConnectionEventListener[])listeners.toArray(new ConnectionEventListener[listeners.size()]); |  | ||||||
| 		for (int i = 0; i < local.length; i++) |  | ||||||
| 		{ |  | ||||||
| 			ConnectionEventListener listener = local[i]; |  | ||||||
| 			if (evt == null) |  | ||||||
| 			{ |  | ||||||
| 				evt = new ConnectionEvent(this, e); |  | ||||||
| 			} |  | ||||||
| 			listener.connectionErrorOccurred(evt); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Instead of declaring a class implementing Connection, which would have |  | ||||||
| 	 * to be updated for every JDK rev, use a dynamic proxy to handle all |  | ||||||
| 	 * calls through the Connection interface.	This is the part that |  | ||||||
| 	 * requires JDK 1.3 or higher, though JDK 1.2 could be supported with a |  | ||||||
| 	 * 3rd-party proxy package. |  | ||||||
| 	 */ |  | ||||||
| 	private class ConnectionHandler implements InvocationHandler |  | ||||||
| 	{ |  | ||||||
| 		private Connection con; |  | ||||||
|         private Connection proxy; // the Connection the client is currently using, which is a proxy |  | ||||||
| 		private boolean automatic = false; |  | ||||||
| 
 |  | ||||||
| 		public ConnectionHandler(Connection con) |  | ||||||
| 		{ |  | ||||||
| 			this.con = con; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public Object invoke(Object proxy, Method method, Object[] args) |  | ||||||
| 		throws Throwable |  | ||||||
| 		{ |  | ||||||
| 			// From Object |  | ||||||
| 			if (method.getDeclaringClass().getName().equals("java.lang.Object")) |  | ||||||
| 			{ |  | ||||||
| 				if (method.getName().equals("toString")) |  | ||||||
| 				{ |  | ||||||
| 					return "Pooled connection wrapping physical connection " + con; |  | ||||||
| 				} |  | ||||||
| 				if (method.getName().equals("hashCode")) |  | ||||||
| 				{ |  | ||||||
| 					return new Integer(con.hashCode()); |  | ||||||
| 				} |  | ||||||
| 				if (method.getName().equals("equals")) |  | ||||||
| 				{ |  | ||||||
| 					if (args[0] == null) |  | ||||||
| 					{ |  | ||||||
| 						return Boolean.FALSE; |  | ||||||
| 					} |  | ||||||
| 					try |  | ||||||
| 					{ |  | ||||||
| 						return Proxy.isProxyClass(args[0].getClass()) && ((ConnectionHandler) Proxy.getInvocationHandler(args[0])).con == con ? Boolean.TRUE : Boolean.FALSE; |  | ||||||
| 					} |  | ||||||
| 					catch (ClassCastException e) |  | ||||||
| 					{ |  | ||||||
| 						return Boolean.FALSE; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
|                                 try |  | ||||||
|                                 { |  | ||||||
|                                     return method.invoke(con, args); |  | ||||||
|                                 } |  | ||||||
|                                 catch (InvocationTargetException e) |  | ||||||
|                                 { |  | ||||||
|                                     throw e.getTargetException(); |  | ||||||
|                                 } |  | ||||||
| 			} |  | ||||||
| 			// All the rest is from the Connection or PGConnection interface |  | ||||||
| 			if (method.getName().equals("isClosed")) |  | ||||||
| 			{ |  | ||||||
| 				return con == null ? Boolean.TRUE : Boolean.FALSE; |  | ||||||
| 			} |  | ||||||
| 			if (con == null) |  | ||||||
| 			{ |  | ||||||
| 				throw new SQLException(automatic ? "Connection has been closed automatically because a new connection was opened for the same PooledConnection or the PooledConnection has been closed" : "Connection has been closed"); |  | ||||||
| 			} |  | ||||||
| 			if (method.getName().equals("close")) |  | ||||||
| 			{ |  | ||||||
| 				SQLException ex = null; |  | ||||||
| 				if (!con.getAutoCommit()) |  | ||||||
| 				{ |  | ||||||
| 					try |  | ||||||
| 					{ |  | ||||||
| 						con.rollback(); |  | ||||||
| 					} |  | ||||||
| 					catch (SQLException e) |  | ||||||
| 					{ |  | ||||||
| 						ex = e; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				con.clearWarnings(); |  | ||||||
| 				con = null; |  | ||||||
|                 proxy = null; |  | ||||||
| 				last = null; |  | ||||||
| 				fireConnectionClosed(); |  | ||||||
| 				if (ex != null) |  | ||||||
| 				{ |  | ||||||
| 					throw ex; |  | ||||||
| 				} |  | ||||||
| 				return null; |  | ||||||
| 			} |  | ||||||
|             else if(method.getName().equals("createStatement")) |  | ||||||
|             { |  | ||||||
|                 Statement st = (Statement)method.invoke(con, args); |  | ||||||
|                 return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Statement.class, org.postgresql.PGStatement.class}, new StatementHandler(this, st)); |  | ||||||
|             } |  | ||||||
|             else if(method.getName().equals("prepareCall")) |  | ||||||
|             { |  | ||||||
|                 Statement st = (Statement)method.invoke(con, args); |  | ||||||
|                 return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{CallableStatement.class, org.postgresql.PGStatement.class}, new StatementHandler(this, st)); |  | ||||||
|             } |  | ||||||
|             else if(method.getName().equals("prepareStatement")) |  | ||||||
|             { |  | ||||||
|                 Statement st = (Statement)method.invoke(con, args); |  | ||||||
|                 return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{PreparedStatement.class, org.postgresql.PGStatement.class}, new StatementHandler(this, st)); |  | ||||||
|             } |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				return method.invoke(con, args); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
|         Connection getProxy() { |  | ||||||
|             return proxy; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setProxy(Connection proxy) { |  | ||||||
|             this.proxy = proxy; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
| 		public void close() |  | ||||||
| 		{ |  | ||||||
| 			if (con != null) |  | ||||||
| 			{ |  | ||||||
| 				automatic = true; |  | ||||||
| 			} |  | ||||||
| 			con = null; |  | ||||||
|             proxy = null; |  | ||||||
| 			// No close event fired here: see JDBC 2.0 Optional Package spec section 6.3 |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
|         public boolean isClosed() { |  | ||||||
|             return con == null; |  | ||||||
|         } |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Instead of declaring classes implementing Statement, PreparedStatement, |  | ||||||
|      * and CallableStatement, which would have to be updated for every JDK rev, |  | ||||||
|      * use a dynamic proxy to handle all calls through the Statement |  | ||||||
|      * interfaces.	This is the part that requires JDK 1.3 or higher, though |  | ||||||
|      * JDK 1.2 could be supported with a 3rd-party proxy package. |  | ||||||
|      * |  | ||||||
|      * The StatementHandler is required in order to return the proper |  | ||||||
|      * Connection proxy for the getConnection method. |  | ||||||
|      */ |  | ||||||
|     private static class StatementHandler implements InvocationHandler { |  | ||||||
|         private ConnectionHandler con; |  | ||||||
|         private Statement st; |  | ||||||
| 
 |  | ||||||
|         public StatementHandler(ConnectionHandler con, Statement st) { |  | ||||||
|             this.con = con; |  | ||||||
|             this.st = st; |  | ||||||
|         } |  | ||||||
|         public Object invoke(Object proxy, Method method, Object[] args) |  | ||||||
|         throws Throwable |  | ||||||
|         { |  | ||||||
|             // From Object |  | ||||||
|             if (method.getDeclaringClass().getName().equals("java.lang.Object")) |  | ||||||
|             { |  | ||||||
|                 if (method.getName().equals("toString")) |  | ||||||
|                 { |  | ||||||
|                     return "Pooled statement wrapping physical statement " + st; |  | ||||||
|                 } |  | ||||||
|                 if (method.getName().equals("hashCode")) |  | ||||||
|                 { |  | ||||||
|                     return new Integer(st.hashCode()); |  | ||||||
|                 } |  | ||||||
|                 if (method.getName().equals("equals")) |  | ||||||
|                 { |  | ||||||
|                     if (args[0] == null) |  | ||||||
|                     { |  | ||||||
|                         return Boolean.FALSE; |  | ||||||
|                     } |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         return Proxy.isProxyClass(args[0].getClass()) && ((StatementHandler) Proxy.getInvocationHandler(args[0])).st == st ? Boolean.TRUE : Boolean.FALSE; |  | ||||||
|                     } |  | ||||||
|                     catch (ClassCastException e) |  | ||||||
|                     { |  | ||||||
|                         return Boolean.FALSE; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 return method.invoke(st, args); |  | ||||||
|             } |  | ||||||
|             // All the rest is from the Statement interface |  | ||||||
|             if (st == null || con.isClosed()) |  | ||||||
|             { |  | ||||||
|                 throw new SQLException("Statement has been closed"); |  | ||||||
|             } |  | ||||||
|             if (method.getName().equals("close")) |  | ||||||
|             { |  | ||||||
|                 try { |  | ||||||
|                     st.close(); |  | ||||||
|                 } finally { |  | ||||||
|                     con = null; |  | ||||||
|                     st = null; |  | ||||||
|                     return null; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             else if (method.getName().equals("getConnection")) |  | ||||||
|             { |  | ||||||
|                 return con.getProxy(); // the proxied connection, not a physical connection |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     return method.invoke(st, args); |  | ||||||
|                 } |  | ||||||
|                 catch (InvocationTargetException e) |  | ||||||
|                 { |  | ||||||
|                     throw e.getTargetException(); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,494 +0,0 @@ | |||||||
| package org.postgresql.jdbc2.optional; |  | ||||||
| 
 |  | ||||||
| import javax.sql.*; |  | ||||||
| import javax.naming.*; |  | ||||||
| import java.util.*; |  | ||||||
| import java.sql.Connection; |  | ||||||
| import java.sql.SQLException; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * DataSource which uses connection pooling.  <font color="red">Don't use this if |  | ||||||
|  * your server/middleware vendor provides a connection pooling implementation |  | ||||||
|  * which interfaces with the PostgreSQL ConnectionPoolDataSource implementation!</font> |  | ||||||
|  * This class is provided as a convenience, but the JDBC Driver is really not |  | ||||||
|  * supposed to handle the connection pooling algorithm.  Instead, the server or |  | ||||||
|  * middleware product is supposed to handle the mechanics of connection pooling, |  | ||||||
|  * and use the PostgreSQL implementation of ConnectionPoolDataSource to provide |  | ||||||
|  * the connections to pool. |  | ||||||
|  * |  | ||||||
|  * <p>If you're sure you want to use this, then you must set the properties |  | ||||||
|  * dataSourceName, databaseName, user, and password (if required for the user). |  | ||||||
|  * The settings for serverName, portNumber, initialConnections, and |  | ||||||
|  * maxConnections are optional.  Note that <i>only connections |  | ||||||
|  * for the default user will be pooled!</i>  Connections for other users will |  | ||||||
|  * be normal non-pooled connections, and will not count against the maximum pool |  | ||||||
|  * size limit.</p> |  | ||||||
|  * |  | ||||||
|  * <p>If you put this DataSource in JNDI, and access it from different JVMs (or |  | ||||||
|  * otherwise load this class from different ClassLoaders), you'll end up with one |  | ||||||
|  * pool per ClassLoader or VM.	This is another area where a server-specific |  | ||||||
|  * implementation may provide advanced features, such as using a single pool |  | ||||||
|  * across all VMs in a cluster.</p> |  | ||||||
|  * |  | ||||||
|  * <p>This implementation supports JDK 1.3 and higher.</p> |  | ||||||
|  * |  | ||||||
|  * @author Aaron Mulder (ammulder@chariotsolutions.com) |  | ||||||
|  * @version $Revision: 1.3 $ |  | ||||||
|  */ |  | ||||||
| public class PoolingDataSource extends BaseDataSource implements DataSource |  | ||||||
| { |  | ||||||
| 	private static Map dataSources = new HashMap(); |  | ||||||
| 
 |  | ||||||
| 	static PoolingDataSource getDataSource(String name) |  | ||||||
| 	{ |  | ||||||
| 		return (PoolingDataSource)dataSources.get(name); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Additional Data Source properties |  | ||||||
| 	protected String dataSourceName;  // Must be protected for subclasses to sync updates to it |  | ||||||
| 	private int initialConnections = 0; |  | ||||||
| 	private int maxConnections = 0; |  | ||||||
| 	// State variables |  | ||||||
| 	private boolean initialized = false; |  | ||||||
| 	private Stack available = new Stack(); |  | ||||||
| 	private Stack used = new Stack(); |  | ||||||
| 	private Object lock = new Object(); |  | ||||||
| 	private ConnectionPool source; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a description of this DataSource. |  | ||||||
| 	 */ |  | ||||||
| 	public String getDescription() |  | ||||||
| 	{ |  | ||||||
| 		return "Pooling DataSource '" + dataSourceName + " from " + org.postgresql.Driver.getVersion(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Ensures the DataSource properties are not changed after the DataSource has |  | ||||||
| 	 * been used. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.lang.IllegalStateException |  | ||||||
| 	 *		   The Server Name cannot be changed after the DataSource has been |  | ||||||
| 	 *		   used. |  | ||||||
| 	 */ |  | ||||||
| 	public void setServerName(String serverName) |  | ||||||
| 	{ |  | ||||||
| 		if (initialized) |  | ||||||
| 		{ |  | ||||||
| 			throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); |  | ||||||
| 		} |  | ||||||
| 		super.setServerName(serverName); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Ensures the DataSource properties are not changed after the DataSource has |  | ||||||
| 	 * been used. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.lang.IllegalStateException |  | ||||||
| 	 *		   The Database Name cannot be changed after the DataSource has been |  | ||||||
| 	 *		   used. |  | ||||||
| 	 */ |  | ||||||
| 	public void setDatabaseName(String databaseName) |  | ||||||
| 	{ |  | ||||||
| 		if (initialized) |  | ||||||
| 		{ |  | ||||||
| 			throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); |  | ||||||
| 		} |  | ||||||
| 		super.setDatabaseName(databaseName); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Ensures the DataSource properties are not changed after the DataSource has |  | ||||||
| 	 * been used. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.lang.IllegalStateException |  | ||||||
| 	 *		   The User cannot be changed after the DataSource has been |  | ||||||
| 	 *		   used. |  | ||||||
| 	 */ |  | ||||||
| 	public void setUser(String user) |  | ||||||
| 	{ |  | ||||||
| 		if (initialized) |  | ||||||
| 		{ |  | ||||||
| 			throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); |  | ||||||
| 		} |  | ||||||
| 		super.setUser(user); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Ensures the DataSource properties are not changed after the DataSource has |  | ||||||
| 	 * been used. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.lang.IllegalStateException |  | ||||||
| 	 *		   The Password cannot be changed after the DataSource has been |  | ||||||
| 	 *		   used. |  | ||||||
| 	 */ |  | ||||||
| 	public void setPassword(String password) |  | ||||||
| 	{ |  | ||||||
| 		if (initialized) |  | ||||||
| 		{ |  | ||||||
| 			throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); |  | ||||||
| 		} |  | ||||||
| 		super.setPassword(password); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Ensures the DataSource properties are not changed after the DataSource has |  | ||||||
| 	 * been used. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.lang.IllegalStateException |  | ||||||
| 	 *		   The Port Number cannot be changed after the DataSource has been |  | ||||||
| 	 *		   used. |  | ||||||
| 	 */ |  | ||||||
| 	public void setPortNumber(int portNumber) |  | ||||||
| 	{ |  | ||||||
| 		if (initialized) |  | ||||||
| 		{ |  | ||||||
| 			throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); |  | ||||||
| 		} |  | ||||||
| 		super.setPortNumber(portNumber); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the number of connections that will be created when this DataSource |  | ||||||
| 	 * is initialized.	If you do not call initialize explicitly, it will be |  | ||||||
| 	 * initialized the first time a connection is drawn from it. |  | ||||||
| 	 */ |  | ||||||
| 	public int getInitialConnections() |  | ||||||
| 	{ |  | ||||||
| 		return initialConnections; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Sets the number of connections that will be created when this DataSource |  | ||||||
| 	 * is initialized.	If you do not call initialize explicitly, it will be |  | ||||||
| 	 * initialized the first time a connection is drawn from it. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.lang.IllegalStateException |  | ||||||
| 	 *		   The Initial Connections cannot be changed after the DataSource has been |  | ||||||
| 	 *		   used. |  | ||||||
| 	 */ |  | ||||||
| 	public void setInitialConnections(int initialConnections) |  | ||||||
| 	{ |  | ||||||
| 		if (initialized) |  | ||||||
| 		{ |  | ||||||
| 			throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); |  | ||||||
| 		} |  | ||||||
| 		this.initialConnections = initialConnections; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the maximum number of connections that the pool will allow.  If a request |  | ||||||
| 	 * comes in and this many connections are in use, the request will block until a |  | ||||||
| 	 * connection is available.  Note that connections for a user other than the |  | ||||||
| 	 * default user will not be pooled and don't count against this limit. |  | ||||||
| 	 * |  | ||||||
| 	 * @return The maximum number of pooled connection allowed, or 0 for no maximum. |  | ||||||
| 	 */ |  | ||||||
| 	public int getMaxConnections() |  | ||||||
| 	{ |  | ||||||
| 		return maxConnections; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Sets the maximum number of connections that the pool will allow.  If a request |  | ||||||
| 	 * comes in and this many connections are in use, the request will block until a |  | ||||||
| 	 * connection is available.  Note that connections for a user other than the |  | ||||||
| 	 * default user will not be pooled and don't count against this limit. |  | ||||||
| 	 * |  | ||||||
| 	 * @param maxConnections The maximum number of pooled connection to allow, or |  | ||||||
| 	 *		  0 for no maximum. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.lang.IllegalStateException |  | ||||||
| 	 *		   The Maximum Connections cannot be changed after the DataSource has been |  | ||||||
| 	 *		   used. |  | ||||||
| 	 */ |  | ||||||
| 	public void setMaxConnections(int maxConnections) |  | ||||||
| 	{ |  | ||||||
| 		if (initialized) |  | ||||||
| 		{ |  | ||||||
| 			throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); |  | ||||||
| 		} |  | ||||||
| 		this.maxConnections = maxConnections; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the name of this DataSource.  This uniquely identifies the DataSource. |  | ||||||
| 	 * You cannot use more than one DataSource in the same VM with the same name. |  | ||||||
| 	 */ |  | ||||||
| 	public String getDataSourceName() |  | ||||||
| 	{ |  | ||||||
| 		return dataSourceName; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Sets the name of this DataSource.  This is required, and uniquely identifies |  | ||||||
| 	 * the DataSource.	You cannot create or use more than one DataSource in the |  | ||||||
| 	 * same VM with the same name. |  | ||||||
| 	 * |  | ||||||
| 	 * @throws java.lang.IllegalStateException |  | ||||||
| 	 *		   The Data Source Name cannot be changed after the DataSource has been |  | ||||||
| 	 *		   used. |  | ||||||
| 	 * @throws java.lang.IllegalArgumentException |  | ||||||
| 	 *		   Another PoolingDataSource with the same dataSourceName already |  | ||||||
| 	 *		   exists. |  | ||||||
| 	 */ |  | ||||||
| 	public void setDataSourceName(String dataSourceName) |  | ||||||
| 	{ |  | ||||||
| 		if (initialized) |  | ||||||
| 		{ |  | ||||||
| 			throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); |  | ||||||
| 		} |  | ||||||
| 		if (this.dataSourceName != null && dataSourceName != null && dataSourceName.equals(this.dataSourceName)) |  | ||||||
| 		{ |  | ||||||
| 			return ; |  | ||||||
| 		} |  | ||||||
| 		synchronized (dataSources) |  | ||||||
| 		{ |  | ||||||
| 			if (getDataSource(dataSourceName) != null) |  | ||||||
| 			{ |  | ||||||
| 				throw new IllegalArgumentException("DataSource with name '" + dataSourceName + "' already exists!"); |  | ||||||
| 			} |  | ||||||
| 			if (this.dataSourceName != null) |  | ||||||
| 			{ |  | ||||||
| 				dataSources.remove(this.dataSourceName); |  | ||||||
| 			} |  | ||||||
| 			this.dataSourceName = dataSourceName; |  | ||||||
| 			dataSources.put(dataSourceName, this); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Initializes this DataSource.  If the initialConnections is greater than zero, |  | ||||||
| 	 * that number of connections will be created.	After this method is called, |  | ||||||
| 	 * the DataSource properties cannot be changed.  If you do not call this |  | ||||||
| 	 * explicitly, it will be called the first time you get a connection from the |  | ||||||
| 	 * DataSource. |  | ||||||
| 	 * @throws java.sql.SQLException |  | ||||||
| 	 *		   Occurs when the initialConnections is greater than zero, but the |  | ||||||
| 	 *		   DataSource is not able to create enough physical connections. |  | ||||||
| 	 */ |  | ||||||
| 	public void initialize() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		synchronized (lock) |  | ||||||
| 		{ |  | ||||||
| 			source = createConnectionPool(); |  | ||||||
| 			source.setDatabaseName(getDatabaseName()); |  | ||||||
| 			source.setPassword(getPassword()); |  | ||||||
| 			source.setPortNumber(getPortNumber()); |  | ||||||
| 			source.setServerName(getServerName()); |  | ||||||
| 			source.setUser(getUser()); |  | ||||||
| 			while (available.size() < initialConnections) |  | ||||||
| 			{ |  | ||||||
| 				available.push(source.getPooledConnection()); |  | ||||||
| 			} |  | ||||||
| 			initialized = true; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
|     protected boolean isInitialized() { |  | ||||||
|         return initialized; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Creates the appropriate ConnectionPool to use for this DataSource. |  | ||||||
|      */ |  | ||||||
|     protected ConnectionPool createConnectionPool() { |  | ||||||
|         return new ConnectionPool(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a <b>non-pooled</b> connection, unless the user and password are the |  | ||||||
| 	 * same as the default values for this connection pool. |  | ||||||
| 	 * |  | ||||||
| 	 * @return A pooled connection. |  | ||||||
| 	 * @throws SQLException |  | ||||||
| 	 *		   Occurs when no pooled connection is available, and a new physical |  | ||||||
| 	 *		   connection cannot be created. |  | ||||||
| 	 */ |  | ||||||
| 	public Connection getConnection(String user, String password) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		// If this is for the default user/password, use a pooled connection |  | ||||||
| 		if (user == null || |  | ||||||
| 				(user.equals(getUser()) && ((password == null && getPassword() == null) || (password != null && password.equals(getPassword()))))) |  | ||||||
| 		{ |  | ||||||
| 			return getConnection(); |  | ||||||
| 		} |  | ||||||
| 		// Otherwise, use a non-pooled connection |  | ||||||
| 		if (!initialized) |  | ||||||
| 		{ |  | ||||||
| 			initialize(); |  | ||||||
| 		} |  | ||||||
| 		return super.getConnection(user, password); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a connection from the connection pool. |  | ||||||
| 	 * |  | ||||||
| 	 * @return A pooled connection. |  | ||||||
| 	 * @throws SQLException |  | ||||||
| 	 *		   Occurs when no pooled connection is available, and a new physical |  | ||||||
| 	 *		   connection cannot be created. |  | ||||||
| 	 */ |  | ||||||
| 	public Connection getConnection() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		if (!initialized) |  | ||||||
| 		{ |  | ||||||
| 			initialize(); |  | ||||||
| 		} |  | ||||||
| 		return getPooledConnection(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Closes this DataSource, and all the pooled connections, whether in use or not. |  | ||||||
| 	 */ |  | ||||||
| 	public void close() |  | ||||||
| 	{ |  | ||||||
| 		synchronized (lock) |  | ||||||
| 		{ |  | ||||||
| 			while (available.size() > 0) |  | ||||||
| 			{ |  | ||||||
| 				PooledConnectionImpl pci = (PooledConnectionImpl)available.pop(); |  | ||||||
| 				try |  | ||||||
| 				{ |  | ||||||
| 					pci.close(); |  | ||||||
| 				} |  | ||||||
| 				catch (SQLException e) |  | ||||||
| 				{} |  | ||||||
| 			} |  | ||||||
| 			available = null; |  | ||||||
| 			while (used.size() > 0) |  | ||||||
| 			{ |  | ||||||
| 				PooledConnectionImpl pci = (PooledConnectionImpl)used.pop(); |  | ||||||
| 				pci.removeConnectionEventListener(connectionEventListener); |  | ||||||
| 				try |  | ||||||
| 				{ |  | ||||||
| 					pci.close(); |  | ||||||
| 				} |  | ||||||
| 				catch (SQLException e) |  | ||||||
| 				{} |  | ||||||
| 			} |  | ||||||
| 			used = null; |  | ||||||
| 		} |  | ||||||
|         removeStoredDataSource(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     protected void removeStoredDataSource() { |  | ||||||
|         synchronized (dataSources) |  | ||||||
|         { |  | ||||||
|             dataSources.remove(dataSourceName); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
| 	 * Gets a connection from the pool.  Will get an available one if |  | ||||||
| 	 * present, or create a new one if under the max limit.  Will |  | ||||||
| 	 * block if all used and a new one would exceed the max. |  | ||||||
| 	 */ |  | ||||||
| 	private Connection getPooledConnection() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		PooledConnection pc = null; |  | ||||||
| 		synchronized (lock) |  | ||||||
| 		{ |  | ||||||
| 			if (available == null) |  | ||||||
| 			{ |  | ||||||
| 				throw new SQLException("DataSource has been closed."); |  | ||||||
| 			} |  | ||||||
| 			while (true) |  | ||||||
| 			{ |  | ||||||
| 				if (available.size() > 0) |  | ||||||
| 				{ |  | ||||||
| 					pc = (PooledConnection)available.pop(); |  | ||||||
| 					used.push(pc); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				if (maxConnections == 0 || used.size() < maxConnections) |  | ||||||
| 				{ |  | ||||||
| 					pc = source.getPooledConnection(); |  | ||||||
| 					used.push(pc); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					try |  | ||||||
| 					{ |  | ||||||
| 						// Wake up every second at a minimum |  | ||||||
| 						lock.wait(1000L); |  | ||||||
| 					} |  | ||||||
| 					catch (InterruptedException e) |  | ||||||
| 					{} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		pc.addConnectionEventListener(connectionEventListener); |  | ||||||
| 		return pc.getConnection(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Notified when a pooled connection is closed, or a fatal error occurs |  | ||||||
| 	 * on a pooled connection.	This is the only way connections are marked |  | ||||||
| 	 * as unused. |  | ||||||
| 	 */ |  | ||||||
| 	private ConnectionEventListener connectionEventListener = new ConnectionEventListener() |  | ||||||
| 			{ |  | ||||||
| 				public void connectionClosed(ConnectionEvent event) |  | ||||||
| 				{ |  | ||||||
| 					((PooledConnection)event.getSource()).removeConnectionEventListener(this); |  | ||||||
| 					synchronized (lock) |  | ||||||
| 					{ |  | ||||||
| 						if (available == null) |  | ||||||
| 						{ |  | ||||||
| 							return ; // DataSource has been closed |  | ||||||
| 						} |  | ||||||
| 						boolean removed = used.remove(event.getSource()); |  | ||||||
| 						if (removed) |  | ||||||
| 						{ |  | ||||||
| 							available.push(event.getSource()); |  | ||||||
| 							// There's now a new connection available |  | ||||||
| 							lock.notify(); |  | ||||||
| 						} |  | ||||||
| 						else |  | ||||||
| 						{ |  | ||||||
| 							// a connection error occured |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				/** |  | ||||||
| 				 * This is only called for fatal errors, where the physical connection is |  | ||||||
| 				 * useless afterward and should be removed from the pool. |  | ||||||
| 				 */ |  | ||||||
| 				public void connectionErrorOccurred(ConnectionEvent event) |  | ||||||
| 				{ |  | ||||||
| 					((PooledConnection) event.getSource()).removeConnectionEventListener(this); |  | ||||||
| 					synchronized (lock) |  | ||||||
| 					{ |  | ||||||
| 						if (available == null) |  | ||||||
| 						{ |  | ||||||
| 							return ; // DataSource has been closed |  | ||||||
| 						} |  | ||||||
| 						used.remove(event.getSource()); |  | ||||||
| 						// We're now at least 1 connection under the max |  | ||||||
| 						lock.notify(); |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}; |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Adds custom properties for this DataSource to the properties defined in |  | ||||||
| 	 * the superclass. |  | ||||||
| 	 */ |  | ||||||
| 	public Reference getReference() throws NamingException |  | ||||||
| 	{ |  | ||||||
| 		Reference ref = super.getReference(); |  | ||||||
| 		ref.add(new StringRefAddr("dataSourceName", dataSourceName)); |  | ||||||
| 		if (initialConnections > 0) |  | ||||||
| 		{ |  | ||||||
| 			ref.add(new StringRefAddr("initialConnections", Integer.toString(initialConnections))); |  | ||||||
| 		} |  | ||||||
| 		if (maxConnections > 0) |  | ||||||
| 		{ |  | ||||||
| 			ref.add(new StringRefAddr("maxConnections", Integer.toString(maxConnections))); |  | ||||||
| 		} |  | ||||||
| 		return ref; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| package org.postgresql.jdbc2.optional; |  | ||||||
| 
 |  | ||||||
| import javax.sql.DataSource; |  | ||||||
| import java.io.Serializable; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Simple DataSource which does not perform connection pooling.  In order to use |  | ||||||
|  * the DataSource, you must set the property databaseName.	The settings for |  | ||||||
|  * serverName, portNumber, user, and password are optional.  Note: these properties |  | ||||||
|  * are declared in the superclass. |  | ||||||
|  * |  | ||||||
|  * @author Aaron Mulder (ammulder@chariotsolutions.com) |  | ||||||
|  * @version $Revision: 1.2 $ |  | ||||||
|  */ |  | ||||||
| public class SimpleDataSource extends BaseDataSource implements Serializable, DataSource |  | ||||||
| { |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a description of this DataSource. |  | ||||||
| 	 */ |  | ||||||
| 	public String getDescription() |  | ||||||
| 	{ |  | ||||||
| 		return "Non-Pooling DataSource from " + org.postgresql.Driver.getVersion(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -1,194 +0,0 @@ | |||||||
| /*------------------------------------------------------------------------- |  | ||||||
|  * |  | ||||||
|  * BlobInputStream.java |  | ||||||
|  *     This is an implementation of an InputStream from a large object. |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2003, PostgreSQL Global Development Group |  | ||||||
|  * |  | ||||||
|  * IDENTIFICATION |  | ||||||
|  *	  $PostgreSQL: pgsql/src/interfaces/jdbc/org/postgresql/largeobject/BlobInputStream.java,v 1.6 2003/11/29 19:52:11 pgsql Exp $ |  | ||||||
|  * |  | ||||||
|  *------------------------------------------------------------------------- |  | ||||||
|  */ |  | ||||||
| package org.postgresql.largeobject; |  | ||||||
| 
 |  | ||||||
| import java.io.InputStream; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.sql.SQLException; |  | ||||||
| 
 |  | ||||||
| public class BlobInputStream extends InputStream |  | ||||||
| { |  | ||||||
| 	/* |  | ||||||
| 	 * The parent LargeObject |  | ||||||
| 	 */ |  | ||||||
| 	private LargeObject lo; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Buffer used to improve performance |  | ||||||
| 	 */ |  | ||||||
| 	private byte[] buffer; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Position within buffer |  | ||||||
| 	 */ |  | ||||||
| 	private int bpos; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * The buffer size |  | ||||||
| 	 */ |  | ||||||
| 	private int bsize; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * The mark position |  | ||||||
| 	 */ |  | ||||||
| 	private int mpos = 0; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * @param lo LargeObject to read from |  | ||||||
| 	 */ |  | ||||||
| 	public BlobInputStream(LargeObject lo) |  | ||||||
| 	{ |  | ||||||
| 		this(lo, 1024); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * @param lo LargeObject to read from |  | ||||||
| 	 * @param bsize buffer size |  | ||||||
| 	 */ |  | ||||||
| 	public BlobInputStream(LargeObject lo, int bsize) |  | ||||||
| 	{ |  | ||||||
| 		this.lo = lo; |  | ||||||
| 		buffer = null; |  | ||||||
| 		bpos = 0; |  | ||||||
| 		this.bsize = bsize; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * The minimum required to implement input stream |  | ||||||
| 	 */ |  | ||||||
| 	public int read() throws java.io.IOException |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			if (buffer == null || bpos >= buffer.length) |  | ||||||
| 			{ |  | ||||||
| 				buffer = lo.read(bsize); |  | ||||||
| 				bpos = 0; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// Handle EOF |  | ||||||
| 			if (bpos >= buffer.length) |  | ||||||
| 			{ |  | ||||||
| 				return -1; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			int ret = (buffer[bpos] & 0x7F); |  | ||||||
| 			if ((buffer[bpos] &0x80) == 0x80) |  | ||||||
| 			{ |  | ||||||
| 				ret |= 0x80; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			bpos++; |  | ||||||
| 
 |  | ||||||
| 			return ret; |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException se) |  | ||||||
| 		{ |  | ||||||
| 			throw new IOException(se.toString()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Closes this input stream and releases any system resources associated |  | ||||||
| 	 * with the stream. |  | ||||||
| 	 * |  | ||||||
| 	 * <p> The <code>close</code> method of <code>InputStream</code> does |  | ||||||
| 	 * nothing. |  | ||||||
| 	 * |  | ||||||
| 	 * @exception  IOException	if an I/O error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public void close() throws IOException |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			lo.close(); |  | ||||||
| 			lo = null; |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException se) |  | ||||||
| 		{ |  | ||||||
| 			throw new IOException(se.toString()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Marks the current position in this input stream. A subsequent call to |  | ||||||
| 	 * the <code>reset</code> method repositions this stream at the last marked |  | ||||||
| 	 * position so that subsequent reads re-read the same bytes. |  | ||||||
| 	 * |  | ||||||
| 	 * <p> The <code>readlimit</code> arguments tells this input stream to |  | ||||||
| 	 * allow that many bytes to be read before the mark position gets |  | ||||||
| 	 * invalidated. |  | ||||||
| 	 * |  | ||||||
| 	 * <p> The general contract of <code>mark</code> is that, if the method |  | ||||||
| 	 * <code>markSupported</code> returns <code>true</code>, the stream somehow |  | ||||||
| 	 * remembers all the bytes read after the call to <code>mark</code> and |  | ||||||
| 	 * stands ready to supply those same bytes again if and whenever the method |  | ||||||
| 	 * <code>reset</code> is called.  However, the stream is not required to |  | ||||||
| 	 * remember any data at all if more than <code>readlimit</code> bytes are |  | ||||||
| 	 * read from the stream before <code>reset</code> is called. |  | ||||||
| 	 * |  | ||||||
| 	 * <p> The <code>mark</code> method of <code>InputStream</code> does |  | ||||||
| 	 * nothing. |  | ||||||
| 	 * |  | ||||||
| 	 * @param	readlimit	the maximum limit of bytes that can be read before |  | ||||||
| 	 *						the mark position becomes invalid. |  | ||||||
| 	 * @see		java.io.InputStream#reset() |  | ||||||
| 	 */ |  | ||||||
| 	public synchronized void mark(int readlimit) |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			mpos = lo.tell(); |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException se) |  | ||||||
| 		{ |  | ||||||
| 			//throw new IOException(se.toString()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Repositions this stream to the position at the time the |  | ||||||
| 	 * <code>mark</code> method was last called on this input stream. |  | ||||||
| 	 * NB: If mark is not called we move to the begining. |  | ||||||
| 	 * @see		java.io.InputStream#mark(int) |  | ||||||
| 	 * @see		java.io.IOException |  | ||||||
| 	 */ |  | ||||||
| 	public synchronized void reset() |  | ||||||
| 	throws IOException |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			lo.seek(mpos); |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException se) |  | ||||||
| 		{ |  | ||||||
| 			throw new IOException(se.toString()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Tests if this input stream supports the <code>mark</code> and |  | ||||||
| 	 * <code>reset</code> methods. The <code>markSupported</code> method of |  | ||||||
| 	 * <code>InputStream</code> returns <code>false</code>. |  | ||||||
| 	 * |  | ||||||
| 	 * @return	<code>true</code> if this true type supports the mark and reset |  | ||||||
| 	 *			method; <code>false</code> otherwise. |  | ||||||
| 	 * @see		java.io.InputStream#mark(int) |  | ||||||
| 	 * @see		java.io.InputStream#reset() |  | ||||||
| 	 */ |  | ||||||
| 	public boolean markSupported() |  | ||||||
| 	{ |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -1,148 +0,0 @@ | |||||||
| /*------------------------------------------------------------------------- |  | ||||||
|  * |  | ||||||
|  * BlobOutputStream.java |  | ||||||
|  *     This implements a basic output stream that writes to a LargeObject |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2003, PostgreSQL Global Development Group |  | ||||||
|  * |  | ||||||
|  * IDENTIFICATION |  | ||||||
|  *	  $PostgreSQL: pgsql/src/interfaces/jdbc/org/postgresql/largeobject/BlobOutputStream.java,v 1.7 2003/11/29 19:52:11 pgsql Exp $ |  | ||||||
|  * |  | ||||||
|  *------------------------------------------------------------------------- |  | ||||||
|  */ |  | ||||||
| package org.postgresql.largeobject; |  | ||||||
| 
 |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.io.OutputStream; |  | ||||||
| import java.sql.SQLException; |  | ||||||
| 
 |  | ||||||
| public class BlobOutputStream extends OutputStream |  | ||||||
| { |  | ||||||
| 	/* |  | ||||||
| 	 * The parent LargeObject |  | ||||||
| 	 */ |  | ||||||
| 	private LargeObject lo; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Buffer |  | ||||||
| 	 */ |  | ||||||
| 	private byte buf[]; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Size of the buffer (default 1K) |  | ||||||
| 	 */ |  | ||||||
| 	private int bsize; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Position within the buffer |  | ||||||
| 	 */ |  | ||||||
| 	private int bpos; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Create an OutputStream to a large object |  | ||||||
| 	 * @param lo LargeObject |  | ||||||
| 	 */ |  | ||||||
| 	public BlobOutputStream(LargeObject lo) |  | ||||||
| 	{ |  | ||||||
| 		this(lo, 1024); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Create an OutputStream to a large object |  | ||||||
| 	 * @param lo LargeObject |  | ||||||
| 	 * @param bsize The size of the buffer used to improve performance |  | ||||||
| 	 */ |  | ||||||
| 	public BlobOutputStream(LargeObject lo, int bsize) |  | ||||||
| 	{ |  | ||||||
| 		this.lo = lo; |  | ||||||
| 		this.bsize = bsize; |  | ||||||
| 		buf = new byte[bsize]; |  | ||||||
| 		bpos = 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public void write(int b) throws java.io.IOException |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			if (bpos >= bsize) |  | ||||||
| 			{ |  | ||||||
| 				lo.write(buf); |  | ||||||
| 				bpos = 0; |  | ||||||
| 			} |  | ||||||
| 			buf[bpos++] = (byte)b; |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException se) |  | ||||||
| 		{ |  | ||||||
| 			throw new IOException(se.toString()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public void write(byte[] buf, int off, int len) throws java.io.IOException |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 			{ |  | ||||||
| 				// If we have any internally buffered data, send it first |  | ||||||
| 				if ( bpos > 0 ) |  | ||||||
| 					flush(); |  | ||||||
| 
 |  | ||||||
| 				if ( off == 0 && len == buf.length ) |  | ||||||
| 					lo.write(buf); // save a buffer creation and copy since full buffer written |  | ||||||
| 				else |  | ||||||
| 					lo.write(buf,off,len); |  | ||||||
| 			} |  | ||||||
| 		catch (SQLException se) |  | ||||||
| 			{ |  | ||||||
| 				throw new IOException(se.toString()); |  | ||||||
| 			} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Flushes this output stream and forces any buffered output bytes |  | ||||||
| 	 * to be written out. The general contract of <code>flush</code> is |  | ||||||
| 	 * that calling it is an indication that, if any bytes previously |  | ||||||
| 	 * written have been buffered by the implementation of the output |  | ||||||
| 	 * stream, such bytes should immediately be written to their |  | ||||||
| 	 * intended destination. |  | ||||||
| 	 * |  | ||||||
| 	 * @exception  IOException	if an I/O error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public void flush() throws IOException |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			if (bpos > 0) |  | ||||||
| 				lo.write(buf, 0, bpos); |  | ||||||
| 			bpos = 0; |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException se) |  | ||||||
| 		{ |  | ||||||
| 			throw new IOException(se.toString()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Closes this output stream and releases any system resources |  | ||||||
| 	 * associated with this stream. The general contract of <code>close</code> |  | ||||||
| 	 * is that it closes the output stream. A closed stream cannot perform |  | ||||||
| 	 * output operations and cannot be reopened. |  | ||||||
| 	 * <p> |  | ||||||
| 	 * The <code>close</code> method of <code>OutputStream</code> does nothing. |  | ||||||
| 	 * |  | ||||||
| 	 * @exception  IOException	if an I/O error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public void close() throws IOException |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			flush(); |  | ||||||
| 			lo.close(); |  | ||||||
| 			lo = null; |  | ||||||
| 		} |  | ||||||
| 		catch (SQLException se) |  | ||||||
| 		{ |  | ||||||
| 			throw new IOException(se.toString()); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,328 +0,0 @@ | |||||||
| /*------------------------------------------------------------------------- |  | ||||||
|  * |  | ||||||
|  * LargeObject.java |  | ||||||
|  *     This class implements the large object interface to org.postgresql. |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2003, PostgreSQL Global Development Group |  | ||||||
|  * |  | ||||||
|  * IDENTIFICATION |  | ||||||
|  *	  $PostgreSQL: pgsql/src/interfaces/jdbc/org/postgresql/largeobject/LargeObject.java,v 1.11 2003/11/29 19:52:11 pgsql Exp $ |  | ||||||
|  * |  | ||||||
|  *------------------------------------------------------------------------- |  | ||||||
|  */ |  | ||||||
| package org.postgresql.largeobject; |  | ||||||
| 
 |  | ||||||
| import java.io.InputStream; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.io.OutputStream; |  | ||||||
| import java.sql.SQLException; |  | ||||||
| import org.postgresql.fastpath.Fastpath; |  | ||||||
| import org.postgresql.fastpath.FastpathArg; |  | ||||||
| 
 |  | ||||||
| /* |  | ||||||
|  * This class provides the basic methods required to run the interface, plus |  | ||||||
|  * a pair of methods that provide InputStream and OutputStream classes |  | ||||||
|  * for this object. |  | ||||||
|  * |  | ||||||
|  * <p>Normally, client code would use the getAsciiStream, getBinaryStream, |  | ||||||
|  * or getUnicodeStream methods in ResultSet, or setAsciiStream, |  | ||||||
|  * setBinaryStream, or setUnicodeStream methods in PreparedStatement to |  | ||||||
|  * access Large Objects. |  | ||||||
|  * |  | ||||||
|  * <p>However, sometimes lower level access to Large Objects are required, |  | ||||||
|  * that are not supported by the JDBC specification. |  | ||||||
|  * |  | ||||||
|  * <p>Refer to org.postgresql.largeobject.LargeObjectManager on how to gain access |  | ||||||
|  * to a Large Object, or how to create one. |  | ||||||
|  * |  | ||||||
|  * @see org.postgresql.largeobject.LargeObjectManager |  | ||||||
|  * @see java.sql.ResultSet#getAsciiStream |  | ||||||
|  * @see java.sql.ResultSet#getBinaryStream |  | ||||||
|  * @see java.sql.ResultSet#getUnicodeStream |  | ||||||
|  * @see java.sql.PreparedStatement#setAsciiStream |  | ||||||
|  * @see java.sql.PreparedStatement#setBinaryStream |  | ||||||
|  * @see java.sql.PreparedStatement#setUnicodeStream |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| public class LargeObject |  | ||||||
| { |  | ||||||
| 	/* |  | ||||||
| 	 * Indicates a seek from the begining of a file |  | ||||||
| 	 */ |  | ||||||
| 	public static final int SEEK_SET = 0; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Indicates a seek from the current position |  | ||||||
| 	 */ |  | ||||||
| 	public static final int SEEK_CUR = 1; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Indicates a seek from the end of a file |  | ||||||
| 	 */ |  | ||||||
| 	public static final int SEEK_END = 2; |  | ||||||
| 
 |  | ||||||
| 	private Fastpath	fp; // Fastpath API to use |  | ||||||
| 	private int oid;	// OID of this object |  | ||||||
| 	private int fd; // the descriptor of the open large object |  | ||||||
| 
 |  | ||||||
| 	private BlobOutputStream os;  // The current output stream |  | ||||||
| 
 |  | ||||||
| 	private boolean closed = false; // true when we are closed |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This opens a large object. |  | ||||||
| 	 * |  | ||||||
| 	 * <p>If the object does not exist, then an SQLException is thrown. |  | ||||||
| 	 * |  | ||||||
| 	 * @param fp FastPath API for the connection to use |  | ||||||
| 	 * @param oid of the Large Object to open |  | ||||||
| 	 * @param mode Mode of opening the large object |  | ||||||
| 	 * (defined in LargeObjectManager) |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 * @see org.postgresql.largeobject.LargeObjectManager |  | ||||||
| 	 */ |  | ||||||
| 	protected LargeObject(Fastpath fp, int oid, int mode) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		this.fp = fp; |  | ||||||
| 		this.oid = oid; |  | ||||||
| 
 |  | ||||||
| 		FastpathArg args[] = new FastpathArg[2]; |  | ||||||
| 		args[0] = new FastpathArg(oid); |  | ||||||
| 		args[1] = new FastpathArg(mode); |  | ||||||
| 		this.fd = fp.getInteger("lo_open", args); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Release large object resources during garbage cleanup */ |  | ||||||
| 	protected void finalize() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		//This code used to call close() however that was problematic |  | ||||||
| 		//because the scope of the fd is a transaction, thus if commit |  | ||||||
| 		//or rollback was called before garbage collection ran then |  | ||||||
| 		//the call to close would error out with an invalid large object |  | ||||||
| 		//handle.  So this method now does nothing and lets the server |  | ||||||
| 		//handle cleanup when it ends the transaction. |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * @return the OID of this LargeObject |  | ||||||
| 	 */ |  | ||||||
| 	public int getOID() |  | ||||||
| 	{ |  | ||||||
| 		return oid; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This method closes the object. You must not call methods in this |  | ||||||
| 	 * object after this is called. |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public void close() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		if (!closed) |  | ||||||
| 		{ |  | ||||||
| 			// flush any open output streams |  | ||||||
| 			if (os != null) |  | ||||||
| 			{ |  | ||||||
| 				try |  | ||||||
| 				{ |  | ||||||
| 					// we can't call os.close() otherwise we go into an infinite loop! |  | ||||||
| 					os.flush(); |  | ||||||
| 				} |  | ||||||
| 				catch (IOException ioe) |  | ||||||
| 				{ |  | ||||||
| 					throw new SQLException(ioe.getMessage()); |  | ||||||
| 				} |  | ||||||
| 				finally |  | ||||||
| 				{ |  | ||||||
| 					os = null; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// finally close |  | ||||||
| 			FastpathArg args[] = new FastpathArg[1]; |  | ||||||
| 			args[0] = new FastpathArg(fd); |  | ||||||
| 			fp.fastpath("lo_close", false, args); // true here as we dont care!! |  | ||||||
| 			closed = true; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Reads some data from the object, and return as a byte[] array |  | ||||||
| 	 * |  | ||||||
| 	 * @param len number of bytes to read |  | ||||||
| 	 * @return byte[] array containing data read |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public byte[] read(int len) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		// This is the original method, where the entire block (len bytes) |  | ||||||
| 		// is retrieved in one go. |  | ||||||
| 		FastpathArg args[] = new FastpathArg[2]; |  | ||||||
| 		args[0] = new FastpathArg(fd); |  | ||||||
| 		args[1] = new FastpathArg(len); |  | ||||||
| 		return fp.getData("loread", args); |  | ||||||
| 
 |  | ||||||
| 		// This version allows us to break this down into 4k blocks |  | ||||||
| 		//if (len<=4048) { |  | ||||||
| 		//// handle as before, return the whole block in one go |  | ||||||
| 		//FastpathArg args[] = new FastpathArg[2]; |  | ||||||
| 		//args[0] = new FastpathArg(fd); |  | ||||||
| 		//args[1] = new FastpathArg(len); |  | ||||||
| 		//return fp.getData("loread",args); |  | ||||||
| 		//} else { |  | ||||||
| 		//// return in 4k blocks |  | ||||||
| 		//byte[] buf=new byte[len]; |  | ||||||
| 		//int off=0; |  | ||||||
| 		//while (len>0) { |  | ||||||
| 		//int bs=4048; |  | ||||||
| 		//len-=bs; |  | ||||||
| 		//if (len<0) { |  | ||||||
| 		//bs+=len; |  | ||||||
| 		//len=0; |  | ||||||
| 		//} |  | ||||||
| 		//read(buf,off,bs); |  | ||||||
| 		//off+=bs; |  | ||||||
| 		//} |  | ||||||
| 		//return buf; |  | ||||||
| 		//} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Reads some data from the object into an existing array |  | ||||||
| 	 * |  | ||||||
| 	 * @param buf destination array |  | ||||||
| 	 * @param off offset within array |  | ||||||
| 	 * @param len number of bytes to read |  | ||||||
| 	 * @return the number of bytes actually read |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public int read(byte buf[], int off, int len) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		byte b[] = read(len); |  | ||||||
| 		if (b.length < len) |  | ||||||
| 			len = b.length; |  | ||||||
| 		System.arraycopy(b, 0, buf, off, len); |  | ||||||
| 		return len; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Writes an array to the object |  | ||||||
| 	 * |  | ||||||
| 	 * @param buf array to write |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public void write(byte buf[]) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		FastpathArg args[] = new FastpathArg[2]; |  | ||||||
| 		args[0] = new FastpathArg(fd); |  | ||||||
| 		args[1] = new FastpathArg(buf); |  | ||||||
| 		fp.fastpath("lowrite", false, args); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Writes some data from an array to the object |  | ||||||
| 	 * |  | ||||||
| 	 * @param buf destination array |  | ||||||
| 	 * @param off offset within array |  | ||||||
| 	 * @param len number of bytes to write |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public void write(byte buf[], int off, int len) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		byte data[] = new byte[len]; |  | ||||||
| 		System.arraycopy(buf, off, data, 0, len); |  | ||||||
| 		write(data); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Sets the current position within the object. |  | ||||||
| 	 * |  | ||||||
| 	 * <p>This is similar to the fseek() call in the standard C library. It |  | ||||||
| 	 * allows you to have random access to the large object. |  | ||||||
| 	 * |  | ||||||
| 	 * @param pos position within object |  | ||||||
| 	 * @param ref Either SEEK_SET, SEEK_CUR or SEEK_END |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public void seek(int pos, int ref) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		FastpathArg args[] = new FastpathArg[3]; |  | ||||||
| 		args[0] = new FastpathArg(fd); |  | ||||||
| 		args[1] = new FastpathArg(pos); |  | ||||||
| 		args[2] = new FastpathArg(ref); |  | ||||||
| 		fp.fastpath("lo_lseek", false, args); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Sets the current position within the object. |  | ||||||
| 	 * |  | ||||||
| 	 * <p>This is similar to the fseek() call in the standard C library. It |  | ||||||
| 	 * allows you to have random access to the large object. |  | ||||||
| 	 * |  | ||||||
| 	 * @param pos position within object from begining |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public void seek(int pos) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		seek(pos, SEEK_SET); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * @return the current position within the object |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public int tell() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		FastpathArg args[] = new FastpathArg[1]; |  | ||||||
| 		args[0] = new FastpathArg(fd); |  | ||||||
| 		return fp.getInteger("lo_tell", args); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This method is inefficient, as the only way to find out the size of |  | ||||||
| 	 * the object is to seek to the end, record the current position, then |  | ||||||
| 	 * return to the original position. |  | ||||||
| 	 * |  | ||||||
| 	 * <p>A better method will be found in the future. |  | ||||||
| 	 * |  | ||||||
| 	 * @return the size of the large object |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public int size() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		int cp = tell(); |  | ||||||
| 		seek(0, SEEK_END); |  | ||||||
| 		int sz = tell(); |  | ||||||
| 		seek(cp, SEEK_SET); |  | ||||||
| 		return sz; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Returns an InputStream from this object. |  | ||||||
| 	 * |  | ||||||
| 	 * <p>This InputStream can then be used in any method that requires an |  | ||||||
| 	 * InputStream. |  | ||||||
| 	 * |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public InputStream getInputStream() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		return new BlobInputStream(this, 4096); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Returns an OutputStream to this object |  | ||||||
| 	 * |  | ||||||
| 	 * <p>This OutputStream can then be used in any method that requires an |  | ||||||
| 	 * OutputStream. |  | ||||||
| 	 * |  | ||||||
| 	 * @exception SQLException if a database-access error occurs. |  | ||||||
| 	 */ |  | ||||||
| 	public OutputStream getOutputStream() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		if (os == null) |  | ||||||
| 			os = new BlobOutputStream(this, 4096); |  | ||||||
| 		return os; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,229 +0,0 @@ | |||||||
| /*------------------------------------------------------------------------- |  | ||||||
|  * |  | ||||||
|  * LargeObjectManager.java |  | ||||||
|  *      This class implements the large object interface to org.postgresql. |  | ||||||
|  * |  | ||||||
|  *      It provides methods that allow client code to create, open and delete |  | ||||||
|  *      large objects from the database. When opening an object, an instance of |  | ||||||
|  *      org.postgresql.largeobject.LargeObject is returned, and its methods |  | ||||||
|  *      then allow access to the object. |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2003, PostgreSQL Global Development Group |  | ||||||
|  * |  | ||||||
|  * IDENTIFICATION |  | ||||||
|  *	  $PostgreSQL: pgsql/src/interfaces/jdbc/org/postgresql/largeobject/LargeObjectManager.java,v 1.12 2003/12/17 15:38:42 davec Exp $ |  | ||||||
|  * |  | ||||||
|  *------------------------------------------------------------------------- |  | ||||||
|  */ |  | ||||||
| package org.postgresql.largeobject; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| import java.sql.ResultSet; |  | ||||||
| import java.sql.SQLException; |  | ||||||
| import org.postgresql.Driver; |  | ||||||
| import org.postgresql.core.BaseConnection; |  | ||||||
| import org.postgresql.fastpath.Fastpath; |  | ||||||
| import org.postgresql.fastpath.FastpathArg; |  | ||||||
| import org.postgresql.util.PSQLException; |  | ||||||
| 
 |  | ||||||
| /* |  | ||||||
|  * This class implements the large object interface to org.postgresql. |  | ||||||
|  * |  | ||||||
|  * <p>It provides methods that allow client code to create, open and delete |  | ||||||
|  * large objects from the database. When opening an object, an instance of |  | ||||||
|  * org.postgresql.largeobject.LargeObject is returned, and its methods then allow |  | ||||||
|  * access to the object. |  | ||||||
|  * |  | ||||||
|  * <p>This class can only be created by org.postgresql.Connection |  | ||||||
|  * |  | ||||||
|  * <p>To get access to this class, use the following segment of code: |  | ||||||
|  * <br><pre> |  | ||||||
|  * import org.postgresql.largeobject.*; |  | ||||||
|  * |  | ||||||
|  * Connection  conn; |  | ||||||
|  * LargeObjectManager lobj; |  | ||||||
|  * |  | ||||||
|  * ... code that opens a connection ... |  | ||||||
|  * |  | ||||||
|  * lobj = ((org.postgresql.PGConnection)myconn).getLargeObjectAPI(); |  | ||||||
|  * </pre> |  | ||||||
|  * |  | ||||||
|  * <p>Normally, client code would use the getAsciiStream, getBinaryStream, |  | ||||||
|  * or getUnicodeStream methods in ResultSet, or setAsciiStream, |  | ||||||
|  * setBinaryStream, or setUnicodeStream methods in PreparedStatement to |  | ||||||
|  * access Large Objects. |  | ||||||
|  * |  | ||||||
|  * <p>However, sometimes lower level access to Large Objects are required, |  | ||||||
|  * that are not supported by the JDBC specification. |  | ||||||
|  * |  | ||||||
|  * <p>Refer to org.postgresql.largeobject.LargeObject on how to manipulate the |  | ||||||
|  * contents of a Large Object. |  | ||||||
|  * |  | ||||||
|  * @see java.sql.ResultSet#getAsciiStream |  | ||||||
|  * @see java.sql.ResultSet#getBinaryStream |  | ||||||
|  * @see java.sql.ResultSet#getUnicodeStream |  | ||||||
|  * @see java.sql.PreparedStatement#setAsciiStream |  | ||||||
|  * @see java.sql.PreparedStatement#setBinaryStream |  | ||||||
|  * @see java.sql.PreparedStatement#setUnicodeStream |  | ||||||
|  */ |  | ||||||
| public class LargeObjectManager |  | ||||||
| { |  | ||||||
| 	// the fastpath api for this connection |  | ||||||
| 	private Fastpath fp; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This mode indicates we want to write to an object |  | ||||||
| 	 */ |  | ||||||
| 	public static final int WRITE = 0x00020000; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This mode indicates we want to read an object |  | ||||||
| 	 */ |  | ||||||
| 	public static final int READ = 0x00040000; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This mode is the default. It indicates we want read and write access to |  | ||||||
| 	 * a large object |  | ||||||
| 	 */ |  | ||||||
| 	public static final int READWRITE = READ | WRITE; |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This prevents us being created by mere mortals |  | ||||||
| 	 */ |  | ||||||
| 	private LargeObjectManager() |  | ||||||
| 	{} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * Constructs the LargeObject API. |  | ||||||
| 	 * |  | ||||||
| 	 * <p><b>Important Notice</b> |  | ||||||
| 	 * <br>This method should only be called by org.postgresql.Connection |  | ||||||
| 	 * |  | ||||||
| 	 * <p>There should only be one LargeObjectManager per Connection. The |  | ||||||
| 	 * org.postgresql.Connection class keeps track of the various extension API's |  | ||||||
| 	 * and it's advised you use those to gain access, and not going direct. |  | ||||||
| 	 */ |  | ||||||
| 	public LargeObjectManager(BaseConnection conn) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		// We need Fastpath to do anything |  | ||||||
| 		this.fp = conn.getFastpathAPI(); |  | ||||||
| 
 |  | ||||||
| 		// Now get the function oid's for the api |  | ||||||
| 		// |  | ||||||
| 		// This is an example of Fastpath.addFunctions(); |  | ||||||
| 		// |  | ||||||
| 		String sql; |  | ||||||
| 		if (conn.getMetaData().supportsSchemasInTableDefinitions()) { |  | ||||||
| 			sql = "SELECT p.proname,p.oid "+ |  | ||||||
| 				" FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "+ |  | ||||||
| 				" WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND ("; |  | ||||||
| 		} else { |  | ||||||
| 			sql = "SELECT proname,oid FROM pg_proc WHERE "; |  | ||||||
| 		} |  | ||||||
| 		sql += " proname = 'lo_open'" + |  | ||||||
| 			" or proname = 'lo_close'" + |  | ||||||
| 			" or proname = 'lo_creat'" + |  | ||||||
| 			" or proname = 'lo_unlink'" + |  | ||||||
| 			" or proname = 'lo_lseek'" + |  | ||||||
| 			" or proname = 'lo_tell'" + |  | ||||||
| 			" or proname = 'loread'" + |  | ||||||
| 			" or proname = 'lowrite'"; |  | ||||||
| 
 |  | ||||||
| 		if (conn.getMetaData().supportsSchemasInTableDefinitions()) { |  | ||||||
| 			sql += ")"; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		ResultSet res = conn.createStatement().executeQuery(sql); |  | ||||||
| 
 |  | ||||||
| 		if (res == null) |  | ||||||
| 			throw new PSQLException("postgresql.lo.init"); |  | ||||||
| 
 |  | ||||||
| 		fp.addFunctions(res); |  | ||||||
| 		res.close(); |  | ||||||
| 		if (Driver.logDebug) |  | ||||||
| 			Driver.debug("Large Object initialised"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This opens an existing large object, based on its OID. This method |  | ||||||
| 	 * assumes that READ and WRITE access is required (the default). |  | ||||||
| 	 * |  | ||||||
| 	 * @param oid of large object |  | ||||||
| 	 * @return LargeObject instance providing access to the object |  | ||||||
| 	 * @exception SQLException on error |  | ||||||
| 	 */ |  | ||||||
| 	public LargeObject open(int oid) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		return new LargeObject(fp, oid, READWRITE); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This opens an existing large object, based on its OID |  | ||||||
| 	 * |  | ||||||
| 	 * @param oid of large object |  | ||||||
| 	 * @param mode mode of open |  | ||||||
| 	 * @return LargeObject instance providing access to the object |  | ||||||
| 	 * @exception SQLException on error |  | ||||||
| 	 */ |  | ||||||
| 	public LargeObject open(int oid, int mode) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		return new LargeObject(fp, oid, mode); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This creates a large object, returning its OID. |  | ||||||
| 	 * |  | ||||||
| 	 * <p>It defaults to READWRITE for the new object's attributes. |  | ||||||
| 	 * |  | ||||||
| 	 * @return oid of new object |  | ||||||
| 	 * @exception SQLException on error |  | ||||||
| 	 */ |  | ||||||
| 	public int create() throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		FastpathArg args[] = new FastpathArg[1]; |  | ||||||
| 		args[0] = new FastpathArg(READWRITE); |  | ||||||
| 		return fp.getInteger("lo_creat", args); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This creates a large object, returning its OID |  | ||||||
| 	 * |  | ||||||
| 	 * @param mode a bitmask describing different attributes of the new object |  | ||||||
| 	 * @return oid of new object |  | ||||||
| 	 * @exception SQLException on error |  | ||||||
| 	 */ |  | ||||||
| 	public int create(int mode) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		FastpathArg args[] = new FastpathArg[1]; |  | ||||||
| 		args[0] = new FastpathArg(mode); |  | ||||||
| 		return fp.getInteger("lo_creat", args); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This deletes a large object. |  | ||||||
| 	 * |  | ||||||
| 	 * @param oid describing object to delete |  | ||||||
| 	 * @exception SQLException on error |  | ||||||
| 	 */ |  | ||||||
| 	public void delete(int oid) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		FastpathArg args[] = new FastpathArg[1]; |  | ||||||
| 		args[0] = new FastpathArg(oid); |  | ||||||
| 		fp.fastpath("lo_unlink", false, args); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* |  | ||||||
| 	 * This deletes a large object. |  | ||||||
| 	 * |  | ||||||
| 	 * <p>It is identical to the delete method, and is supplied as the C API uses |  | ||||||
| 	 * unlink. |  | ||||||
| 	 * |  | ||||||
| 	 * @param oid describing object to delete |  | ||||||
| 	 * @exception SQLException on error |  | ||||||
| 	 */ |  | ||||||
| 	public void unlink(int oid) throws SQLException |  | ||||||
| 	{ |  | ||||||
| 		delete(oid); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user