Author: psteitz Date: Sun Feb 22 23:43:52 2009 New Revision: 746849 URL: http://svn.apache.org/viewvc?rev=746849&view=rev Log: Added a connectionInitSqls configuration parameter to BasicDataSource allowing the user to specify a collection of SQL statements to execute one time when a physical database connection is first opened. JIRA: DBCP-175 Thanks to Jiri Melichna and Jerome Lacoste.
Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSourceFactory.java commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java commons/proper/dbcp/trunk/src/java/org/apache/commons/jocl/JOCLContentHandler.java commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSourceFactory.java commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java commons/proper/dbcp/trunk/src/test/org/apache/commons/jocl/TestJOCLContentHandler.java commons/proper/dbcp/trunk/src/test/testpool.jocl commons/proper/dbcp/trunk/xdocs/changes.xml commons/proper/dbcp/trunk/xdocs/configuration.xml Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java (original) +++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSource.java Sun Feb 22 23:43:52 2009 @@ -19,6 +19,11 @@ import java.io.PrintWriter; import java.util.Properties; +import java.util.Collection; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Collections; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; @@ -801,6 +806,60 @@ } this.restartNeeded = true; } + + /** + * These SQL statements run once after a Connection is created. + * <p> + * This property can be used for example to run ALTER SESSION SET + * NLS_SORT=XCYECH in an Oracle Database only once after connection + * creation. + * </p> + * + * @since 1.3 + */ + protected List connectionInitSqls; + + /** + * Returns the list of SQL statements executed when a physical connection + * is first created. Returns an empty list if there are no initialization + * statements configured. + * + * @return initialization SQL statements + * @since 1.3 + */ + public synchronized Collection getConnectionInitSqls() { + if (connectionInitSqls == null) { + return Collections.EMPTY_LIST; + } + return connectionInitSqls; + } + + /** + * Sets the list of SQL statements to be executed when a physical + * connection is first created. + * + * @param connectionInitSqls + */ + public synchronized void setConnectionInitSqls(Collection connectionInitSqls) { + this.connectionInitSqls = null; + if ((connectionInitSqls != null) && (connectionInitSqls.size() > 0)) { + for (Iterator iterator = connectionInitSqls.iterator(); + iterator.hasNext();) { + Object o = iterator.next(); + if (o != null) { + String s = o.toString(); + if (s.trim().length() > 0) { + if (this.connectionInitSqls == null) { + this.connectionInitSqls = new ArrayList(); + } + this.connectionInitSqls.add(s); + } + } + } + } + this.restartNeeded = true; + } + /** * Controls access to the underlying connection. @@ -1235,6 +1294,7 @@ connectionPool, statementPoolFactory, validationQuery, + connectionInitSqls, defaultReadOnly, defaultAutoCommit, defaultTransactionIsolation, Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSourceFactory.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSourceFactory.java?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSourceFactory.java (original) +++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/BasicDataSourceFactory.java Sun Feb 22 23:43:52 2009 @@ -22,6 +22,8 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; +import java.util.StringTokenizer; +import java.util.Collections; import javax.naming.Context; import javax.naming.Name; @@ -63,6 +65,12 @@ private final static String PROP_URL = "url"; private final static String PROP_USERNAME = "username"; private final static String PROP_VALIDATIONQUERY = "validationQuery"; + /** + * The property name for initConnectionSqls. + * The associated value String must be of the form [query;]* + * @since 1.3 + */ + private final static String PROP_INITCONNECTIONSQLS = "initConnectionSqls"; private final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed"; private final static String PROP_REMOVEABANDONED = "removeAbandoned"; private final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout"; @@ -92,6 +100,7 @@ PROP_URL, PROP_USERNAME, PROP_VALIDATIONQUERY, + PROP_INITCONNECTIONSQLS, PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED, PROP_REMOVEABANDONED, PROP_REMOVEABANDONEDTIMEOUT, @@ -312,6 +321,12 @@ dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value)); } + value = properties.getProperty(PROP_INITCONNECTIONSQLS); + if (value != null) { + StringTokenizer tokenizer = new StringTokenizer(value, ";"); + dataSource.setConnectionInitSqls(Collections.list(tokenizer)); + } + value = properties.getProperty(PROP_CONNECTIONPROPERTIES); if (value != null) { Properties p = getProperties(value); Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java (original) +++ commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java Sun Feb 22 23:43:52 2009 @@ -21,6 +21,8 @@ import java.sql.Statement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Collection; +import java.util.Iterator; import org.apache.commons.pool.KeyedObjectPool; import org.apache.commons.pool.KeyedObjectPoolFactory; import org.apache.commons.pool.PoolableObjectFactory; @@ -62,6 +64,28 @@ * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param connectionInitSqls a Collection of SQL statements to initialize {...@link Connection}s. Using <tt>null</tt> turns off initialization. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @since 1.3 + */ + public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, Collection connectionInitSqls, boolean defaultReadOnly, boolean defaultAutoCommit) { + _connFactory = connFactory; + _pool = pool; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _connectionInitSqls = connectionInitSqls; + _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; + _defaultAutoCommit = defaultAutoCommit; + } + + /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {...@link Connection}s @@ -83,6 +107,30 @@ * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param connectionInitSqls a Collection of SQL statement to initialize {...@link Connection}s. Using <tt>null</tt> turns off initialization. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {...@link Connection}s + * @since 1.3 + */ + public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, Collection connectionInitSqls, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation) { + _connFactory = connFactory; + _pool = pool; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _connectionInitSqls = connectionInitSqls; + _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; + _defaultAutoCommit = defaultAutoCommit; + _defaultTransactionIsolation = defaultTransactionIsolation; + } + + /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s * @param config the AbandonedConfig if tracing SQL objects @@ -212,6 +260,45 @@ } /** + * Create a new <tt>PoolableConnectionFactory</tt>. + * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s + * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s + * @param stmtPoolFactory the {...@link KeyedObjectPoolFactory} to use to create {...@link KeyedObjectPool}s for pooling {...@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {...@link java.sql.PreparedStatement} pooling + * @param validationQuery a query to use to {...@link #validateObject validate} {...@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. + * @param connectionInitSqls a Collection of SQL statements to initialize {...@link Connection}s. Using <tt>null</tt> turns off initialization. + * @param defaultReadOnly the default "read only" setting for borrowed {...@link Connection}s + * @param defaultAutoCommit the default "auto commit" setting for returned {...@link Connection}s + * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {...@link Connection}s + * @param defaultCatalog the default "catalog" setting for returned {...@link Connection}s + * @param config the AbandonedConfig if tracing SQL objects + * @since 1.3 + */ + public PoolableConnectionFactory( + ConnectionFactory connFactory, + ObjectPool pool, + KeyedObjectPoolFactory stmtPoolFactory, + String validationQuery, + Collection connectionInitSqls, + Boolean defaultReadOnly, + boolean defaultAutoCommit, + int defaultTransactionIsolation, + String defaultCatalog, + AbandonedConfig config) { + + _connFactory = connFactory; + _pool = pool; + _config = config; + _pool.setFactory(this); + _stmtPoolFactory = stmtPoolFactory; + _validationQuery = validationQuery; + _connectionInitSqls = connectionInitSqls; + _defaultReadOnly = defaultReadOnly; + _defaultAutoCommit = defaultAutoCommit; + _defaultTransactionIsolation = defaultTransactionIsolation; + _defaultCatalog = defaultCatalog; + } + + /** * Sets the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s. * @param connFactory the {...@link ConnectionFactory} from which to obtain base {...@link Connection}s */ @@ -230,6 +317,16 @@ } /** + * Sets the SQL statements I use to initialize newly created {...@link Connection}s. + * Using <tt>null</tt> turns off connection initialization. + * @param connectionInitSqls SQL statement to initialize {...@link Connection}s. + * @since 1.3 + */ + synchronized public void setConnectionInitSql(Collection connectionInitSqls) { + _connectionInitSqls = connectionInitSqls; + } + + /** * Sets the {...@link ObjectPool} in which to pool {...@link Connection}s. * @param pool the {...@link ObjectPool} in which to pool those {...@link Connection}s */ @@ -296,6 +393,7 @@ public Object makeObject() throws Exception { Connection conn = _connFactory.createConnection(); + initializeConnection(conn); if (conn == null) { throw new IllegalStateException("Connection factory returned null from createConnection"); } @@ -307,6 +405,37 @@ return new PoolableConnection(conn,_pool,_config); } + private void initializeConnection(Connection conn) throws SQLException { + Collection sqls = _connectionInitSqls; + if(conn.isClosed()) { + throw new SQLException("initializeConnection: connection closed"); + } + if(null != sqls) { + Statement stmt = null; + try { + stmt = conn.createStatement(); + for (Iterator iterator = sqls.iterator(); iterator.hasNext();) + { + Object o = iterator.next(); + if (o == null) { + throw new NullPointerException("null connectionInitSqls element"); + } + // o might not be a String instance + String sql = o.toString(); + stmt.execute(sql); + } + } finally { + if (stmt != null) { + try { + stmt.close(); + } catch(Exception t) { + // ignored + } + } + } + } + } + public void destroyObject(Object obj) throws Exception { if(obj instanceof PoolableConnection) { ((PoolableConnection)obj).reallyClose(); @@ -402,6 +531,7 @@ protected ConnectionFactory _connFactory = null; protected String _validationQuery = null; + protected Collection _connectionInitSqls = null; protected ObjectPool _pool = null; protected KeyedObjectPoolFactory _stmtPoolFactory = null; protected Boolean _defaultReadOnly = null; Modified: commons/proper/dbcp/trunk/src/java/org/apache/commons/jocl/JOCLContentHandler.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/java/org/apache/commons/jocl/JOCLContentHandler.java?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/java/org/apache/commons/jocl/JOCLContentHandler.java (original) +++ commons/proper/dbcp/trunk/src/java/org/apache/commons/jocl/JOCLContentHandler.java Sun Feb 22 23:43:52 2009 @@ -31,10 +31,11 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.Collection; +import java.util.List; import java.util.ArrayList; // to do: -// + add support for arrays // + add support for strings as CDATA (makes multiline strings easier, for example) // ? some kind of support for invoking methods? @@ -166,7 +167,7 @@ * Formally, a DTD for the JOCL grammar is as follows: * <p> * <pre> - * <!ELEMENT object (object|byte|boolean|char|double|float|int|long|short|string)*> + * <!ELEMENT object (object|array|collection|list|byte|boolean|char|double|float|int|long|short|string)*> * <!ATTLIST object * class CDATA #REQUIRED * null (true|false) "false"> @@ -429,6 +430,12 @@ String isnullstr = getAttributeValue(ATT_ISNULL,attr,"false"); boolean isnull = ("true".equalsIgnoreCase(isnullstr) || "yes".equalsIgnoreCase(isnullstr)); _cur = new ConstructorDetails(cname,_cur,isnull); + } else if(ELT_ARRAY.equals(localName)) { + _cur = new ConstructorDetails(Object[].class,_cur,false,true); + } else if(ELT_COLLECTION.equals(localName)) { + _cur = new ConstructorDetails(Collection.class,_cur,false,true); + } else if(ELT_LIST.equals(localName)) { + _cur = new ConstructorDetails(List.class,_cur,false,true); } else if(ELT_BOOLEAN.equals(localName)) { String valstr = getAttributeValue(ATT_VALUE,attr,"false"); boolean val = ("true".equalsIgnoreCase(valstr) || "yes".equalsIgnoreCase(valstr)); @@ -479,7 +486,8 @@ public void endElement(String uri, String localName, String qname) throws SAXException { try { if(isJoclNamespace(uri,localName,qname)) { - if(ELT_OBJECT.equals(localName)) { + if(ELT_OBJECT.equals(localName) || ELT_ARRAY.equals(localName) + || ELT_COLLECTION.equals(localName) || ELT_LIST.equals(localName)) { ConstructorDetails temp = _cur; _cur = _cur.getParent(); if(null == _cur) { @@ -660,6 +668,21 @@ /** The name of the "object" element. */ protected static final String ELT_OBJECT = "object"; + /** The name of the "array" element. + * @since 1.2.2 + */ + protected static final String ELT_ARRAY = "array"; + + /** The name of the "collection" element. + * @since 1.2.2 + */ + protected static final String ELT_COLLECTION = "collection"; + + /** The name of the "list" element. + * @since 1.2.2 + */ + protected static final String ELT_LIST = "list"; + /** The name of the "object" element's "class" attribute. */ protected static final String ATT_CLASS = "class"; @@ -702,21 +725,33 @@ private ArrayList _argTypes = null; private ArrayList _argValues = null; private boolean _isnull = false; + private boolean _isgroup = false; public ConstructorDetails(String classname, ConstructorDetails parent) throws ClassNotFoundException { - this(Class.forName(classname),parent,false); + this(Class.forName(classname),parent,false,false); } public ConstructorDetails(String classname, ConstructorDetails parent, boolean isnull) throws ClassNotFoundException { - this(Class.forName(classname),parent,isnull); + this(Class.forName(classname),parent,isnull,false); + } + + /** + * @since 1.3 + */ + public ConstructorDetails(String classname, ConstructorDetails parent, boolean isnull, boolean isgroup) throws ClassNotFoundException { + this(Class.forName(classname),parent,isnull,isgroup); } - public ConstructorDetails(Class type, ConstructorDetails parent, boolean isnull) { + /** + * @since 1.3 + */ + public ConstructorDetails(Class type, ConstructorDetails parent, boolean isnull, boolean isgroup) { _parent = parent; _type = type; _argTypes = new ArrayList(); _argValues = new ArrayList(); _isnull = isnull; + _isgroup = isgroup; } public void addArgument(Object value) { @@ -742,6 +777,14 @@ public Object createObject() throws InstantiationException, ClassNotFoundException, IllegalAccessException, InvocationTargetException { if(_isnull) { return null; + } else if( _isgroup ) { + if (_type.equals(Object[].class)) { + return _argValues.toArray(); + } else if (_type.equals(Collection.class) || _type.equals(List.class)) { + return _argValues; + } else { + throw new IllegalStateException("implementation error: unhandled _type:" + _type); + } } else { Class k = getType(); Class[] argtypes = (Class[])_argTypes.toArray(new Class[0]); Modified: commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java (original) +++ commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSource.java Sun Feb 22 23:43:52 2009 @@ -20,6 +20,7 @@ import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; +import java.util.Arrays; import junit.framework.Test; import junit.framework.TestSuite; @@ -60,6 +61,7 @@ ds.setUsername("username"); ds.setPassword("password"); ds.setValidationQuery("SELECT DUMMY FROM DUAL"); + ds.setConnectionInitSqls(Arrays.asList(new String[] { "SELECT 1", "SELECT 2"})); } protected BasicDataSource createDataSource() throws Exception { @@ -75,7 +77,7 @@ public void testClose() throws Exception { ds.setAccessToUnderlyingConnectionAllowed(true); - // active conneciton is held open when ds is closed + // active connection is held open when ds is closed Connection activeConnection = getConnection(); Connection rawActiveConnection = ((DelegatingConnection) activeConnection).getInnermostDelegate(); assertFalse(activeConnection.isClosed()); @@ -87,7 +89,7 @@ assertFalse(idleConnection.isClosed()); assertFalse(rawIdleConnection.isClosed()); - // idle wrapper should be closed but raw conneciton should be open + // idle wrapper should be closed but raw connection should be open idleConnection.close(); assertTrue(idleConnection.isClosed()); assertFalse(rawIdleConnection.isClosed()); @@ -179,7 +181,7 @@ } public void testPooling() throws Exception { - // this also needs access to the undelying connection + // this also needs access to the underlying connection ds.setAccessToUnderlyingConnectionAllowed(true); super.testPooling(); } @@ -233,6 +235,29 @@ } } + public void testEmptyInitConnectionSql() throws Exception { + ds.setConnectionInitSqls(Arrays.asList(new String[]{"", " "})); + assertNotNull(ds.getConnectionInitSqls()); + assertEquals(0, ds.getConnectionInitSqls().size()); + + ds.setConnectionInitSqls(null); + assertNotNull(ds.getConnectionInitSqls()); + assertEquals(0, ds.getConnectionInitSqls().size()); + } + + public void testInvalidConnectionInitSql() { + try { + ds.setConnectionInitSqls(Arrays.asList(new String[]{"SELECT 1","invalid"})); + ds.getConnection(); + fail("expected SQLException"); + } + catch (SQLException e) { + if (e.toString().indexOf("invalid") < 0) { + fail("expected detailed error message"); + } + } + } + public void testSetValidationTestProperties() { // defaults assertEquals(true, ds.getTestOnBorrow()); Modified: commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSourceFactory.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSourceFactory.java?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSourceFactory.java (original) +++ commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TestBasicDataSourceFactory.java Sun Feb 22 23:43:52 2009 @@ -61,11 +61,16 @@ properties.setProperty("username", "username"); properties.setProperty("password", "password"); properties.setProperty("validationQuery", "SELECT DUMMY FROM DUAL"); + properties.setProperty("initConnectionSqls", "SELECT 1;SELECT 2"); BasicDataSource ds = (BasicDataSource) BasicDataSourceFactory.createDataSource(properties); assertEquals("jdbc:apache:commons:testdriver", ds.getUrl()); assertEquals(10, ds.getMaxActive()); assertEquals(true, ds.getDefaultAutoCommit()); + + assertEquals(2, ds.connectionInitSqls.size()); + assertEquals("SELECT 1", ds.connectionInitSqls.get(0)); + assertEquals("SELECT 2", ds.connectionInitSqls.get(1)); } } Modified: commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java (original) +++ commons/proper/dbcp/trunk/src/test/org/apache/commons/dbcp/TesterStatement.java Sun Feb 22 23:43:52 2009 @@ -146,6 +146,9 @@ public boolean execute(String sql) throws SQLException { checkOpen(); + if("invalid".equals(sql)) { + throw new SQLException("invalid query"); + } return _executeResponse; } Modified: commons/proper/dbcp/trunk/src/test/org/apache/commons/jocl/TestJOCLContentHandler.java URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/org/apache/commons/jocl/TestJOCLContentHandler.java?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/org/apache/commons/jocl/TestJOCLContentHandler.java (original) +++ commons/proper/dbcp/trunk/src/test/org/apache/commons/jocl/TestJOCLContentHandler.java Sun Feb 22 23:43:52 2009 @@ -22,6 +22,13 @@ import junit.framework.TestSuite; import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.SAXException; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.io.InputStream; +import java.io.IOException; /** * @version $Revision$ $Date$ @@ -46,7 +53,7 @@ jocl = new JOCLContentHandler(); } - public void testPrimatives() throws Exception { + public void testPrimitives() throws Exception { jocl.startDocument(); jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","jocl","jocl",new AttributesImpl()); { @@ -155,15 +162,96 @@ jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","long","long"); } jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","object","object"); + + // test array of 2 longs + { + AttributesImpl attr = new AttributesImpl(); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","array","array",attr); + } + { + AttributesImpl attr = new AttributesImpl(); + attr.addAttribute("http://apache.org/xml/xmlns/jakarta/commons/jocl","value","value","CDATA","12"); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","long","long",attr); + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","long","long"); + } + { + AttributesImpl attr = new AttributesImpl(); + attr.addAttribute("http://apache.org/xml/xmlns/jakarta/commons/jocl","value","value","CDATA","34"); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","long","long",attr); + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","long","long"); + } + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","object","object"); + + // test collection of 2 Strings, one null + { + AttributesImpl attr = new AttributesImpl(); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","collection","collection",attr); + } + { + AttributesImpl attr = new AttributesImpl(); + attr.addAttribute("http://apache.org/xml/xmlns/jakarta/commons/jocl","null","null","CDATA","true"); + attr.addAttribute("http://apache.org/xml/xmlns/jakarta/commons/jocl","class","class","CDATA","java.lang.String"); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","object","object",attr); + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","object","object"); + } + { + AttributesImpl attr = new AttributesImpl(); + attr.addAttribute("http://apache.org/xml/xmlns/jakarta/commons/jocl","value","value","CDATA","String #1"); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","string","string",attr); + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","string","string"); + } + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","object","object"); + + // test list of 1 Date, one Long + { + AttributesImpl attr = new AttributesImpl(); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","list","list",attr); + } + { + AttributesImpl attr = new AttributesImpl(); + attr.addAttribute("http://apache.org/xml/xmlns/jakarta/commons/jocl","class","class","CDATA","java.util.Date"); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","object","object",attr); + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","object","object"); + } + { + AttributesImpl attr = new AttributesImpl(); + attr.addAttribute("http://apache.org/xml/xmlns/jakarta/commons/jocl","value","value","CDATA","12"); + jocl.startElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","long","long",attr); + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","long","long"); + } + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","object","object"); + jocl.endElement("http://apache.org/xml/xmlns/jakarta/commons/jocl","jocl","jocl"); jocl.endDocument(); assertEquals(String.class,jocl.getType(0)); assertEquals(java.util.Date.class,jocl.getType(1)); assertEquals(java.util.Date.class,jocl.getType(2)); + assertTrue(jocl.getType(3).isArray()); + assertEquals(Collection.class,jocl.getType(4)); + assertEquals(List.class,jocl.getType(5)); assertTrue(null == jocl.getValue(0)); assertTrue(null != jocl.getValue(1)); assertEquals(new java.util.Date(345L),jocl.getValue(2)); + + Object[] objects = (Object[])jocl.getValue(3); + assertEquals(new Long(12L), objects[0]); + assertEquals(new Long(34L), objects[1]); + + Iterator iterator = ((Collection)jocl.getValue(4)).iterator(); + assertNull(iterator.next()); + assertEquals("String #1", iterator.next()); + + List list = (List) jocl.getValue(5); + assertEquals(java.util.Date.class,list.get(0).getClass()); + assertEquals(new Long(12L),list.get(1)); + } + + public void testParse() + throws IOException, SAXException + { + InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("testpool.jocl"); + JOCLContentHandler jocl = JOCLContentHandler.parse(stream); } } Modified: commons/proper/dbcp/trunk/src/test/testpool.jocl URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/testpool.jocl?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/src/test/testpool.jocl (original) +++ commons/proper/dbcp/trunk/src/test/testpool.jocl Sun Feb 22 23:43:52 2009 @@ -47,6 +47,10 @@ <boolean value="true"/> </object> <string value="SELECT COUNT(*) FROM DUAL"/> + <collection> + <string value="ALTER SESSION SET NLS_COMP=ANSI"/> + <string value="ALTER SESSION SET NLS_SORT=BINARY"/> + </collection> <boolean value="false"/> <boolean value="true"/> </object> Modified: commons/proper/dbcp/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/xdocs/changes.xml?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/xdocs/changes.xml (original) +++ commons/proper/dbcp/trunk/xdocs/changes.xml Sun Feb 22 23:43:52 2009 @@ -42,6 +42,11 @@ new features as well as bug fixes and instrumentation. Some bug fixes will change semantics (e.g. connection close will become idempotent). The minimum JDK level will be increased to 1.4"> + <action dev="psteitz" type="update" issue="DBCP-175" due-to="Jiri Melichna and Jerome Lacoste"> + Added a connectionInitSqls configuration parameter to BasicDataSource + allowing the user to specify a collection of SQL statements to execute + one time when a physical database connection is first opened. + </action> <action dev="markt" type="fix"> PoolableConnectionFactory.makeObject() is no longer synchronized. This provides improved response times when load spikes at the cost of a @@ -71,7 +76,7 @@ <action dev="markt" type="fix" issue="DBCP-253"> Eliminated masked _stmt field in descendents of DelegatingStatement. </action> - <action dev="markt" type="fix" issue="DBCP-191" due-to="Michael Heuer & J. David Beutel" > + <action dev="markt" type="fix" issue="DBCP-191" due-to="Michael Heuer and J. David Beutel" > Modified DBCP sources to support compilation under JDK 1.4-1.6 using Ant flags to do conditional compilation. </action> Modified: commons/proper/dbcp/trunk/xdocs/configuration.xml URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/xdocs/configuration.xml?rev=746849&r1=746848&r2=746849&view=diff ============================================================================== --- commons/proper/dbcp/trunk/xdocs/configuration.xml (original) +++ commons/proper/dbcp/trunk/xdocs/configuration.xml Sun Feb 22 23:43:52 2009 @@ -241,6 +241,15 @@ is eligable for eviction by the idle object evictor (if any). </td> </tr> + <tr> + <td>connectionInitSqls</td> + <td>null</td> + <td> + A Collection of SQL statements that will be used to initialize physical + connections when they are first created. These statements are executed + only once - when the configured connection factory creates the connection. + </td> + </tr> </table> <table>