You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2004/02/06 14:01:53 UTC

cvs commit: db-ojb/src/java/org/apache/ojb/broker/util BrokerHelper.java

arminw      2004/02/06 05:01:53

  Modified:    src/java/org/apache/ojb/broker/accesslayer RsIterator.java
               src/java/org/apache/ojb/broker/core
                        PersistenceBrokerImpl.java
                        QueryReferenceBroker.java
               src/java/org/apache/ojb/broker/metadata/fieldaccess
                        AbstractPersistentField.java
                        PersistentFieldDirectAccessImpl.java
               src/java/org/apache/ojb/broker/util BrokerHelper.java
  Added:       src/java/org/apache/ojb/broker/accesslayer/sql
                        SqlExistStatement.java
               src/java/org/apache/ojb/broker/cache InternalCache.java
  Log:
  - introduce workaround for concurrency object materialization problem
  showed in ...broker.MultithreadedReadTest (thanks Sven Efftinge).
  When an object was materialzed we put it in an temporary storage (local map)
  till the object was full materialized. Then push it to the real ObjectCache
  (workaround, should be solved by two-level cache in 1.1)
  
  - introduce a new check in PB.store (thanks Guillaume Nodet). Check for PK fields represent
  a 'null' value, if true we know given object is new and needs insert
  (no other checks necessary in this case).
  
  - in PB.store method replace dbAccess.materializeObject(cld, oid) method call
  by !SqlHelper.doesExist(this, cld, oid). First method does materialize the full object
  if found in DB, latter avoids materialization of object and only requests first found PK
  column on select statement (instead of all object columns).
  (better solution in 1.1, we have to integrate this in JdbcAccess)
  
  - move method 'buildMessageString(Object obj, Object value, Field field)' form
  BrokerHelper to AbstractPersistentField
  
  Revision  Changes    Path
  1.1                  db-ojb/src/java/org/apache/ojb/broker/accesslayer/sql/SqlExistStatement.java
  
  Index: SqlExistStatement.java
  ===================================================================
  package org.apache.ojb.broker.accesslayer.sql;
  
  import org.apache.ojb.broker.OJBRuntimeException;
  import org.apache.ojb.broker.metadata.ClassDescriptor;
  import org.apache.ojb.broker.metadata.FieldDescriptor;
  import org.apache.ojb.broker.util.logging.Logger;
  
  /**
   * Generate a select to check existence of an object.
   * Something like "SELECT id_1 FROM myTable where id_1 = 123 and id_2 = 'kjngzt'".
   *
   * @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
   * @version $Id: SqlExistStatement.java,v 1.1 2004/02/06 13:01:52 arminw Exp $
   */
  public class SqlExistStatement extends SqlPkStatement
  {
      private static final String SELECT = "SELECT ";
      private static final String FROM = " FROM ";
  
      public SqlExistStatement(ClassDescriptor aCld, Logger aLogger)
      {
          super(aCld, aLogger);
      }
  
      /**
       * Return SELECT clause for object existence call
       */
      public String getStatement()
      {
          StringBuffer stmt = new StringBuffer(128);
          ClassDescriptor cld = getClassDescriptor();
  
          FieldDescriptor[] fieldDescriptors = cld.getPkFields();
          if (fieldDescriptors == null || fieldDescriptors.length == 0)
          {
              throw new OJBRuntimeException("No PK fields defined in metadata for " + cld.getClassNameOfObject());
          }
          FieldDescriptor field = fieldDescriptors[0];
  
          stmt.append(SELECT);
          stmt.append(field.getColumnName());
          stmt.append(FROM);
          stmt.append(cld.getFullTableName());
          appendWhereClause(cld, false, stmt);
          return stmt.toString();
      }
  }
  
  
  
  1.57      +13 -11    db-ojb/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java
  
  Index: RsIterator.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java,v
  retrieving revision 1.56
  retrieving revision 1.57
  diff -u -r1.56 -r1.57
  --- RsIterator.java	20 Dec 2003 12:35:40 -0000	1.56
  +++ RsIterator.java	6 Feb 2004 13:01:52 -0000	1.57
  @@ -43,6 +43,7 @@
    * Apache Software Foundation, please see <http://www.apache.org/> .
    */
   
  +import java.lang.ref.WeakReference;
   import java.sql.ResultSet;
   import java.sql.SQLException;
   import java.util.Collection;
  @@ -51,16 +52,15 @@
   import java.util.Map;
   import java.util.NoSuchElementException;
   import java.util.Vector;
  -import java.lang.ref.WeakReference;
   
   import org.apache.ojb.broker.Identity;
  +import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.PBLifeCycleEvent;
  +import org.apache.ojb.broker.PBStateEvent;
  +import org.apache.ojb.broker.PBStateListener;
   import org.apache.ojb.broker.PersistenceBrokerException;
   import org.apache.ojb.broker.VirtualProxy;
  -import org.apache.ojb.broker.PBStateListener;
  -import org.apache.ojb.broker.PBStateEvent;
  -import org.apache.ojb.broker.OJBRuntimeException;
  -import org.apache.ojb.broker.cache.ObjectCache;
  +import org.apache.ojb.broker.cache.InternalCache;
   import org.apache.ojb.broker.core.PersistenceBrokerImpl;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.DescriptorRepository;
  @@ -98,7 +98,7 @@
    * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird <a>- added the
    *         support for extents mapped to single table - added the .size
    *         functionality - added cursor control
  - * 
  + *
    * @version $Id$
    */
   public class RsIterator implements OJBIterator
  @@ -113,7 +113,7 @@
   	 */
       private PBLifeCycleEvent afterLookupEvent;
   
  -    private ObjectCache m_cache;
  +    private InternalCache m_cache;
   
       /**
        * reference to the PersistenceBroker
  @@ -184,7 +184,7 @@
        */
       public RsIterator(RsQueryObject queryObject, final PersistenceBrokerImpl broker)
       {
  -        setCache(broker.serviceObjectCache());
  +        setCache(broker.getInternalCache());
           setRow(new HashMap());
           setBroker(broker);
           setQueryObject(queryObject);
  @@ -480,6 +480,7 @@
   					 */
                       synchronized (result)
                       {
  +                        getCache().enableMaterializationCache();
                           getCache().cache(oid, result);
                           /*
   						 * arminw: move LoadedObjectsRegistry to odmg-layer
  @@ -499,6 +500,7 @@
                           // Maps ReferenceDescriptors to HashSets of owners
                           getBroker().getReferenceBroker().retrieveReferences(result, cld, unforced);
                           getBroker().getReferenceBroker().retrieveCollections(result, cld, unforced);
  +                        getCache().disableMaterializationCache();
                       }
                   }
               }
  @@ -938,12 +940,12 @@
           return m_row;
       }
   
  -    protected void setCache(ObjectCache cache)
  +    protected void setCache(InternalCache cache)
       {
           this.m_cache = cache;
       }
   
  -    protected ObjectCache getCache()
  +    protected InternalCache getCache()
       {
           return m_cache;
       }
  
  
  
  1.1                  db-ojb/src/java/org/apache/ojb/broker/cache/InternalCache.java
  
  Index: InternalCache.java
  ===================================================================
  package org.apache.ojb.broker.cache;
  
  import java.util.HashMap;
  import java.util.Iterator;
  
  import org.apache.ojb.broker.Identity;
  import org.apache.ojb.broker.util.logging.LoggerFactory;
  import org.apache.ojb.broker.util.logging.Logger;
  
  /**
   * A wrapper class for {@link ObjectCache} implementation. This class is used as a
   * workaround for a concurrency materialization problem with shared cache implementations.
   * To avoid passing of partial materialized objects to cache this class act as a
   * temporary storage for unmaterialized (read) objects.
   * <br/>
   * TODO: Will be replaced on cache refactoring 
   *
   * @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
   * @version $Id: InternalCache.java,v 1.1 2004/02/06 13:01:52 arminw Exp $
   */
  public class InternalCache implements ObjectCache
  {
      private static Logger log = LoggerFactory.getLogger(InternalCache.class);
  
      private ObjectCache realCache;
      private HashMap localCache;
      private boolean enabledReadCache;
  
      public InternalCache(ObjectCache realCache)
      {
          this.realCache = realCache;
          this.localCache = new HashMap();
          enabledReadCache = false;
      }
  
      public void enableMaterializationCache()
      {
          enabledReadCache = true;
      }
  
      public void disableMaterializationCache()
      {
          enabledReadCache = false;
          pushToRealCache();
      }
  
      private void pushToRealCache()
      {
          Iterator it = localCache.keySet().iterator();
          Identity oid;
          while (it.hasNext())
          {
              oid = (Identity) it.next();
              realCache.cache(oid, localCache.get(oid));
          }
          localCache.clear();
      }
  
      public void cache(Identity oid, Object obj)
      {
          if(enabledReadCache)
          {
              localCache.put(oid, obj);
          }
          else
          {
              realCache.cache(oid, obj);
          }
      }
  
      public Object lookup(Identity oid)
      {
          Object result = null;
          if(enabledReadCache)
          {
              result = localCache.get(oid);
          }
          if(result == null)
          {
              result = realCache.lookup(oid);
          }
          return result;
      }
  
      public void remove(Identity oid)
      {
          if(enabledReadCache && !localCache.isEmpty())
          {
              localCache.remove(oid);
          }
          realCache.remove(oid);
      }
  
      public void localClear()
      {
          if(localCache.size() > 0)
          {
              log.error("Found " + localCache.size() + " abandoned objects in local cache, check code to force" +
                      " push to real ObjectCache");
          }
          localCache.clear();
      }
  
      public void clear()
      {
          localCache.clear();
          realCache.clear();
      }
  }
  
  
  
  1.65      +39 -13    db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java
  
  Index: PersistenceBrokerImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java,v
  retrieving revision 1.64
  retrieving revision 1.65
  diff -u -r1.64 -r1.65
  --- PersistenceBrokerImpl.java	28 Jan 2004 23:49:32 -0000	1.64
  +++ PersistenceBrokerImpl.java	6 Feb 2004 13:01:52 -0000	1.65
  @@ -85,6 +85,7 @@
   import org.apache.ojb.broker.accesslayer.StatementManagerIF;
   import org.apache.ojb.broker.accesslayer.sql.SqlGenerator;
   import org.apache.ojb.broker.accesslayer.sql.SqlGeneratorFactory;
  +import org.apache.ojb.broker.cache.InternalCache;
   import org.apache.ojb.broker.cache.ObjectCache;
   import org.apache.ojb.broker.cache.ObjectCacheFactory;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
  @@ -142,7 +143,7 @@
        * Any later lookups with the same pk values will return the cached object
        * instead of performing another db lookup.
        */
  -    private ObjectCache objectCache;
  +    private InternalCache objectCache;
       /**
        * m_DbAccess is used to do all Jdbc related work: connecting, executing...
        */
  @@ -189,7 +190,13 @@
           */
           brokerHelper = new BrokerHelper(this);
           connectionManager = ConnectionManagerFactory.getInstance().createConnectionManager(this);
  -        objectCache = ObjectCacheFactory.getInstance().createObjectCache(this);
  +        /*
  +        TODO: find better solution
  +        InternalCache is a interim solution help to solve the problem of not full
  +        materialized object reads by concurrent threads and will be replaced when
  +        the new real two-level cache was introduced
  +        */
  +        objectCache = new InternalCache(ObjectCacheFactory.getInstance().createObjectCache(this));
           sequenceManager = SequenceManagerFactory.getSequenceManager(this);
           dbAccess = JdbcAccessFactory.getInstance().createJdbcAccess(this);
           statementManager = StatementManagerFactory.getInstance().createStatementManager(this);
  @@ -199,6 +206,11 @@
           referencesBroker = new QueryReferenceBroker(this);
       }
   
  +    public InternalCache getInternalCache()
  +    {
  +        return objectCache;
  +    }
  +
       public SqlGenerator serviceSqlGenerator()
       {
           return this.sqlGenerator;
  @@ -659,16 +671,22 @@
               }
   
               ClassDescriptor cld = getClassDescriptor(obj.getClass());
  +            /*
  +            if one of the PK fields was null, the objects was new
  +            and needs insert
  +            */
  +            boolean doInsert = serviceBrokerHelper().hasNullPKField(cld, obj);
               Identity oid = new Identity(obj, this, cld);
  -            // check if update or insert is needed
  -            boolean doInsert = false;
  -            // lookup cache or db to see whether object needs insert or update
  -            if (objectCache.lookup(oid) == null
  -                    && dbAccess.materializeObject(cld, oid) == null)
  +            /*
  +            if PK values are set, lookup cache or db to see whether object
  +            needs insert or update
  +            */
  +            if (!doInsert)
               {
  -                doInsert = true;
  -                // now store it:
  +                doInsert = objectCache.lookup(oid) == null
  +                    && !serviceBrokerHelper().doesExist(cld, oid, obj);
               }
  +            // now store it:
               store(obj, oid, cld, doInsert);
   
               // let the connection manager to execute batch
  @@ -1063,7 +1081,6 @@
               {
                   // cache object immediately , so that references
                   // can be established from referenced Objects back to this Object
  -
                   objectCache.cache(oid, newObj);
   
                   /*
  @@ -1126,14 +1143,22 @@
           return result;
       }
   
  +    public Object getObjectByIdentity(Identity id) throws PersistenceBrokerException
  +    {
  +        objectCache.enableMaterializationCache();
  +        Object result = doGetObjectByIdentity(id);
  +        objectCache.disableMaterializationCache();
  +        return result;
  +    }
  +
       /**
  -     * Reterieve an object by it's identity
  +     * Internal used method to retrieve object based on Identity.
        *
        * @param id
        * @return
        * @throws PersistenceBrokerException
        */
  -    public Object getObjectByIdentity(Identity id) throws PersistenceBrokerException
  +    public Object doGetObjectByIdentity(Identity id) throws PersistenceBrokerException
       {
           if (logger.isDebugEnabled()) logger.debug("getObjectByIdentity " + id);
   
  @@ -1692,6 +1717,7 @@
       private void clearRegistrationLists()
       {
           nowStoring.clear();
  +        objectCache.localClear();
       }
   
       /**
  
  
  
  1.9       +3 -3      db-ojb/src/java/org/apache/ojb/broker/core/QueryReferenceBroker.java
  
  Index: QueryReferenceBroker.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/QueryReferenceBroker.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- QueryReferenceBroker.java	18 Jan 2004 14:36:11 -0000	1.8
  +++ QueryReferenceBroker.java	6 Feb 2004 13:01:52 -0000	1.9
  @@ -345,7 +345,7 @@
               } //JMM : why not see if the object has already been loaded
               else if ( pb.serviceObjectCache().lookup(id) != null )
               {
  -                refObj = pb.getObjectByIdentity(id);
  +                refObj = pb.doGetObjectByIdentity(id);
               }
               else if ((m_retrievalTasks != null) && !rds.isLazy()
                       && (rds.getItemProxyClass() == null))
  @@ -475,7 +475,7 @@
           }
           else
           {
  -            return pb.getObjectByIdentity(id);
  +            return pb.doGetObjectByIdentity(id);
           }
       }
   
  
  
  
  1.13      +20 -1     db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/AbstractPersistentField.java
  
  Index: AbstractPersistentField.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/AbstractPersistentField.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- AbstractPersistentField.java	28 Jan 2004 20:04:50 -0000	1.12
  +++ AbstractPersistentField.java	6 Feb 2004 13:01:52 -0000	1.13
  @@ -58,6 +58,7 @@
   import org.apache.ojb.broker.util.ProxyHelper;
   import org.apache.ojb.broker.util.logging.Logger;
   import org.apache.ojb.broker.util.logging.LoggerFactory;
  +import org.apache.commons.lang.SystemUtils;
   
   import java.lang.reflect.Field;
   
  @@ -404,4 +405,22 @@
       {
           return getField().getDeclaringClass();
       }
  +
  +    /**
  +     * Build a String representation of given arguments.
  +     */
  +	public String buildMessageString(Object obj, Object value, Field field)
  +	{
  +		String eol = SystemUtils.LINE_SEPARATOR;
  +		StringBuffer buf = new StringBuffer();
  +		buf
  +			.append(eol + "[try to set 'object value' in 'target object'")
  +            .append(eol + "target obj class: " + (obj != null ? obj.getClass().getName() : null))
  +			.append(eol + "target field name: " + field != null ? field.getName() : null)
  +			.append(eol + "target field type: " + (field != null ? field.getType() : null))
  +			.append(eol + "object value class: " + (value != null ? value.getClass().getName() : null))
  +			.append(eol + "object value: " + (value != null ? value : null))
  +			.append(eol + "]");
  +		return buf.toString();
  +	}
   }
  
  
  
  1.8       +3 -3      db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldDirectAccessImpl.java
  
  Index: PersistentFieldDirectAccessImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldDirectAccessImpl.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- PersistentFieldDirectAccessImpl.java	7 Jan 2004 19:11:10 -0000	1.7
  +++ PersistentFieldDirectAccessImpl.java	6 Feb 2004 13:01:52 -0000	1.8
  @@ -118,13 +118,13 @@
           }
           catch (IllegalAccessException e)
           {
  -            getLog().error("while set field: " + BrokerHelper.buildMessageString(obj, value, fld));
  +            getLog().error("while set field: " + buildMessageString(obj, value, fld));
               throw new MetadataException("IllegalAccess error setting field:" +
                       (fld != null ? fld.getName() : null) + " in object:" + obj.getClass().getName(), e);
           }
           catch (Exception e)
           {
  -            getLog().error("while set field: " + BrokerHelper.buildMessageString(obj, value, fld), e);
  +            getLog().error("while set field: " + buildMessageString(obj, value, fld), e);
               throw new MetadataException("Error setting field:" + (fld != null ? fld.getName() : null) +
                       " in object:" + obj.getClass().getName(), e);
           }
  
  
  
  1.35      +147 -99   db-ojb/src/java/org/apache/ojb/broker/util/BrokerHelper.java
  
  Index: BrokerHelper.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/BrokerHelper.java,v
  retrieving revision 1.34
  retrieving revision 1.35
  diff -u -r1.34 -r1.35
  --- BrokerHelper.java	29 Jan 2004 00:01:48 -0000	1.34
  +++ BrokerHelper.java	6 Feb 2004 13:01:53 -0000	1.35
  @@ -54,15 +54,16 @@
    * <http://www.apache.org/>.
    */
   
  -import java.lang.reflect.Field;
   import java.util.StringTokenizer;
  +import java.util.Map;
  +import java.util.WeakHashMap;
   
  -import org.apache.commons.lang.SystemUtils;
   import org.apache.ojb.broker.Identity;
   import org.apache.ojb.broker.PBKey;
   import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.PersistenceBrokerException;
   import org.apache.ojb.broker.VirtualProxy;
  +import org.apache.ojb.broker.PersistenceBrokerSQLException;
   import org.apache.ojb.broker.query.Query;
   import org.apache.ojb.broker.query.QueryBySQL;
   import org.apache.ojb.broker.query.QueryByCriteria;
  @@ -72,14 +73,20 @@
   import org.apache.ojb.broker.query.ReportQueryByMtoNCriteria;
   import org.apache.ojb.broker.core.ValueContainer;
   import org.apache.ojb.broker.accesslayer.IndirectionHandler;
  +import org.apache.ojb.broker.accesslayer.StatementManagerIF;
  +import org.apache.ojb.broker.accesslayer.sql.SqlExistStatement;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.FieldDescriptor;
   import org.apache.ojb.broker.metadata.MetadataException;
   import org.apache.ojb.broker.metadata.MetadataManager;
   import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
   import org.apache.ojb.broker.util.sequence.SequenceManagerException;
  +import org.apache.ojb.broker.util.logging.LoggerFactory;
   //#ifdef JDK13
   import java.lang.reflect.Proxy;
  +import java.sql.PreparedStatement;
  +import java.sql.ResultSet;
  +import java.sql.SQLException;
   //#else
   /*
   import com.develop.java.lang.reflect.Proxy;
  @@ -285,7 +292,7 @@
        * - If given value is instance of String with length 0 and the field-descriptor
        * is a primary key, true will be returned<br/>
        */
  -    public static boolean representsNull(FieldDescriptor fld, Object aValue)
  +    public boolean representsNull(FieldDescriptor fld, Object aValue)
       {
           if(aValue == null) return true;
   
  @@ -301,6 +308,23 @@
           return result;
       }
   
  +    /**
  +     * Detect if the given object has a PK field represents a 'null' value.
  +     */
  +    public boolean hasNullPKField(ClassDescriptor cld, Object obj)
  +    {
  +        FieldDescriptor[] fields = cld.getPkFields();
  +        boolean hasNull = false;
  +        FieldDescriptor fld;
  +        for (int i = 0; i < fields.length; i++)
  +        {
  +            fld = fields[i];
  +            hasNull = representsNull(fld, fld.getPersistentField().get(obj));
  +            if(hasNull) break;
  +        }
  +        return hasNull;
  +    }
  +
   	/**
   	 * Get an autoincremented value that has already
   	 * had a field conversion run on it.
  @@ -471,120 +495,144 @@
       }
   
       /**
  -         * Build a Count-Query based on aQuery
  -         * @param aQuery
  -         * @return
  -         */
  -        public Query getCountQuery(Query aQuery)
  +     * Build a Count-Query based on aQuery
  +     * @param aQuery
  +     * @return
  +     */
  +    public Query getCountQuery(Query aQuery)
  +    {
  +        if (aQuery instanceof QueryBySQL)
           {
  -            if (aQuery instanceof QueryBySQL)
  -            {
  -                return getCountQuery((QueryBySQL)aQuery);
  -            }
  -            else
  -            {
  -                return getCountQuery((QueryByCriteria)aQuery);
  -            }
  +            return getCountQuery((QueryBySQL)aQuery);
           }
  -
  -        /**
  -         * Create a Count-Query for QueryBySQL
  -         * @param aQuery
  -         * @return
  -         */
  -        private Query getCountQuery(QueryBySQL aQuery)
  +        else
           {
  -            String countSql = aQuery.getSql();
  +            return getCountQuery((QueryByCriteria)aQuery);
  +        }
  +    }
   
  -            int fromPos = countSql.toUpperCase().indexOf(" FROM ");
  -            if (fromPos >= 0)
  -            {
  -                countSql = "select count(*)" + countSql.substring(fromPos);
  -            }
  +    /**
  +     * Create a Count-Query for QueryBySQL
  +     * @param aQuery
  +     * @return
  +     */
  +    private Query getCountQuery(QueryBySQL aQuery)
  +    {
  +        String countSql = aQuery.getSql();
   
  -            int orderPos = countSql.toUpperCase().indexOf(" ORDER BY ");
  -            if (orderPos >= 0)
  -            {
  -                countSql = countSql.substring(0, orderPos);
  -            }
  +        int fromPos = countSql.toUpperCase().indexOf(" FROM ");
  +        if (fromPos >= 0)
  +        {
  +            countSql = "select count(*)" + countSql.substring(fromPos);
  +        }
   
  -            return new QueryBySQL(aQuery.getSearchClass(), countSql);
  +        int orderPos = countSql.toUpperCase().indexOf(" ORDER BY ");
  +        if (orderPos >= 0)
  +        {
  +            countSql = countSql.substring(0, orderPos);
           }
   
  +        return new QueryBySQL(aQuery.getSearchClass(), countSql);
  +    }
  +
   
  -        /**
  -         * Create a Count-Query for QueryByCriteria
  -         * @param aQuery
  -         * @return
  -         */
  -        private Query getCountQuery(QueryByCriteria aQuery)
  +    /**
  +     * Create a Count-Query for QueryByCriteria
  +     * @param aQuery
  +     * @return
  +     */
  +    private Query getCountQuery(QueryByCriteria aQuery)
  +    {
  +        Class searchClass = aQuery.getSearchClass();
  +        ReportQueryByCriteria countQuery;
  +        Criteria countCrit = null;
  +        String[] columns;
  +
  +        // build a ReportQuery based on query orderby needs to be cleared
  +        if (aQuery.getCriteria() != null)
           {
  -            Class searchClass = aQuery.getSearchClass();
  -            ReportQueryByCriteria countQuery;
  -            Criteria countCrit = null;
  -            String[] columns;
  +            countCrit = aQuery.getCriteria().copy(false, false, false);
  +        }
   
  -            // build a ReportQuery based on query orderby needs to be cleared
  -            if (aQuery.getCriteria() != null)
  -            {
  -                countCrit = aQuery.getCriteria().copy(false, false, false);
  -            }
  +        if (aQuery.isDistinct())
  +        {
  +            //
  +            // BRJ: Count distinct is dbms dependent
  +            // hsql/sapdb: select count (distinct(person_id || project_id)) from person_project
  +            // mysql: select count (distinct person_id,project_id)  from person_project
  +            //
  +            FieldDescriptor[] pkFields = m_broker.getClassDescriptor(searchClass).getPkFields();
  +            columns = new String[pkFields.length];
   
  -            if (aQuery.isDistinct())
  +            for (int i = 0; i < pkFields.length; i++)
               {
  -                //
  -                // BRJ: Count distinct is dbms dependent
  -                // hsql/sapdb: select count (distinct(person_id || project_id)) from person_project
  -                // mysql: select count (distinct person_id,project_id)  from person_project
  -                //
  -                FieldDescriptor[] pkFields = m_broker.getClassDescriptor(searchClass).getPkFields();
  -                columns = new String[pkFields.length];
  -
  -                for (int i = 0; i < pkFields.length; i++)
  -                {
  -                    columns[i] = "count(distinct " + pkFields[i].getAttributeName() + ")";
  -                }
  +                columns[i] = "count(distinct " + pkFields[i].getAttributeName() + ")";
               }
  -            else
  -            {
  -                // BRJ: use count(*) if query not distinct
  -                columns = new String[1];
  -                columns[0] = "count(*)";
  -            }
  -
  +        }
  +        else
  +        {
  +            // BRJ: use count(*) if query not distinct
  +            columns = new String[1];
  +            columns[0] = "count(*)";
  +        }
   
  -            // BRJ: we have to preserve indirection table !
  -            if (aQuery instanceof MtoNQuery)
  -            {
  -                MtoNQuery mnQuery = (MtoNQuery)aQuery;
  -                ReportQueryByMtoNCriteria mnReportQuery = new ReportQueryByMtoNCriteria(searchClass, columns, countCrit);
  -                mnReportQuery.setIndirectionTable(mnQuery.getIndirectionTable());
   
  -                countQuery = mnReportQuery;
  -            }
  -            else
  -            {
  -                countQuery = new ReportQueryByCriteria(searchClass, columns, countCrit);
  -            }
  +        // BRJ: we have to preserve indirection table !
  +        if (aQuery instanceof MtoNQuery)
  +        {
  +            MtoNQuery mnQuery = (MtoNQuery)aQuery;
  +            ReportQueryByMtoNCriteria mnReportQuery = new ReportQueryByMtoNCriteria(searchClass, columns, countCrit);
  +            mnReportQuery.setIndirectionTable(mnQuery.getIndirectionTable());
   
  -            return countQuery;
  +            countQuery = mnReportQuery;
           }
  +        else
  +        {
  +            countQuery = new ReportQueryByCriteria(searchClass, columns, countCrit);
  +        }
  +
  +        return countQuery;
  +    }
  +
   
       /*
  -     * TODO: Only used by PersistentField implementation, so move to fieldaccess package?
  +    NOTE: use WeakHashMap to allow reclaiming of no longer used ClassDescriptor
  +    instances
  +    */
  +    private Map sqlSelectMap = new WeakHashMap();
  +    /**
  +     * TODO: This method should be moved to {@link org.apache.ojb.broker.accesslayer.JdbcAccess}
  +     * before 1.1 release. This method only checks if the requested object can be
  +     * found in DB (without full object materialization).
        */
  -	public static String buildMessageString(Object obj, Object value, Field field)
  -	{
  -		String eol = SystemUtils.LINE_SEPARATOR;
  -		StringBuffer buf = new StringBuffer();
  -		buf
  -			.append(eol + "[try to set 'object value' in 'target object'")
  -            .append(eol + "target obj class: " + (obj != null ? obj.getClass().getName() : null))
  -			.append(eol + "target field name: " + field != null ? field.getName() : null)
  -			.append(eol + "target field type: " + (field != null ? field.getType() : null))
  -			.append(eol + "object value class: " + (value != null ? value.getClass().getName() : null))
  -			.append(eol + "object value: " + (value != null ? value : null))
  -			.append(eol + "]");
  -		return buf.toString();
  -	}
  +    public boolean doesExist(ClassDescriptor cld, Identity oid, Object obj)
  +    {
  +        boolean result = false;
  +        String sql = (String) sqlSelectMap.get(cld);
  +        if(sql == null)
  +        {
  +            sql = new SqlExistStatement(cld, LoggerFactory.getDefaultLogger()).getStatement();
  +            sqlSelectMap.put(cld, sql);
  +        }
  +        StatementManagerIF sm = m_broker.serviceStatementManager();
  +        PreparedStatement stmt = null;
  +        ResultSet rs = null;
  +        try
  +        {
  +            stmt = sm.getPreparedStatement(cld, sql, false);
  +            sm.bindSelect(stmt, oid, cld);
  +            rs = stmt.executeQuery();
  +            result = rs.next();
  +        }
  +        catch (SQLException e)
  +        {
  +            throw new PersistenceBrokerSQLException("", e);
  +        }
  +        finally
  +        {
  +            sm.closeResources(stmt, rs);
  +        }
  +
  +        return result;
  +    }
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org