openjpa-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Patrick Linskey <plins...@gmail.com>
Subject Re: svn commit: r652913 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ openjpa-jdbc/src/main/java/org/...
Date Sat, 03 May 2008 03:16:03 GMT
Hi,

This is failing the license header check test in the snapshot build.

-Patrick

On May 2, 2008, at 2:09 PM, mikedd@apache.org wrote:

> Author: mikedd
> Date: Fri May  2 14:09:14 2008
> New Revision: 652913
>
> URL: http://svn.apache.org/viewvc?rev=652913&view=rev
> Log:
> OPENJPA-407 committing patch provided by Fay Wang and Jeremy Bauer
>
> Added:
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/QuerySQLCacheValue.java   (with props)
>    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/ 
> openjpa/kernel/TestQuerySQLCache.java   (with props)
> Modified:
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/JDBCConfiguration.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/JDBCConfigurationImpl.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> kernel/JDBCStoreManager.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> meta/strats/RelationFieldStrategy.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> meta/strats/StoreCollectionFieldStrategy.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/LogicalUnion.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SQLBuffer.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/Select.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SelectExecutor.java
>    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SelectImpl.java
>    openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ 
> jdbc/kernel/localizer.properties
>    openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ 
> jdbc/meta/strats/localizer.properties
>    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ 
> kernel/FetchConfigurationImpl.java
>    openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml
>    openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/conf/JDBCConfiguration.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfiguration.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/JDBCConfiguration.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/JDBCConfiguration.java Fri May  2 14:09:14 2008
> @@ -18,6 +18,8 @@
>  */
> package org.apache.openjpa.jdbc.conf;
>
> +import java.util.Map;
> +
> import javax.sql.DataSource;
>
> import org.apache.openjpa.conf.OpenJPAConfiguration;
> @@ -602,4 +604,23 @@
>      * @see #getDataSource
>      */
>     public DataSource getDataSource2(StoreContext ctx);
> +
> +    /**
> +     * Return QuerySQLCacheValue.
> +     * @since 1.2.0
> +     */
> +    public QuerySQLCacheValue getQuerySQLCache();
> +
> +    /**
> +     * Whether querySQLCache is enabled or not.
> +     * @since 1.2.0
> +     */
> +    public boolean isQuerySQLCacheOn();
> +
> +    /**
> +     * Return QuerySQLCacheInstance.
> +     * @since 1.2.0
> +     */
> +    public Map getQuerySQLCacheInstance();
> +
> }
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/conf/JDBCConfigurationImpl.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/JDBCConfigurationImpl.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/JDBCConfigurationImpl.java Fri May  2 14:09:14 2008
> @@ -20,6 +20,9 @@
>
> import java.sql.Connection;
> import java.sql.ResultSet;
> +import java.util.HashMap;
> +import java.util.Map;
> +
> import javax.sql.DataSource;
>
> import org.apache.commons.lang.StringUtils;
> @@ -82,6 +85,8 @@
>     public ObjectValue mappingDefaultsPlugin;
>     public PluginValue driverDataSourcePlugin;
>     public MappingFactoryValue mappingFactoryPlugin;
> +    public QuerySQLCacheValue querySQLCache;
> +    private Map querySQLCacheInstance = new HashMap();
>
>     // used internally
>     private String firstUser = null;
> @@ -302,6 +307,9 @@
>         seqPlugin.setDefault(JDBCSeqValue.ALIASES[0]);
>         seqPlugin.setString(JDBCSeqValue.ALIASES[0]);
>
> +        querySQLCache = new QuerySQLCacheValue("jdbc.QuerySQLCache");
> +        addValue(querySQLCache);
> +
>         // this static initializer is to get past a weird
>         // ClassCircularityError that happens only under IBM's
>         // JDK 1.3.1 on Linux from within the JRun ClassLoader;
> @@ -856,4 +864,21 @@
>                 return true;
>         return false;
>     }
> +
> +    public void setQuerySQLCache(String querySQLCache) {
> +        this.querySQLCache.setString(querySQLCache);
> +    }
> +
> +    public QuerySQLCacheValue getQuerySQLCache() {
> +        return querySQLCache;
> +    }
> +
> +    public boolean isQuerySQLCacheOn() {
> +        return querySQLCache.isSQLCacheOn();
> +    }
> +
> +    public Map getQuerySQLCacheInstance() {
> +        return querySQLCacheInstance;
> +    }
> +
> }
>
> Added: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/ 
> jdbc/conf/QuerySQLCacheValue.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/QuerySQLCacheValue.java?rev=652913&view=auto
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/QuerySQLCacheValue.java (added)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> conf/QuerySQLCacheValue.java Fri May  2 14:09:14 2008
> @@ -0,0 +1,86 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License.  You may obtain a copy of the License at
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied.  See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + */
> +package org.apache.openjpa.jdbc.conf;
> +
> +import java.util.Collections;
> +import java.util.Hashtable;
> +import java.util.Map;
> +import java.util.concurrent.ConcurrentHashMap;
> +
> +import org.apache.openjpa.lib.conf.Configurations;
> +import org.apache.openjpa.lib.conf.PluginValue;
> +import org.apache.openjpa.util.CacheMap;
> +
> +
> +/**
> + * A cache of sql queries.
> + *
> + * @since 1.2
> + * @nojavadoc
> + */
> +public class QuerySQLCacheValue
> +    extends PluginValue {
> +
> +    public static final String[] ALIASES = {
> +        "true", CacheMap.class.getName(),
> +        "all", ConcurrentHashMap.class.getName(),
> +        "false", null,
> +    };
> +
> +    public QuerySQLCacheValue(String prop) {
> +        super(prop, true);
> +        setAliases(ALIASES);
> +        setDefault(ALIASES[0]);
> +        setClassName(ALIASES[1]);
> +    }
> +
> +    public boolean isSQLCacheOn() {
> +        if (getClassName() == null)
> +            return false;
> +        return true;
> +    }
> +
> +    public Object newInstance() {
> +        // make sure map handles concurrency
> +        String clsName = getClassName();
> +        if (clsName == null)
> +            return null;
> +        Map map = null;
> +
> +        try {
> +            // Use the "OpenJPA" classloader first...
> +            map = (Map) Configurations.newInstance(clsName,  
> this.getClass()
> +                    .getClassLoader());
> +        } catch (Exception e) {
> +            // If the "OpenJPA" classloader fails, then try the  
> classloader
> +            // that was used to load java.util.Map...
> +            map = (Map) Configurations.newInstance(clsName,
> +                    Map.class.getClassLoader());
> +        }
> +        if (map != null
> +                && !(map instanceof Hashtable)
> +                && !(map instanceof CacheMap)
> +                && !(map instanceof
> +                         
> org.apache.openjpa.lib.util.concurrent.ConcurrentMap)
> +                && !(map instanceof  
> java.util.concurrent.ConcurrentMap))
> +            map = Collections.synchronizedMap(map);
> +        return map;
> +    }
> +
> +}
>
> Propchange: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/conf/QuerySQLCacheValue.java
> ------------------------------------------------------------------------------
>    svn:eol-style = native
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/kernel/JDBCStoreManager.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> kernel/JDBCStoreManager.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> kernel/JDBCStoreManager.java Fri May  2 14:09:14 2008
> @@ -29,15 +29,20 @@
> import java.util.Collections;
> import java.util.HashSet;
> import java.util.Iterator;
> +import java.util.List;
> +import java.util.Map;
> import java.util.Set;
> +
> import javax.sql.DataSource;
>
> import org.apache.openjpa.event.OrphanedKeyAction;
> import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
> +import org.apache.openjpa.jdbc.conf.QuerySQLCacheValue;
> import org.apache.openjpa.jdbc.meta.ClassMapping;
> import org.apache.openjpa.jdbc.meta.Discriminator;
> import org.apache.openjpa.jdbc.meta.FieldMapping;
> import org.apache.openjpa.jdbc.meta.ValueMapping;
> +import org.apache.openjpa.jdbc.schema.Column;
> import org.apache.openjpa.jdbc.sql.DBDictionary;
> import org.apache.openjpa.jdbc.sql.JoinSyntaxes;
> import org.apache.openjpa.jdbc.sql.Joins;
> @@ -60,10 +65,12 @@
> import org.apache.openjpa.lib.jdbc.DelegatingConnection;
> import org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement;
> import org.apache.openjpa.lib.jdbc.DelegatingStatement;
> +import org.apache.openjpa.lib.log.Log;
> import org.apache.openjpa.lib.rop.MergedResultObjectProvider;
> import org.apache.openjpa.lib.rop.ResultObjectProvider;
> import org.apache.openjpa.lib.util.Localizer;
> import org.apache.openjpa.meta.ClassMetaData;
> +import org.apache.openjpa.meta.FetchGroup;
> import org.apache.openjpa.meta.FieldMetaData;
> import org.apache.openjpa.meta.JavaTypes;
> import org.apache.openjpa.meta.ValueStrategies;
> @@ -99,7 +106,11 @@
>
>     // track the pending statements so we can cancel them
>     private Set _stmnts = Collections.synchronizedSet(new HashSet());
> -
> +
> +    private Map _sqlCache = null;
> +    private boolean _isQuerySQLCache = true;
> +    private static final Object _nullCacheValue = new Object();
> +
>     public StoreContext getContext() {
>         return _ctx;
>     }
> @@ -125,6 +136,9 @@
>
>         if (_conf.getUpdateManagerInstance().orderDirty())
>             ctx.setOrderDirtyObjects(true);
> +
> +        _sqlCache = _conf.getQuerySQLCacheInstance();
> +        _isQuerySQLCache = _conf.isQuerySQLCacheOn();
>     }
>
>     public JDBCConfiguration getConfiguration() {
> @@ -402,13 +416,86 @@
>     private Result getInitializeStateResult(OpenJPAStateManager sm,
>         ClassMapping mapping, JDBCFetchConfiguration fetch, int subs)
>         throws SQLException {
> +        List params = new ArrayList();
> +        Select sel = newSelect(sm, mapping, fetch, subs, params);
> +        if (sel == null) return null;
> +        return sel.execute(this, fetch, params);
> +    }
> +
> +    private Select newSelect(OpenJPAStateManager sm,
> +        ClassMapping mapping, JDBCFetchConfiguration fetch, int subs,
> +        List params) {
> +        if (!_isQuerySQLCache)
> +            return newSelect(sm, mapping, fetch, subs);
> +
> +        Map<SelectKey, Select> selectImplCacheMap =
> +            getCacheMapFromQuerySQLCache(JDBCStoreManager.class);
> +        JDBCFetchConfiguration fetchClone = new  
> JDBCFetchConfigurationImpl();
> +        fetchClone.copy(fetch);
> +        SelectKey selKey = new SelectKey(mapping, null, fetchClone);
> +        Select sel = null;
> +        boolean found = true;
> +        Object obj = selectImplCacheMap.get(selKey);
> +        if (obj == null) {
> +            synchronized (selectImplCacheMap) {
> +                obj = selectImplCacheMap.get(selKey);
> +                if (obj == null) {
> +                    // Not found in cache, create a new select
> +                    obj = newSelect(sm, mapping, fetch, subs);
> +                    found = false;
> +                }
> +
> +                if (obj == null) {
> +                    // If the generated SelectImpl is null, store a  
> generic
> +                    // known object in the cache as a placeholder.  
> Some map
> +                    // implementations do not allow null values.
> +                    obj = _nullCacheValue;
> +                    found = false;
> +                }
> +                else if (obj != _nullCacheValue)
> +                {
> +                    sel = (Select)obj;
> +                    if (sel.getSQL() == null) {
> +                        sel.setSQL(this, fetch);
> +                        found = false;
> +                    }
> +                }
> +                if (!found) {
> +                    addToSqlCache(selectImplCacheMap, selKey, obj);
> +                }
> +            }
> +        }
> +
> +        if (obj != null && obj != _nullCacheValue)
> +            sel = (Select) obj;
> +
> +        Log log = _conf.getLog(JDBCConfiguration.LOG_JDBC);
> +        if (log.isTraceEnabled()) {
> +            if (!found)
> +                log.trace(_loc.get("cache-missed", mapping,  
> this.getClass()));
> +            else
> +                log.trace(_loc.get("cache-hit", mapping,  
> this.getClass()));
> +        }
> +
> +        if (sel == null)
> +            return null;
> +
> +        Object oid = sm.getObjectId();
> +        Column[] cols = mapping.getPrimaryKeyColumns();
> +        sel.wherePrimaryKey(mapping, cols, cols, oid, this,
> +        	null, null, params);
> +        return sel;
> +    }
> +
> +    protected Select newSelect(OpenJPAStateManager sm,
> +        ClassMapping mapping, JDBCFetchConfiguration fetch, int  
> subs) {
>         Select sel = _sql.newSelect();
>         if (!select(sel, mapping, subs, sm, null, fetch,
>             JDBCFetchConfiguration.EAGER_JOIN, true, false))
>             return null;
>         sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
>         sel.setExpectedResultCount(1, false);
> -        return sel.execute(this, fetch);
> +        return sel;
>     }
>
>     /**
> @@ -1419,4 +1506,163 @@
>             }
>         }
>     }
> +
> +    public Map getCacheMapFromQuerySQLCache(Object key) {
> +        synchronized(_sqlCache) {
> +            //sqlCache is a map of map
> +            Map cacheMap = (Map)_sqlCache.get(key);
> +            if (cacheMap == null) {
> +                cacheMap = createSQLCache();
> +                _sqlCache.put(key, cacheMap);
> +            }
> +            return cacheMap;
> +        }
> +    }
> +
> +    public void addToSqlCache(Map cacheMap, Object key, Object  
> value) {
> +        cacheMap.put(key, value);
> +    }
> +
> +    public Map createSQLCache() {
> +        QuerySQLCacheValue querySQLCache = _conf.getQuerySQLCache();
> +        return (Map)querySQLCache.newInstance();
> +    }
> +
> +    public boolean isQuerySQLCacheOn() {
> +        return _isQuerySQLCache;
> +    }
> +
> +    public Map getQuerySQLCache() {
> +        return _sqlCache;
> +    }
> +
> +    public static class SelectKey {
> +        public ClassMapping mapping;
> +        public FieldMapping fm;
> +        public JDBCFetchConfiguration fetch;
> +
> +        public SelectKey (ClassMapping mapping, FieldMapping fm,
> +            JDBCFetchConfiguration fetch) {
> +            this.mapping = mapping;
> +            this.fm = fm;
> +            this.fetch = fetch;
> +        }
> +
> +        public boolean equals(Object o) {
> +            if (this == o) return true;
> +            if (o == null || getClass() != o.getClass()) return  
> false;
> +
> +            SelectKey selectKey = (SelectKey) o;
> +            if (fetch != null ? !equals(fetch, selectKey.fetch) :
> +                selectKey.fetch != null) return false;
> +            if (mapping != null ? ! 
> mapping.equals(selectKey.mapping) :
> +                selectKey.mapping != null) return false;
> +            if (fm != null ? !fm.equals(selectKey.fm) :
> +                selectKey.fm != null) return false;
> +            return true;
> +        }
> +
> +        public boolean equals(JDBCFetchConfiguration fetch1,
> +        	JDBCFetchConfiguration fetch2) {
> +            if (fetch1 == fetch2)
> +            	return true;
> +
> +            if (fetch1.getIsolation() != fetch2.getIsolation())
> +            	return false;
> +            if (fetch1.getFetchDirection() !=  
> fetch2.getFetchDirection())
> +            	return false;
> +            if (fetch1.getEagerFetchMode() !=  
> fetch2.getEagerFetchMode())
> +            	return false;
> +            if (fetch1.getSubclassFetchMode() !=  
> fetch2.getSubclassFetchMode())
> +            	return false;
> +            if (fetch1.getJoinSyntax() != fetch2.getJoinSyntax())
> +            	return false;
> +            Set joins1 = fetch1.getJoins();
> +            Set joins2 = fetch2.getJoins();
> +            if (joins1 != null ? !joins1.equals(joins2) : joins2 !=  
> null)
> +                return false;
> +
> +            if (fetch1.getMaxFetchDepth() !=  
> fetch2.getMaxFetchDepth())
> +            	return false;
> +            if (fetch1.getReadLockLevel() !=  
> fetch2.getReadLockLevel())
> +            	return false;
> +            if (fetch1.getWriteLockLevel() !=  
> fetch2.getWriteLockLevel())
> +            	return false;
> +
> +            boolean sameFetchGroup = false;
> +            boolean hasFetchGroupAll =  
> ((JDBCFetchConfigurationImpl)fetch1).
> +            	hasFetchGroupAll();
> +            boolean hasFetchGroupAll1 =  
> ((JDBCFetchConfigurationImpl)fetch2).
> +            	hasFetchGroupAll();
> +            if (hasFetchGroupAll && hasFetchGroupAll1)
> +                sameFetchGroup = true;
> +            else if (!hasFetchGroupAll && !hasFetchGroupAll1){
> +                boolean hasFetchGroupDefault =
> +                	 
> ((JDBCFetchConfigurationImpl)fetch1).hasFetchGroupDefault();
> +                boolean hasFetchGroupDefault1 =
> +                	 
> ((JDBCFetchConfigurationImpl)fetch2).hasFetchGroupDefault();
> +                if (hasFetchGroupDefault && hasFetchGroupDefault1)
> +                    sameFetchGroup = true;
> +            }
> +
> +            if (!sameFetchGroup) {
> +                Set fetchGroups = fetch1.getFetchGroups();
> +                Set fetchGroups1 = fetch2.getFetchGroups();
> +                if (fetchGroups != null ? ! 
> fetchGroups.equals(fetchGroups1) :
> +                	fetchGroups1 != null)
> +                    return false;
> +            }
> +
> +            Set fields = fetch1.getFields();
> +            Set fields1 = fetch2.getFields();
> +            int size = fields.size();
> +            int size1 = fields1.size();
> +            if (size == 0 && size1 == 0)
> +                return true;
> +            else if (size != size1)
> +                return false;
> +
> +            if (fields != null ? !fields.equals(fields1) : fields1 ! 
> = null)
> +                return false;
> +
> +            return true;
> +        }
> +
> +
> +        public int hashCode() {
> +            int result = 0;
> +            result = 31 * result + (mapping != null ?  
> mapping.hashCode() : 0);
> +            result = 31 * result + (fm != null ? fm.hashCode() : 0);
> +            result = 31 * result + fetch.getIsolation();
> +            result = 31 * result + fetch.getFetchDirection();
> +            result = 31 * result + fetch.getEagerFetchMode();
> +            result = 31 * result + fetch.getSubclassFetchMode();
> +            result = 31 * result + fetch.getJoinSyntax();
> +            Set joins = fetch.getJoins();
> +            result = 31 * result + (joins != null ?  
> joins.hashCode() : 0);
> +
> +            result = 31 * result + fetch.getMaxFetchDepth();
> +            result = 31 * result + fetch.getReadLockLevel();
> +            result = 31 * result + fetch.getWriteLockLevel();
> +        	
> +            if  
> (((JDBCFetchConfigurationImpl)fetch).hasFetchGroupAll())
> +            	result = 31 * result + FetchGroup.NAME_ALL.hashCode();
> +            else {
> +                Set fetchGroups = fetch.getFetchGroups();
> +                if  
> (((JDBCFetchConfigurationImpl)fetch).hasFetchGroupDefault()
> +                	&& fetchGroups != null && fetchGroups.size() == 1)
> +                    result = 31 * result +  
> FetchGroup.NAME_DEFAULT.hashCode();
> +                else {
> +                    result = 31 * result + (fetchGroups != null &&
> +                        fetchGroups.size() > 0 ?
> +                        fetchGroups.hashCode() : 0);
> +                }
> +            }
> +            Set fields = fetch.getFields();
> +        	result = 31 * result + (fields != null &&  fields.size() >  
> 0 ?
> +        		fields.hashCode() : 0);
> +
> +            return result;
> +        }
> +    }
> }
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/meta/strats/RelationFieldStrategy.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> meta/strats/RelationFieldStrategy.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> meta/strats/RelationFieldStrategy.java Fri May  2 14:09:14 2008
> @@ -19,11 +19,16 @@
> package org.apache.openjpa.jdbc.meta.strats;
>
> import java.sql.SQLException;
> +import java.util.ArrayList;
> import java.util.HashMap;
> +import java.util.List;
> import java.util.Map;
>
> +import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
> import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
> +import org.apache.openjpa.jdbc.kernel.JDBCFetchConfigurationImpl;
> import org.apache.openjpa.jdbc.kernel.JDBCStore;
> +import org.apache.openjpa.jdbc.kernel.JDBCStoreManager;
> import org.apache.openjpa.jdbc.meta.ClassMapping;
> import org.apache.openjpa.jdbc.meta.Embeddable;
> import org.apache.openjpa.jdbc.meta.FieldMapping;
> @@ -38,12 +43,14 @@
> import org.apache.openjpa.jdbc.schema.Table;
> import org.apache.openjpa.jdbc.sql.DBDictionary;
> import org.apache.openjpa.jdbc.sql.Joins;
> +import org.apache.openjpa.jdbc.sql.LogicalUnion;
> import org.apache.openjpa.jdbc.sql.Result;
> import org.apache.openjpa.jdbc.sql.Row;
> import org.apache.openjpa.jdbc.sql.RowManager;
> import org.apache.openjpa.jdbc.sql.SQLBuffer;
> import org.apache.openjpa.jdbc.sql.Select;
> import org.apache.openjpa.jdbc.sql.SelectExecutor;
> +import org.apache.openjpa.jdbc.sql.SelectImpl;
> import org.apache.openjpa.jdbc.sql.Union;
> import org.apache.openjpa.kernel.OpenJPAStateManager;
> import org.apache.openjpa.lib.log.Log;
> @@ -55,6 +62,7 @@
> import org.apache.openjpa.util.MetaDataException;
> import org.apache.openjpa.util.OpenJPAId;
> import org.apache.openjpa.util.UnsupportedException;
> +
> import serp.util.Numbers;
>
> /**
> @@ -579,9 +587,97 @@
>         final int subs = field.getSelectSubclasses();
>         final Joins[] resJoins = new Joins[rels.length];
>
> -        // select related mapping columns; joining from the related  
> type
> -        // back to our fk table if not an inverse mapping (in which  
> case we
> -        // can just make sure the inverse cols == our pk values)
> +        //cache union for field here
> +        //select data for this sm
> +        Union union = null;
> +        SelectImpl sel = null;
> +        List parmList = null;
> +
> +        if (!((JDBCStoreManager)store).isQuerySQLCacheOn())
> +            union = newUnion(sm, store, fetch, rels, subs, resJoins);
> +        else {
> +            Map<JDBCStoreManager.SelectKey, Object[]>  
> relationFieldUnionCache =
> +                 
> ((JDBCStoreManager)store).getCacheMapFromQuerySQLCache(
> +                RelationFieldStrategy.class);
> +            boolean found = true;
> +            JDBCFetchConfiguration fetchClone = new  
> JDBCFetchConfigurationImpl();
> +            fetchClone.copy(fetch);
> +            JDBCStoreManager.SelectKey selKey =
> +                new JDBCStoreManager.SelectKey(null, field, fetch);
> +            Object[] obj = relationFieldUnionCache.get(selKey);
> +            if (obj != null) {
> +                union = (Union) obj[0];
> +                resJoins[0] = (Joins)obj[1];
> +            } else {
> +                synchronized(relationFieldUnionCache) {
> +                    obj = relationFieldUnionCache.get(selKey);
> +                    if (obj != null) {
> +                        union = (Union) obj[0];
> +                        resJoins[0] = (Joins) obj[1];
> +                    } else {
> +                        // select related mapping columns; joining  
> from the
> +                        // related type back to our fk table if not  
> an inverse
> +                        // mapping (in which case we can just make  
> sure the
> +                        // inverse cols == our pk values)
> +                        union = newUnion(sm, store, fetch, rels,  
> subs,
> +                                resJoins);
> +                        found = false;
> +                    }
> +                    sel =  
> ((LogicalUnion.UnionSelect)union.getSelects()[0]).
> +                        getDelegate();
> +                    SQLBuffer buf = sel.getSQL();
> +                    if (buf == null) {
> +                    	((SelectImpl)sel).setSQL(store, fetch);
> +                        found = false;
> +                    }
> +
> +                    // only cache the union when elems length is 1  
> for now
> +                    if (!found && rels.length == 1) {
> +                        Object[] obj1 = new Object[2];
> +                        obj1[0] = union;
> +                        obj1[1] = resJoins[0];
> +                        ((JDBCStoreManager)store).addToSqlCache(
> +                            relationFieldUnionCache, selKey, obj1);
> +                    }
> +                }
> +            }
> +            Log log = store.getConfiguration().
> +                getLog(JDBCConfiguration.LOG_JDBC);
> +            if (log.isTraceEnabled()){
> +                if (found)
> +                    log.trace(_loc.get("cache-hit", field,  
> this.getClass()));
> +                else
> +                    log.trace(_loc.get("cache-missed", field,  
> this.getClass()));
> +            }
> +
> +            parmList = new ArrayList();
> +            ClassMapping mapping = field.getDefiningMapping();
> +            Object oid = sm.getObjectId();
> +            Column[] cols = mapping.getPrimaryKeyColumns();
> +            if (sel == null)
> +                sel = ((LogicalUnion.UnionSelect)union.getSelects() 
> [0]).
> +                getDelegate();
> +
> +            sel.wherePrimaryKey(mapping, cols, cols, oid, store,
> +            	null, null, parmList);
> +        }
> +
> +        Result res = union.execute(store, fetch, parmList);
> +        try {
> +            Object val = null;
> +            if (res.next())
> +                val = res.load(rels[res.indexOf()], store, fetch,
> +                    resJoins[res.indexOf()]);
> +            sm.storeObject(field.getIndex(), val);
> +        } finally {
> +            res.close();
> +        }
> +    }
> +
> +    protected Union newUnion(final OpenJPAStateManager sm,
> +        final JDBCStore store, final JDBCFetchConfiguration fetch,
> +        final ClassMapping[] rels, final int subs,
> +        final Joins[] resJoins) {
>         Union union = store.getSQLFactory().newUnion(rels.length);
>         union.setExpectedResultCount(1, false);
>         if (fetch.getSubclassFetchMode(field.getTypeMapping())
> @@ -602,17 +698,7 @@
>                     resJoins[idx]);
>             }
>         });
> -
> -        Result res = union.execute(store, fetch);
> -        try {
> -            Object val = null;
> -            if (res.next())
> -                val = res.load(rels[res.indexOf()], store, fetch,
> -                    resJoins[res.indexOf()]);
> -            sm.storeObject(field.getIndex(), val);
> -        } finally {
> -            res.close();
> -        }
> +        return union;
>     }
>
>     public Object toDataStoreValue(Object val, JDBCStore store) {
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> meta/strats/StoreCollectionFieldStrategy.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> meta/strats/StoreCollectionFieldStrategy.java Fri May  2 14:09:14 2008
> @@ -22,21 +22,29 @@
> import java.util.ArrayList;
> import java.util.Collection;
> import java.util.HashMap;
> +import java.util.List;
> import java.util.Map;
>
> +import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
> import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
> +import org.apache.openjpa.jdbc.kernel.JDBCFetchConfigurationImpl;
> import org.apache.openjpa.jdbc.kernel.JDBCStore;
> +import org.apache.openjpa.jdbc.kernel.JDBCStoreManager;
> import org.apache.openjpa.jdbc.meta.ClassMapping;
> import org.apache.openjpa.jdbc.meta.FieldMapping;
> import org.apache.openjpa.jdbc.meta.FieldStrategy;
> import org.apache.openjpa.jdbc.schema.Column;
> import org.apache.openjpa.jdbc.schema.ForeignKey;
> import org.apache.openjpa.jdbc.sql.Joins;
> +import org.apache.openjpa.jdbc.sql.LogicalUnion;
> import org.apache.openjpa.jdbc.sql.Result;
> import org.apache.openjpa.jdbc.sql.Select;
> import org.apache.openjpa.jdbc.sql.SelectExecutor;
> +import org.apache.openjpa.jdbc.sql.SelectImpl;
> import org.apache.openjpa.jdbc.sql.Union;
> import org.apache.openjpa.kernel.OpenJPAStateManager;
> +import org.apache.openjpa.lib.log.Log;
> +import org.apache.openjpa.lib.util.Localizer;
> import org.apache.openjpa.meta.JavaTypes;
> import org.apache.openjpa.util.ChangeTracker;
> import org.apache.openjpa.util.Id;
> @@ -55,6 +63,9 @@
> public abstract class StoreCollectionFieldStrategy
>     extends ContainerFieldStrategy {
>
> +    private static final Localizer _loc = Localizer.forPackage
> +        (StoreCollectionFieldStrategy.class);
> +
>     /**
>      * Return the foreign key used to join to the owning field for  
> the given
>      * element mapping from {@link #getIndependentElementMappings}  
> (or null).
> @@ -445,19 +456,83 @@
>             return;
>         }
>
> +        //cache union for field here
>         // select data for this sm
> +        boolean found = true;
>         final ClassMapping[] elems =  
> getIndependentElementMappings(true);
>         final Joins[] resJoins = new Joins[Math.max(1, elems.length)];
> -        Union union = store.getSQLFactory().newUnion
> -            (Math.max(1, elems.length));
> -        union.select(new Union.Selector() {
> -            public void select(Select sel, int idx) {
> -                ClassMapping elem = (elems.length == 0) ? null :  
> elems[idx];
> -                resJoins[idx] = selectAll(sel, elem, sm, store,  
> fetch,
> -                    JDBCFetchConfiguration.EAGER_PARALLEL);
> +        List parmList = null;
> +        Union union = null;
> +        SelectImpl sel = null;
> +        Map<JDBCStoreManager.SelectKey, Object[]>  
> storeCollectionUnionCache = null;
> +        JDBCStoreManager.SelectKey selKey = null;
> +        if (!((JDBCStoreManager)store).isQuerySQLCacheOn())
> +            union = newUnion(sm, store, fetch, elems, resJoins);
> +        else {
> +            parmList = new ArrayList();
> +            JDBCFetchConfiguration fetchClone = new  
> JDBCFetchConfigurationImpl();
> +            fetchClone.copy(fetch);
> +
> +            // to specify the type so that no cast is needed
> +            storeCollectionUnionCache = ((JDBCStoreManager)store).
> +                 
> getCacheMapFromQuerySQLCache(StoreCollectionFieldStrategy.class);
> +            selKey =
> +                new JDBCStoreManager.SelectKey(null, field,  
> fetchClone);
> +            Object[] objs = storeCollectionUnionCache.get(selKey);
> +            if (objs != null) {
> +                union = (Union) objs[0];
> +                resJoins[0] = (Joins) objs[1];
>             }
> -        });
> +            else {
> +                synchronized(storeCollectionUnionCache) {
> +                    objs = storeCollectionUnionCache.get(selKey);
> +                    if (objs == null) {
> +                        // select data for this sm
> +                        union = newUnion(sm, store, fetch, elems,  
> resJoins);
> +                        found = false;
> +                    } else {
> +                        union = (Union) objs[0];
> +                        resJoins[0] = (Joins) objs[1];
> +                    }
> +
> +                    sel =  
> ((LogicalUnion.UnionSelect)union.getSelects()[0]).
> +                        getDelegate();
> +                    if (sel.getSQL() == null) {
> +                    	((SelectImpl)sel).setSQL(store, fetch);
> +                        found = false;
> +                    }
> +
> +                    // only cache the union when elems length is 1  
> for now
> +                    if (!found && elems.length == 1) {
> +                        Object[] objs1 = new Object[2];
> +                        objs1[0] = union;
> +                        objs1[1] = resJoins[0];
> +                        ((JDBCStoreManager)store).addToSqlCache(
> +                            storeCollectionUnionCache, selKey,  
> objs1);
> +                     }
> +                }
> +            }
> +
> +            Log log = store.getConfiguration().
> +                getLog(JDBCConfiguration.LOG_JDBC);
> +            if (log.isTraceEnabled()) {
> +                if (found)
> +                    log.trace(_loc.get("cache-hit", field,  
> this.getClass()));
> +                else
> +                    log.trace(_loc.get("cache-missed", field,  
> this.getClass()));
> +            }
> +
> +            ClassMapping mapping = field.getDefiningMapping();
> +            Object oid = sm.getObjectId();
> +            Column[] cols = mapping.getPrimaryKeyColumns();
> +            if (sel == null)
> +                sel = ((LogicalUnion.UnionSelect)union.getSelects() 
> [0]).
> +                getDelegate();
>
> +            sel.wherePrimaryKey(mapping, cols, cols, oid, store,
> +                	null, null, parmList);
> +        }
> +
>         // create proxy
>         Object coll;
>         ChangeTracker ct = null;
> @@ -470,14 +545,14 @@
>         }
>
>         // load values
> -        Result res = union.execute(store, fetch);
> +        Result res = union.execute(store, fetch, parmList);
>         try {
>             int seq = -1;
>             while (res.next()) {
>                 if (ct != null && field.getOrderColumn() != null)
>                     seq = res.getInt(field.getOrderColumn());
> -                add(store, coll, loadElement(sm, store, fetch, res,
> -                    resJoins[res.indexOf()]));
> +               	add(store, coll, loadElement(sm, store, fetch, res,
> +           	        resJoins[res.indexOf()]));
>             }
>             if (ct != null && field.getOrderColumn() != null)
>                 ct.setNextSequence(seq + 1);
> @@ -493,6 +568,21 @@
>             sm.storeObject(field.getIndex(), coll);
>     }
>
> +    protected Union newUnion(final OpenJPAStateManager sm, final  
> JDBCStore store,
> +        final JDBCFetchConfiguration fetch, final ClassMapping[]  
> elems,
> +        final Joins[] resJoins) {
> +        Union union = store.getSQLFactory().newUnion
> +        (Math.max(1, elems.length));
> +        union.select(new Union.Selector() {
> +            public void select(Select sel, int idx) {
> +                ClassMapping elem = (elems.length == 0) ? null :  
> elems[idx];
> +                resJoins[idx] = selectAll(sel, elem, sm, store,  
> fetch,
> +                        JDBCFetchConfiguration.EAGER_PARALLEL);
> +            }
> +        });
> +        return union;
> +    }
> +
>     /**
>      * Select data for loading, starting in field table.
>      */
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/sql/LogicalUnion.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/LogicalUnion.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/LogicalUnion.java Fri May  2 14:09:14 2008
> @@ -202,20 +202,32 @@
>     }
>
>     public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch)
> +            throws SQLException {
> +        return execute(store, fetch, null);
> +    }
> +
> +    public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
> +        int lockLevel)
> +        throws SQLException {
> +        return execute(store, fetch, lockLevel, null);
> +    }
> +
> +    public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
> +        List params)
>         throws SQLException {
>         if (fetch == null)
>             fetch = store.getFetchConfiguration();
> -        return execute(store, fetch, fetch.getReadLockLevel());
> +        return execute(store, fetch, fetch.getReadLockLevel(),  
> params);
>     }
>
>     public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
> -        int lockLevel)
> +        int lockLevel, List params)
>         throws SQLException {
>         if (fetch == null)
>             fetch = store.getFetchConfiguration();
>
>         if (sels.length == 1) {
> -            Result res = sels[0].execute(store, fetch, lockLevel);
> +            Result res = sels[0].execute(store, fetch, lockLevel,  
> params);
>             ((AbstractResult) res).setBaseMapping(mappings[0]);
>             return res;
>         }
> @@ -224,7 +236,7 @@
>             AbstractResult res;
>             for (int i = 0; i < sels.length; i++) {
>                 res = (AbstractResult) sels[i].execute(store, fetch,
> -                    lockLevel);
> +                    lockLevel, params);
>                 res.setBaseMapping(mappings[i]);
>                 res.setIndexOf(i);
>
> @@ -256,7 +268,7 @@
>             List l;
>             for (int i = 0; i < res.length; i++) {
>                 res[i] = (AbstractResult) sels[i].execute(store,  
> fetch,
> -                    lockLevel);
> +                    lockLevel, params);
>                 res[i].setBaseMapping(mappings[i]);
>                 res[i].setIndexOf(i);
>
> @@ -303,7 +315,7 @@
>     /**
>      * A select that is part of a logical union.
>      */
> -    protected class UnionSelect
> +    public class UnionSelect
>         implements Select {
>
>         protected final SelectImpl sel;
> @@ -396,6 +408,18 @@
>             return sel.getCount(store);
>         }
>
> +        public Result execute(JDBCStore store,  
> JDBCFetchConfiguration fetch,
> +            List params)
> +            throws SQLException {
> +            return sel.execute(store, fetch, params);
> +        }
> +
> +        public Result execute(JDBCStore store,  
> JDBCFetchConfiguration fetch,
> +            int lockLevel, List params)
> +            throws SQLException {
> +            return sel.execute(store, fetch, lockLevel, params);
> +        }
> +
>         public Result execute(JDBCStore store,  
> JDBCFetchConfiguration fetch)
>             throws SQLException {
>             return sel.execute(store, fetch);
> @@ -406,7 +430,7 @@
>             throws SQLException {
>             return sel.execute(store, fetch, lockLevel);
>         }
> -
> +
>         public List getSubselects() {
>             return Collections.EMPTY_LIST;
>         }
> @@ -475,6 +499,14 @@
>             return sel.getHaving();
>         }
>
> +        public SQLBuffer getSQL() {
> +            return sel.getSQL();
> +        }
> +
> +        public void setSQL(JDBCStore store, JDBCFetchConfiguration  
> fetch) {
> +            sel.setSQL(store, fetch);
> +        }
> +
>         public void addJoinClassConditions() {
>             sel.addJoinClassConditions();
>         }
> @@ -717,6 +749,15 @@
>             JDBCStore store) {
>             sel.wherePrimaryKey(oid, mapping, store);
>         }
> +
> +        public int wherePrimaryKey(ClassMapping mapping, Column[]  
> toCols,
> +            Column[] fromCols, Object oid, JDBCStore store,  
> PathJoins pj,
> +            SQLBuffer buf, List parmList) {
> +            return sel.wherePrimaryKey(mapping, toCols, fromCols,  
> oid, store, pj,
> +                buf, parmList);
> +        }
> +
> +
>
>         public void whereForeignKey(ForeignKey fk, Object oid,
>             ClassMapping mapping, JDBCStore store) {
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/sql/SQLBuffer.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SQLBuffer.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SQLBuffer.java Fri May  2 14:09:14 2008
> @@ -450,9 +450,19 @@
>      * the SQL in this buffer.
>      */
>     public PreparedStatement prepareStatement(Connection conn, int  
> rsType,
> +        int rsConcur, List parms)
> +        throws SQLException {
> +        return prepareStatement(conn, null, rsType, rsConcur, parms);
> +    }
> +
> +    /**
> +     * Create and populate the parameters of a prepared statement  
> using
> +     * the SQL in this buffer.
> +     */
> +    public PreparedStatement prepareStatement(Connection conn, int  
> rsType,
>         int rsConcur)
>         throws SQLException {
> -        return prepareStatement(conn, null, rsType, rsConcur);
> +        return prepareStatement(conn, rsType, rsConcur, null);
>     }
>
>     /**
> @@ -462,6 +472,16 @@
>     public PreparedStatement prepareStatement(Connection conn,
>         JDBCFetchConfiguration fetch, int rsType, int rsConcur)
>         throws SQLException {
> +        return prepareStatement(conn, fetch, rsType, rsConcur, null);
> +    }
> +
> +    /**
> +     * Create and populate the parameters of a prepred statement  
> using the
> +     * SQL in this buffer and the given fetch configuration.
> +     */
> +    public PreparedStatement prepareStatement(Connection conn,
> +        JDBCFetchConfiguration fetch, int rsType, int rsConcur,  
> List parms)
> +        throws SQLException {
>         if (rsType == -1 && fetch == null)
>             rsType = ResultSet.TYPE_FORWARD_ONLY;
>         else if (rsType == -1)
> @@ -476,7 +496,7 @@
>         else
>             stmnt = conn.prepareStatement(getSQL(), rsType, rsConcur);
>         try {
> -            setParameters(stmnt);
> +            setParameters(stmnt, parms);
>             if (fetch != null) {
>                 if (fetch.getFetchBatchSize() > 0)
>                     stmnt.setFetchSize(fetch.getFetchBatchSize());
> @@ -559,13 +579,25 @@
>      */
>     public void setParameters(PreparedStatement ps)
>         throws SQLException {
> -        if (_params == null)
> +        setParameters(ps, null);
> +    }
> +
> +    /**
> +     * Populate the parameters of an existing PreparedStatement
> +     * with values from this buffer.
> +     */
> +    public void setParameters(PreparedStatement ps, List cacheParams)
> +        throws SQLException {
> +        List params = ((cacheParams != null && cacheParams.size() >  
> 0) ?
> +            cacheParams : _params);
> +
> +        if (params == null)
>             return;
>
>         Column col;
> -        for (int i = 0; i < _params.size(); i++) {
> +        for (int i = 0; i < params.size(); i++) {
>             col = (_cols == null) ? null : (Column) _cols.get(i);
> -            _dict.setUnknown(ps, i + 1, _params.get(i), col);
> +            _dict.setUnknown(ps, i + 1, params.get(i), col);
>         }
>     }
>
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/sql/Select.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/Select.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/Select.java Fri May  2 14:09:14 2008
> @@ -193,6 +193,19 @@
>     public SQLBuffer getHaving();
>
>     /**
> +     * Return the SQL for this select. This buffer contains
> +     * the final SQL to be executed/cached.
> +     */
> +    public SQLBuffer getSQL();
> +
> +    /**
> +     * Create and set the SQLBuffer object to this select. This  
> buffer contains
> +     * the final SQL to be executed/cached.
> +     */
> +    public void setSQL(JDBCStore store, JDBCFetchConfiguration  
> fetch);
> +
> +
> +    /**
>      * Apply class conditions from relation joins.  This may affect  
> the return
>      * values of {@link #getJoins}, {@link #getJoinIterator}, and
>      * {@link #getWhere}.
> @@ -515,6 +528,19 @@
>      */
>     public void wherePrimaryKey(Object oid, ClassMapping mapping,
>         JDBCStore store);
> +
> +
> +    /**
> +     * Add where conditions setting the mapping's primary key to  
> the given
> +     * oid values. If the parmList is not null, the value of the  
> primary
> +     * key will be collected and saved into the parmList. If the  
> parmList is
> +     * null, this method will build the where clause with the value
> +     * incorporated in the where clause.
> +     */
> +    public int wherePrimaryKey(ClassMapping mapping, Column[] toCols,
> +            Column[] fromCols, Object oid, JDBCStore store,  
> PathJoins pj,
> +            SQLBuffer buf, List parmList);
> +
>
>     /**
>      * Add where conditions setting the given foreign key to the given
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/sql/SelectExecutor.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectExecutor.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SelectExecutor.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SelectExecutor.java Fri May  2 14:09:14 2008
> @@ -19,6 +19,7 @@
> package org.apache.openjpa.jdbc.sql;
>
> import java.sql.SQLException;
> +import java.util.List;
>
> import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
> import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
> @@ -133,6 +134,20 @@
>      * Execute this select in the context of the given store manager.
>      */
>     public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
> +        List params)
> +        throws SQLException;
> +
> +    /**
> +     * Execute this select in the context of the given store manager.
> +     */
> +    public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
> +        int lockLevel, List params)
> +        throws SQLException;
> +
> +    /**
> +     * Execute this select in the context of the given store manager.
> +     */
> +    public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
>         int lockLevel)
>         throws SQLException;
> }
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/ 
> openjpa/jdbc/sql/SelectImpl.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SelectImpl.java (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ 
> sql/SelectImpl.java Fri May  2 14:09:14 2008
> @@ -118,6 +118,9 @@
>     // 'parent.address.street' for the purposes of comparisons
>     private Map _aliases = null;
>
> +    // to cache table alias using Table as the key
> +    private Map _tableAliases = null;
> +
>     // map of indexes to table aliases like 'TABLENAME t0'
>     private SortedMap _tables = null;
>
> @@ -167,7 +170,10 @@
>     // if the bit is set, the corresponding alias has been removed  
> from parent
>     // and recorded under subselect.
>     private BitSet _removedAliasFromParent = new BitSet(16);
> -
> +
> +    //contains final sql statement to be executed/cached
> +    private SQLBuffer _sql = null;
> +
>     /**
>      * Helper method to return the proper table alias for the given  
> alias index.
>      */
> @@ -300,7 +306,7 @@
>             stmnt = prepareStatement(conn, sql, null,
>                 ResultSet.TYPE_FORWARD_ONLY,
>                 ResultSet.CONCUR_READ_ONLY, false);
> -            rs = executeQuery(conn, stmnt, sql, false, store);
> +            rs = executeQuery(conn, stmnt, sql, false, store, null);
>             return getCount(rs);
>         } finally {
>             if (rs != null)
> @@ -312,20 +318,31 @@
>         }
>     }
>
> -    public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch)
> -        throws SQLException {
> +    public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
> +        List parms) throws SQLException {
>         if (fetch == null)
>             fetch = store.getFetchConfiguration();
>         return execute(store.getContext(), store, fetch,
> -            fetch.getReadLockLevel());
> +            fetch.getReadLockLevel(), parms);
> +    }
> +
> +    public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch)
> +        throws SQLException {
> +        return execute(store, fetch, null);
> +     }
> +
> +    public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
> +        int lockLevel, List parms)
> +        throws SQLException {
> +            if (fetch == null)
> +                fetch = store.getFetchConfiguration();
> +            return execute(store.getContext(), store, fetch,  
> lockLevel, parms);
>     }
>
>     public Result execute(JDBCStore store, JDBCFetchConfiguration  
> fetch,
>         int lockLevel)
>         throws SQLException {
> -        if (fetch == null)
> -            fetch = store.getFetchConfiguration();
> -        return execute(store.getContext(), store, fetch, lockLevel);
> +        return execute(store, fetch, lockLevel, null);
>     }
>
>     /**
> @@ -333,16 +350,21 @@
>      * context is passed in separately for profiling purposes.
>      */
>     protected Result execute(StoreContext ctx, JDBCStore store,
> -        JDBCFetchConfiguration fetch, int lockLevel)
> +        JDBCFetchConfiguration fetch, int lockLevel, List params)
>         throws SQLException {
> -        boolean forUpdate = false;
> -        if (!isAggregate() && _grouping == null) {
> -            JDBCLockManager lm = store.getLockManager();
> -            if (lm != null)
> -                forUpdate = lm.selectForUpdate(this, lockLevel);
> -        }
> -
> -        SQLBuffer sql = toSelect(forUpdate, fetch);
> +        boolean forUpdate = isForUpdate(store, lockLevel);
> +
> +        // A non-null _sql indicates that this SelectImpl object
> +        // is obtained from cache. The _sql is constructed
> +        // under the assumption that isAggregate() is false
> +        // and _grouping is null. If neither of these holds,
> +        // we need to re-construct the _sql
> +        if (_sql != null && (isAggregate() || _grouping != null))
> +            _sql = null;
> +
> +        if (_sql == null)
> +        	_sql = toSelect(forUpdate, fetch);
> +
>         boolean isLRS = isLRS();
>         int rsType = (isLRS && supportsRandomAccess(forUpdate))
>             ? -1 : ResultSet.TYPE_FORWARD_ONLY;
> @@ -351,13 +373,15 @@
>         ResultSet rs = null;
>         try {
>             if (isLRS)
> -                stmnt = prepareStatement(conn, sql, fetch, rsType,  
> -1, true);
> +                stmnt = prepareStatement(conn, _sql, fetch, rsType,  
> -1, true,
> +                        params);
>             else
> -                stmnt = prepareStatement(conn, sql, null, rsType,  
> -1, false);
> +                stmnt = prepareStatement(conn, _sql, null, rsType,  
> -1, false,
> +                        params);
>
>             setTimeout(stmnt, forUpdate, fetch);
>
> -            rs = executeQuery(conn, stmnt, sql, isLRS, store);
> +            rs = executeQuery(conn, stmnt, _sql, isLRS, store,  
> params);
>         } catch (SQLException se) {
>             // clean up statement
>             if (stmnt != null)
> @@ -367,7 +391,17 @@
>         }
>
>         return getEagerResult(conn, stmnt, rs, store, fetch,  
> forUpdate,
> -            sql.getSQL());
> +            _sql.getSQL());
> +    }
> +
> +    private boolean isForUpdate(JDBCStore store, int lockLevel) {
> +    	boolean forUpdate = false;
> +        if (!isAggregate() && _grouping == null) {
> +            JDBCLockManager lm = store.getLockManager();
> +            if (lm != null)
> +                forUpdate = lm.selectForUpdate(this, lockLevel);
> +        }
> +        return forUpdate;
>     }
>
>     /**
> @@ -413,10 +447,22 @@
>     protected PreparedStatement prepareStatement(Connection conn,
>         SQLBuffer sql, JDBCFetchConfiguration fetch, int rsType,
>         int rsConcur, boolean isLRS) throws SQLException {
> +        // add comments why we pass in null as the last parameter
> +        return prepareStatement(conn, sql, fetch, rsType, rsConcur,  
> isLRS,
> +                null);
> +    }
> +
> +    /**
> +     * This method is to provide override for non-JDBC or JDBC-like
> +     * implementation of preparing statement.
> +     */
> +    protected PreparedStatement prepareStatement(Connection conn,
> +        SQLBuffer sql, JDBCFetchConfiguration fetch, int rsType,
> +        int rsConcur, boolean isLRS, List params) throws  
> SQLException {
>         if (fetch == null)
> -            return sql.prepareStatement(conn, rsType, rsConcur);
> +            return sql.prepareStatement(conn, rsType, rsConcur,  
> params);
>         else
> -            return sql.prepareStatement(conn, fetch, rsType, -1);
> +            return sql.prepareStatement(conn, fetch, rsType, -1,  
> params);
>     }
>
>     /**
> @@ -445,7 +491,8 @@
>      * implementation of executing query.
>      */
>     protected ResultSet executeQuery(Connection conn,  
> PreparedStatement stmnt,
> -        SQLBuffer sql, boolean isLRS, JDBCStore store) throws  
> SQLException {
> +        SQLBuffer sql, boolean isLRS, JDBCStore store, List params)
> +        throws SQLException {
>         return stmnt.executeQuery();
>     }
>
> @@ -589,6 +636,19 @@
>         return _having;
>     }
>
> +    public SQLBuffer getSQL() {
> +        return _sql;
> +    }
> +
> +    public void setSQL(SQLBuffer sql) {
> +        _sql = sql;
> +    }
> +
> +    public void setSQL(JDBCStore store, JDBCFetchConfiguration  
> fetch) {
> +        boolean forUpdate = isForUpdate(store,  
> fetch.getReadLockLevel());
> +        _sql = toSelect(forUpdate, fetch);
> +    }
> +
>     public void addJoinClassConditions() {
>         if (_joins == null || _joins.joins() == null)
>             return;
> @@ -656,13 +716,30 @@
>      * Return the alias for the given column.
>      */
>     private String getColumnAlias(String col, Table table, PathJoins  
> pj) {
> +        String tableAlias = null;
> +        if (pj == null || pj.path() == null) {
> +            if (_tableAliases == null)
> +                _tableAliases = new HashMap();
> +            tableAlias = (String) _tableAliases.get(table);
> +            if (tableAlias == null) {
> +                tableAlias = getTableAlias(table, pj).toString();
> +                _tableAliases.put(table, tableAlias);
> +            }
> +            return new  
> StringBuilder(tableAlias).append(col).toString();
> +        }
> +        return getTableAlias(table, pj).append(col).toString();
> +    }
> +
> +    private StringBuilder getTableAlias(Table table, PathJoins pj) {
> +        StringBuilder buf = new StringBuilder();
>         if (_from != null) {
>             String alias = toAlias(_from.getTableIndex(table, pj,  
> true));
>             if (_dict.requiresAliasForSubselect)
> -                return FROM_SELECT_ALIAS + "." + alias + "_" + col;
> -            return alias + "_" + col;
> +                return  
> buf.append(FROM_SELECT_ALIAS).append(".").append(alias).
> +                    append("_");
> +            return buf.append(alias).append("_");
>         }
> -        return toAlias(getTableIndex(table, pj, true)) + "." + col;
> +        return buf.append(toAlias(getTableIndex(table, pj,  
> true))).append(".");
>     }
>
>     public boolean isAggregate() {
> @@ -1263,12 +1340,38 @@
>             return;
>         }
>
> +        SQLBuffer buf = new SQLBuffer(_dict);
> +
> +        // only bother to pack pk values into array if app id
> +        int count = wherePrimaryKey(mapping, toCols, fromCols, oid,  
> store, pj,
> +        	buf, null);
> +            	
> +        if (constCols != null && constCols.length > 0) {
> +            for (int i = 0; i < constCols.length; i++, count++) {
> +                if (count > 0)
> +                    buf.append(" AND ");
> +                buf.append(getColumnAlias(constCols[i], pj));
> +
> +                if (vals[i] == null)
> +                    buf.append(" IS ");
> +                else
> +                    buf.append(" = ");
> +                buf.appendValue(vals[i], constCols[i]);
> +            }
> +        }
> +
> +        where(buf, pj);
> +    }
> +
> +    public int wherePrimaryKey(ClassMapping mapping, Column[] toCols,
> +    	Column[] fromCols, Object oid, JDBCStore store, PathJoins pj,
> +    	SQLBuffer buf, List parmList) {
>         // only bother to pack pk values into array if app id
> +    	boolean collectParmValueOnly = (parmList != null ? true :  
> false);
>         Object[] pks = null;
>         if (mapping.getIdentityType() == ClassMapping.ID_APPLICATION)
>             pks = ApplicationIds.toPKValues(oid, mapping);
>
> -        SQLBuffer buf = new SQLBuffer(_dict);
>         Joinable join;
>         Object val;
>         int count = 0;
> @@ -1281,8 +1384,13 @@
>                 val = pks[mapping.getField(join.getFieldIndex()).
>                     getPrimaryKeyIndex()];
>                 val = join.getJoinValue(val, toCols[i], store);
> +                if (parmList != null)
> +                	parmList.add(val);
>             }
> -
> +
> +            if (collectParmValueOnly)
> +            	continue;
> +
>             if (count > 0)
>                 buf.append(" AND ");
>             buf.append(getColumnAlias(fromCols[i], pj));
> @@ -1292,24 +1400,9 @@
>                 buf.append(" = ");
>             buf.appendValue(val, fromCols[i]);
>         }
> -
> -        if (constCols != null && constCols.length > 0) {
> -            for (int i = 0; i < constCols.length; i++, count++) {
> -                if (count > 0)
> -                    buf.append(" AND ");
> -                buf.append(getColumnAlias(constCols[i], pj));
> -
> -                if (vals[i] == null)
> -                    buf.append(" IS ");
> -                else
> -                    buf.append(" = ");
> -                buf.appendValue(vals[i], constCols[i]);
> -            }
> -        }
> -
> -        where(buf, pj);
> +        return count;
>     }
> -
> +
>     /**
>      * Test to see if the given set of columns contains all the
>      * columns in the given potential subset.
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/ 
> openjpa/jdbc/kernel/localizer.properties
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/localizer.properties?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ 
> jdbc/kernel/localizer.properties (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ 
> jdbc/kernel/localizer.properties Fri May  2 14:09:14 2008
> @@ -113,4 +113,5 @@
> batch_limit: The batch limit is set to {0}.
> batch_update_info: ExecuteBatch command returns update count {0} for \
> 	statement {1}.
> -
> +cache-hit: SQL Cache hit with key: {0} in {1}
> +cache-missed: SQL Cache missed with key: {0} in {1}
>
> Modified: openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/ 
> openjpa/jdbc/meta/strats/localizer.properties
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/strats/localizer.properties?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ 
> jdbc/meta/strats/localizer.properties (original)
> +++ openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/ 
> jdbc/meta/strats/localizer.properties Fri May  2 14:09:14 2008
> @@ -134,3 +134,5 @@
> 	its "{1}" primary key field does not use a simple mapping.
> unmapped-datastore-value: Instances of type "{0}" are not valid  
> query \
> 	parameters because the type is not mapped.
> +cache-hit: SQL Cache hit with key: {0} in {1}
> +cache-missed: SQL Cache missed with key: {0} in {1}
>
> Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/ 
> openjpa/kernel/FetchConfigurationImpl.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ 
> kernel/FetchConfigurationImpl.java (original)
> +++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ 
> kernel/FetchConfigurationImpl.java Fri May  2 14:09:14 2008
> @@ -82,6 +82,9 @@
>         public Set rootClasses;
>         public Set rootInstances;
>         public Map hints = null;
> +
> +        public boolean fetchGroupContainsDefault = false;
> +        public boolean fetchGroupContainsAll = false;
>     }
>
>     private final ConfigurationState _state;
> @@ -92,7 +95,7 @@
>     private boolean _load = true;
>     private int _availableRecursion;
>     private int _availableDepth;
> -
> +
>     public FetchConfigurationImpl() {
>         this(null);
>     }
> @@ -221,10 +224,22 @@
>
>     public boolean hasFetchGroup(String group) {
>         return _state.fetchGroups != null
> -            && (_state.fetchGroups.contains(group)
> -            || _state.fetchGroups.contains(FetchGroup.NAME_ALL));
> +            && (hasFetchGroupAll()
> +            ||  _state.fetchGroups.contains(group));
>     }
>
> +    public boolean hasFetchGroupDefault()
> +    {
> +        // Fetch group All includes fetch group Default by definition
> +        return _state.fetchGroupContainsDefault ||
> +            _state.fetchGroupContainsAll;
> +    }
> +
> +    public boolean hasFetchGroupAll()
> +    {
> +        return _state.fetchGroupContainsAll;
> +    }
> +
>     public FetchConfiguration addFetchGroup(String name) {
>         if (StringUtils.isEmpty(name))
>             throw new UserException(_loc.get("null-fg"));
> @@ -234,6 +249,10 @@
>             if (_state.fetchGroups == null)
>                 _state.fetchGroups = new HashSet();
>             _state.fetchGroups.add(name);
> +            if (FetchGroup.NAME_ALL.equals(name))
> +                _state.fetchGroupContainsAll = true;
> +            else if (FetchGroup.NAME_DEFAULT.equals(name))
> +                _state.fetchGroupContainsDefault = true;
>         } finally {
>             unlock();
>         }
> @@ -251,8 +270,13 @@
>     public FetchConfiguration removeFetchGroup(String group) {
>         lock();
>         try {
> -            if (_state.fetchGroups != null)
> +            if (_state.fetchGroups != null) {
>                 _state.fetchGroups.remove(group);
> +                if (FetchGroup.NAME_ALL.equals(group))
> +                    _state.fetchGroupContainsAll = false;
> +                else if (FetchGroup.NAME_DEFAULT.equals(group))
> +                    _state.fetchGroupContainsDefault = false;
> +            }
>         } finally {
>             unlock();
>         }
> @@ -262,8 +286,9 @@
>     public FetchConfiguration removeFetchGroups(Collection groups) {
>         lock();
>         try {
> -            if (_state.fetchGroups != null)
> -                _state.fetchGroups.removeAll(groups);
> +            if (_state.fetchGroups != null && groups != null)
> +                for (Object group : groups)
> +                    removeFetchGroup(group.toString());
>         } finally {
>             unlock();
>         }
> @@ -273,8 +298,11 @@
>     public FetchConfiguration clearFetchGroups() {
>         lock();
>         try {
> -            if (_state.fetchGroups != null)
> +            if (_state.fetchGroups != null) {
>                 _state.fetchGroups.clear();
> +                _state.fetchGroupContainsAll = false;
> +                _state.fetchGroupContainsDefault = true;
> +            }
>         } finally {
>             unlock();
>         }
> @@ -562,9 +590,9 @@
>      * Whether our configuration state includes the given field.
>      */
>     private boolean includes(FieldMetaData fmd) {
> -        if ((fmd.isInDefaultFetchGroup()
> -            && hasFetchGroup(FetchGroup.NAME_DEFAULT))
> -            || hasFetchGroup(FetchGroup.NAME_ALL)
> +        if (hasFetchGroupAll()
> +            || (fmd.isInDefaultFetchGroup()
> +            && hasFetchGroupDefault())
>             || hasField(fmd.getFullName(false)))
>             return true;
>         String[] fgs = fmd.getCustomFetchGroups();
>
> Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/ 
> apache/openjpa/kernel/TestQuerySQLCache.java
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestQuerySQLCache.java?rev=652913&view=auto
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/ 
> openjpa/kernel/TestQuerySQLCache.java (added)
> +++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/ 
> openjpa/kernel/TestQuerySQLCache.java Fri May  2 14:09:14 2008
> @@ -0,0 +1,391 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License.  You may obtain a copy of the License at
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied.  See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + */
> +package org.apache.openjpa.kernel;
> +
> +import java.util.HashMap;
> +import java.util.Iterator;
> +import java.util.Map;
> +import java.util.Set;
> +import java.util.concurrent.ConcurrentHashMap;
> +
> +import javax.persistence.EntityManager;
> +import javax.persistence.EntityManagerFactory;
> +import javax.persistence.Persistence;
> +
> +import junit.framework.TestCase;
> +
> +import org.apache.openjpa.jdbc.kernel.JDBCStoreManager;
> +import org.apache.openjpa.persistence.EntityManagerImpl;
> +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
> +import org.apache.openjpa.persistence.OpenJPAPersistence;
> +import org.apache.openjpa.persistence.simple.Person;
> +
> +/*
> + * Verify multiple permutations of openjpa.jdbc.QuerySQLCache  
> settings.
> + */
> +public class TestQuerySQLCache
> +    extends TestCase {
> +
> +    final int nThreads = 5;
> +    final int nPeople = 100;
> +    final int nIterations = 10;
> +
> +    /*
> +     * Verify QuerySQLCacheValue setting "all" is caching queries.
> +     */
> +    public void testAllCacheSetting() {
> +        Map props = new HashMap(System.getProperties());
> +        props.put("openjpa.MetaDataFactory", "jpa(Types="
> +            + Person.class.getName() + ")");
> +        props.put("openjpa.jdbc.QuerySQLCache", "all");
> +        OpenJPAEntityManagerFactorySPI emf =  
> (OpenJPAEntityManagerFactorySPI)
> +            OpenJPAPersistence.cast(
> +                Persistence.createEntityManagerFactory("test",  
> props));
> +
> +        EntityManagerImpl em =  
> (EntityManagerImpl)emf.createEntityManager();
> +        BrokerImpl broker = (BrokerImpl) em.getBroker();
> +        DelegatingStoreManager dstore = broker.getStoreManager();
> +        JDBCStoreManager jstore =
> +            (JDBCStoreManager)dstore.getInnermostDelegate();
> +
> +        em.getTransaction().begin();
> +        Person p = new Person();
> +        p.setId(1);
> +        em.persist(p);
> +        em.flush();
> +        em.getTransaction().commit();
> +
> +        Person p1 = em.find(Person.class, 1);
> +        Map sqlCache = jstore.getQuerySQLCache();
> +        Set keys = sqlCache.keySet();
> +        for (Iterator iter = keys.iterator(); iter.hasNext();) {
> +            Map cacheMap = (Map) iter.next();
> +            //make sure there is an entry in the cache
> +            assertEquals(1, cacheMap.size());
> +        }
> +
> +        em.getTransaction().begin();
> +        em.remove(p);
> +        em.flush();
> +        em.getTransaction().commit();
> +
> +        em.close();
> +        emf.close();
> +    }
> +
> +    /*
> +     * Verify QuerySQLCacheValue setting "true" uses the expected  
> cache
> +     * implementation and is caching.
> +     */
> +    public void testTrueCacheSetting() {
> +        Map props = new HashMap(System.getProperties());
> +        props.put("openjpa.MetaDataFactory", "jpa(Types="
> +            + Person.class.getName() + ")");
> +        props.put("openjpa.jdbc.QuerySQLCache", "true");
> +        OpenJPAEntityManagerFactorySPI emf =  
> (OpenJPAEntityManagerFactorySPI)
> +            OpenJPAPersistence.cast(
> +                Persistence.createEntityManagerFactory("test",  
> props));
> +
> +        EntityManagerImpl em =  
> (EntityManagerImpl)emf.createEntityManager();
> +        BrokerImpl broker = (BrokerImpl) em.getBroker();
> +        DelegatingStoreManager dstore = broker.getStoreManager();
> +        JDBCStoreManager jstore =
> +            (JDBCStoreManager)dstore.getInnermostDelegate();
> +
> +        em.getTransaction().begin();
> +        Person p = new Person();
> +        p.setId(1);
> +        em.persist(p);
> +        em.flush();
> +        em.getTransaction().commit();
> +
> +        Person p1 = em.find(Person.class, 1);
> +        Map sqlCache = jstore.getQuerySQLCache();
> +        Set keys = sqlCache.keySet();
> +        for (Iterator iter = keys.iterator(); iter.hasNext();) {
> +            Map cacheMap = (Map) iter.next();
> +            //make sure there is an entry in the cache
> +            assertEquals(1, cacheMap.size());
> +        }
> +
> +        em.getTransaction().begin();
> +        em.remove(p);
> +        em.flush();
> +        em.getTransaction().commit();
> +
> +        em.close();
> +        emf.close();
> +    }
> +
> +    /*
> +     * Verify caching is disabled when the QuerySQLCacheValue  
> setting is
> +     * "false".
> +     */
> +    public void testFalseCacheSetting() {
> +        Map props = new HashMap(System.getProperties());
> +        props.put("openjpa.MetaDataFactory", "jpa(Types="
> +            + Person.class.getName() + ")");
> +        props.put("openjpa.jdbc.QuerySQLCache", "false");
> +        OpenJPAEntityManagerFactorySPI emf =  
> (OpenJPAEntityManagerFactorySPI)
> +            OpenJPAPersistence.cast(
> +                Persistence.createEntityManagerFactory("test",  
> props));
> +
> +        EntityManagerImpl em =  
> (EntityManagerImpl)emf.createEntityManager();
> +        BrokerImpl broker = (BrokerImpl) em.getBroker();
> +        DelegatingStoreManager dstore = broker.getStoreManager();
> +        JDBCStoreManager jstore =
> +            (JDBCStoreManager)dstore.getInnermostDelegate();
> +
> +        em.getTransaction().begin();
> +        Person p = new Person();
> +        p.setId(1);
> +        em.persist(p);
> +        em.flush();
> +        em.getTransaction().commit();
> +
> +        Person p1 = em.find(Person.class, 1);
> +
> +        assertFalse(jstore.isQuerySQLCacheOn());
> +
> +        em.getTransaction().begin();
> +        em.remove(p);
> +        em.flush();
> +        em.getTransaction().commit();
> +
> +        em.close();
> +        emf.close();
> +    }
> +
> +    /*
> +     * Verify QuerySQLCacheValue setting with a custom cache  
> backend uses
> +     * the expected cache implementation and is caching.
> +     */
> +    public void testCustomCacheSetting() {
> +        Map props = new HashMap(System.getProperties());
> +        props.put("openjpa.MetaDataFactory", "jpa(Types="
> +            + Person.class.getName() + ")");
> +        props.put("openjpa.jdbc.QuerySQLCache",
> +             
> "org.apache.openjpa.kernel.TestQuerySQLCache.CustomCacheMap");
> +        OpenJPAEntityManagerFactorySPI emf =  
> (OpenJPAEntityManagerFactorySPI)
> +            OpenJPAPersistence.cast(
> +                Persistence.createEntityManagerFactory("test",  
> props));
> +
> +        EntityManagerImpl em =  
> (EntityManagerImpl)emf.createEntityManager();
> +        BrokerImpl broker = (BrokerImpl) em.getBroker();
> +        DelegatingStoreManager dstore = broker.getStoreManager();
> +        JDBCStoreManager jstore =
> +            (JDBCStoreManager)dstore.getInnermostDelegate();
> +
> +        em.getTransaction().begin();
> +        Person p = new Person();
> +        p.setId(1);
> +        em.persist(p);
> +        em.flush();
> +        em.getTransaction().commit();
> +
> +        Person p1 = em.find(Person.class, 1);
> +
> +        assertTrue(jstore.isQuerySQLCacheOn());
> +
> +        Map sqlCache = jstore.getQuerySQLCache();
> +        Set keys = sqlCache.keySet();
> +        for (Iterator iter = keys.iterator(); iter.hasNext();) {
> +            Map cacheMap = (Map) iter.next();
> +            assertTrue((cacheMap instanceof
> +                 
> org.apache.openjpa.kernel.TestQuerySQLCache.CustomCacheMap));
> +            //make sure there is an entry in the cache
> +            assertEquals(1, cacheMap.size());
> +        }
> +
> +        em.getTransaction().begin();
> +        em.remove(p);
> +        em.flush();
> +        em.getTransaction().commit();
> +
> +        em.close();
> +        emf.close();
> +    }
> +
> +    /*
> +     * Verify an exception is thrown if a bad cache implementation  
> class
> +     * is specified.
> +     */
> +    public void testBadCustomCacheSetting() {
> +        Map props = new HashMap(System.getProperties());
> +        props.put("openjpa.MetaDataFactory", "jpa(Types="
> +            + Person.class.getName() + ")");
> +        props.put("openjpa.jdbc.QuerySQLCache",
> +             
> "org.apache.openjpa.kernel.TestQuerySQLCache.BadCacheMap");
> +
> +        try {
> +            OpenJPAEntityManagerFactorySPI emf =
> +                 
> (OpenJPAEntityManagerFactorySPI)OpenJPAPersistence.cast(
> +                         
> Persistence.createEntityManagerFactory("test", props));
> +            // EMF creation should throw an exception because the  
> cache
> +            // implementation class will not be found.
> +            assertFalse(false);
> +        } catch (Exception e) {
> +            assertTrue(true);
> +        }
> +    }
> +
> +    /*
> +     * Verify multi-threaded multi-entity manager finder works with  
> the
> +     * QuerySQLCache set to "all".
> +     */
> +    public void testMultiEMCachingAll() {
> +        Map props = new HashMap(System.getProperties());
> +        props.put("openjpa.MetaDataFactory", "jpa(Types="
> +            + Person.class.getName() + ")");
> +        props.put("openjpa.jdbc.QuerySQLCache",
> +            "all");
> +        runMultiEMCaching(props);
> +    }
> +
> +    /*
> +     * Verify multi-threaded multi-entity manager finder works with  
> the
> +     * QuerySQLCache set to "true".
> +     */
> +    public void testMultiEMCachingTrue() {
> +        Map props = new HashMap(System.getProperties());
> +        props.put("openjpa.MetaDataFactory", "jpa(Types="
> +            + Person.class.getName() + ")");
> +        props.put("openjpa.jdbc.QuerySQLCache",
> +            "true");
> +        runMultiEMCaching(props);
> +    }
> +
> +    private void runMultiEMCaching(Map props) {
> +
> +        EntityManagerFactory emfac =
> +                Persistence.createEntityManagerFactory("test",  
> props);
> +
> +        EntityManager em = emfac.createEntityManager();
> +
> +        // Create some entities
> +        em.getTransaction().begin();
> +        for (int i = 0; i < nPeople; i++)
> +        {
> +            Person p = new Person();
> +            p.setId(i);
> +            em.persist(p);
> +        }
> +        em.flush();
> +        em.getTransaction().commit();
> +        em.close();
> +
> +        Thread[] newThreads = new Thread[nThreads];
> +        FindPeople[] customer = new FindPeople[nThreads];
> +
> +        for (int i=0; i < nThreads; i++) {
> +            customer[i] = new FindPeople(emfac, 0, nPeople,
> +                nIterations, i);
> +            newThreads[i] = new Thread(customer[i]);
> +            newThreads[i].start();
> +        }
> +
> +        // Wait for the worker threads to complete
> +        for (int i = 0; i < nThreads; i++) {
> +            try {
> +                newThreads[i].join();
> +            } catch (InterruptedException e) {
> +                this.fail("Caught Interrupted Exception: " + e);
> +            }
> +        }
> +
> +        // Run through the state of all runnables to assert if any  
> of them
> +        // failed.
> +        for (int i = 0; i < nThreads; i++) {
> +            assertFalse(customer[i].hadFailures());
> +        }
> +
> +        // Clean up the entities used in this test
> +        em = emfac.createEntityManager();
> +        em.getTransaction().begin();
> +
> +        for (int i = 0; i < nPeople; i++) {
> +            Person p = em.find(Person.class, i);
> +            em.remove(p);
> +        }
> +        em.flush();
> +        em.getTransaction().commit();
> +        em.close();
> +    }
> +
> +    /*
> +     * Empty ConcurrentHashMap subclass. Useful for testing custom  
> cache
> +     * storage implementations.
> +     */
> +    public class CustomCacheMap extends ConcurrentHashMap {
> +
> +    }
> +
> +    /*
> +     * Simple runnable to test finder in a tight loop.  Multiple  
> instances
> +     * of this runnable will run simultaneously.
> +     */
> +    private class FindPeople implements Runnable {
> +
> +        private int startId;
> +        private int endId;
> +        private int thread;
> +        private int iterations;
> +        private EntityManagerFactory emf;
> +        private boolean failures = false;
> +
> +        public FindPeople(EntityManagerFactory emf,
> +            int startId, int endId, int iterations, int thread) {
> +            super();
> +            this.startId = startId;
> +            this.endId = endId;
> +            this.thread = thread;
> +            this.iterations = iterations;
> +            this.emf = emf;
> +        }
> +
> +        public boolean hadFailures()
> +        {
> +            return failures;
> +        }
> +
> +        public void run() {
> +            try {
> +                EntityManager em = emf.createEntityManager();
> +                for (int j = 0; j < iterations; j++) {
> +
> +                    for (int i = startId; i < endId; i++) {
> +                        Person p1 = em.find(Person.class, i);
> +                        if (p1.getId() != i) {
> +                            System.out.println("Finder failed: " +  
> i);
> +                            failures = true;
> +                            break;
> +                        }
> +                    }
> +                    em.clear();
> +                }
> +                em.close();
> +            }
> +            catch (Exception e) {
> +               failures = true;
> +               System.out.println("Thread " + thread + "  
> exception :" +
> +                   e );
> +            }
> +        }
> +    }
> +}
>
> Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/ 
> apache/openjpa/kernel/TestQuerySQLCache.java
> ------------------------------------------------------------------------------
>    svn:eol-style = native
>
> Modified: openjpa/trunk/openjpa-project/src/doc/manual/ 
> ref_guide_caching.xml
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_caching.xml?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-project/src/doc/manual/ 
> ref_guide_caching.xml (original)
> +++ openjpa/trunk/openjpa-project/src/doc/manual/ 
> ref_guide_caching.xml Fri May  2 14:09:14 2008
> @@ -885,4 +885,85 @@
> 			</tgroup>
> 		</table>
> 	</section>
> +    <section id="ref_guide_cache_querysql">
> +        <title>
> +            Query SQL Cache
> +        </title>
> +        <indexterm zone="ref_guide_cache_querysql">
> +            <primary>
> +                caching
> +            </primary>
> +            <secondary>
> +                query sql cache
> +            </secondary>
> +        </indexterm>
> +        <para>
> +The query SQL cache is a <classname>Map</classname> used to cache
> +pushed-down SQL query strings for the find operation.  As a result,
> +the SQL queries are only generated once in OpenJPA, and cached  
> thereafter.
> +This query SQL cache is shared across entity managers and the fetch  
> plan
> +is part of the cache key. You can control the SQL cache through
> +the <link linkend="openjpa.jdbc.QuerySQLCache"><literal>
> +openjpa.jdbc.QuerySQLCache</literal></link> configuration  
> property.  This
> +property accepts a plugin string (see <xref  
> linkend="ref_guide_conf_plugins"/>)
> +describing the <classname>Map</classname> used to associate query  
> strings and
> +their parsed form.  This property accepts the following aliases:
> +        </para>
> +        <table>
> +            <title>
> +                Pre-defined aliases
> +            </title>
> +            <tgroup cols="2" align="left" colsep="1" rowsep="1">
> +                <colspec colname="alias"/>
> +                <colspec colname="value"/>
> +                <colspec colname="notes"/>
> +                <thead>
> +                    <row>
> +                        <entry colname="alias">Alias</entry>
> +                        <entry colname="value">Value</entry>
> +                        <entry colname="notes">Notes</entry>
> +                    </row>
> +                </thead>
> +                <tbody>
> +                    <row>
> +                        <entry colname="alias">
> +<literal>true</literal>
> +                        </entry>
> +                        <entry colname="value">
> +<literal>org.apache.openjpa.util.CacheMap</literal>
> +                        </entry>
> +                        <entry colname="notes">
> +The default option.  Uses a
> +<ulink url="../javadoc/org/apache/openjpa/util/CacheMap.html">
> +<literal>CacheMap</literal></ulink> to store sql string.
> +<literal>CacheMap</literal> maintains a fixed number of cache  
> entries, and an
> +optional soft reference map for entries that are moved out of the  
> LRU space.
> +So, for applications that have a monotonically increasing number of  
> distinct
> +queries, this option can be used to ensure that a fixed amount of  
> memory is
> +used by the cache.
> +                        </entry>
> +                    </row>
> +                    <row>
> +                        <entry colname="alias"><literal>all</ 
> literal></entry>
> +                        <entry colname="value">
> +<literal>org.apache.openjpa.lib.util.ConcurrentHashMap</literal>
> +                        </entry>
> +                        <entry colname="notes">
> +This is the fastest option, but sql string is never dropped from the
> +cache, so if you use a large number of dynamic queries, this option  
> may result
> +in ever-increasing memory usage. Note that if your queries only  
> differ in the
> +values of the parameters, this should not be an issue.
> +                        </entry>
> +                    </row>
> +                    <row>
> +                        <entry colname="alias"><literal>false</ 
> literal></entry>
> +                        <entry colname="value"><emphasis>none</ 
> emphasis></entry>
> +                        <entry colname="notes">
> +Disables the sql cache.
> +                        </entry>
> +                    </row>
> +                </tbody>
> +            </tgroup>
> +        </table>
> +    </section>
> </chapter>
>
> Modified: openjpa/trunk/openjpa-project/src/doc/manual/ 
> ref_guide_conf.xml
> URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml?rev=652913&r1=652912&r2=652913&view=diff
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml  
> (original)
> +++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml  
> Fri May  2 14:09:14 2008
> @@ -3328,6 +3328,42 @@
> classes. See <xref linkend="ref_guide_mapping_factory"/> for details.
>             </para>
>         </section>
> +        <section id="openjpa.jdbc.QuerySQLCache">
> +            <title>
> +                openjpa.jdbc.QuerySQLCache
> +            </title>
> +            <indexterm zone="openjpa.jdbc.QuerySQLCache">
> +                <primary>
> +                    QuerySQLCache
> +                </primary>
> +            </indexterm>
> +            <indexterm zone="openjpa.jdbc.QuerySQLCache">
> +                <primary>
> +                    caching
> +                </primary>
> +                <secondary>
> +                    QuerySQLCache
> +                </secondary>
> +            </indexterm>
> +            <para>
> +<emphasis role="bold">Property name:</emphasis>
> +<literal>openjpa.jdbc.QuerySQLCache</literal>
> +            </para>
> +            <para>
> +<emphasis role="bold">Resource adaptor config-property:</emphasis>
> +<literal>QuerySQLCache</literal>
> +            </para>
> +            <para>
> +<emphasis role="bold">Default:</emphasis> <literal>true</literal>.
> +            </para>
> +            <para>
> +<emphasis role="bold">Description:</emphasis> A plugin string (see
> +<xref linkend="ref_guide_conf_plugins"/>) describing the
> +<classname>java.util.Map</classname> to use for caching of the SQL  
> string
> +used by the find operation.  See <xref  
> linkend="ref_guide_cache_querysql"/> for
> +details.
> +            </para>
> +        </section>
>         <section id="openjpa.jdbc.ResultSetType">
>             <title>
>                 openjpa.jdbc.ResultSetType
>
>

-- 
Patrick Linskey
202 669 5907


Mime
View raw message