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>
- * &lt;!ELEMENT object 
(object|byte|boolean|char|double|float|int|long|short|string)*&gt;
+ * &lt;!ELEMENT object 
(object|array|collection|list|byte|boolean|char|double|float|int|long|short|string)*&gt;
  * &lt;!ATTLIST object
  *   class CDATA #REQUIRED
  *   null (true|false) "false"&gt;
@@ -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>


Reply via email to