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 2007/03/02 02:33:47 UTC

svn commit: r513577 [1/3] - in /db/ojb/trunk/src: java/org/apache/ojb/broker/ java/org/apache/ojb/broker/accesslayer/ java/org/apache/ojb/broker/accesslayer/sql/ java/org/apache/ojb/broker/core/ java/org/apache/ojb/broker/metadata/ java/org/apache/ojb/...

Author: arminw
Date: Thu Mar  1 17:33:44 2007
New Revision: 513577

URL: http://svn.apache.org/viewvc?view=rev&rev=513577
Log:
merge trunk with 1.0.x branch

Added:
    db/ojb/trunk/src/test/org/apache/ojb/broker/PaginationTest.java
    db/ojb/trunk/src/test/org/apache/ojb/repository_junit_pagination.xml
Modified:
    db/ojb/trunk/src/java/org/apache/ojb/broker/PersistenceBroker.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/ChainingIterator.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/OJBIterator.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/PagingIterator.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/JdbcConnectionDescriptor.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/Platform.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDb2Impl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDefaultImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformFirebirdImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformHsqldbImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMckoiImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMsSQLServerImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMySQLImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformOracleImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformPostgreSQLImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformSapdbImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/query/AbstractQueryImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/query/Query.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/query/QueryByCriteria.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/query/QueryByCriteriaImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/query/QueryByExampleImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/query/ReportQueryByCriteriaImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/BrokerHelper.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/ExceptionHelper.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/AbstractSequenceManager.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/PerFieldManager.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManager.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerHighLowImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerIdentityImpl.java
    db/ojb/trunk/src/samples/org/apache/ojb/tutorials/PBExample.java
    db/ojb/trunk/src/schema/ojbtest-schema.xml
    db/ojb/trunk/src/test/org/apache/ojb/broker/AbstractArticle.java
    db/ojb/trunk/src/test/org/apache/ojb/broker/AllTests.java
    db/ojb/trunk/src/test/org/apache/ojb/broker/PersistenceBrokerTest.java
    db/ojb/trunk/src/test/org/apache/ojb/broker/sequence/DatabaseIdentityHsqlTest.java
    db/ojb/trunk/src/test/org/apache/ojb/broker/sequence/DatabaseIdentityMaxDBTest.java
    db/ojb/trunk/src/test/org/apache/ojb/broker/sequence/DatabaseIdentityMySqlTest.java
    db/ojb/trunk/src/test/org/apache/ojb/broker/sequence/DatabaseIdentityTest.java
    db/ojb/trunk/src/test/org/apache/ojb/odmg/DListTest.java
    db/ojb/trunk/src/test/org/apache/ojb/odmg/ObjectImageTest.java
    db/ojb/trunk/src/test/org/apache/ojb/repository.xml
    db/ojb/trunk/src/test/org/apache/ojb/repository_database.xml
    db/ojb/trunk/src/test/org/apache/ojb/repository_junit_meta_seq.xml

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/PersistenceBroker.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/PersistenceBroker.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/PersistenceBroker.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/PersistenceBroker.java Thu Mar  1 17:33:44 2007
@@ -37,11 +37,7 @@
  * PersistenceBroker declares a protocol for persisting arbitrary objects.
  * A typical implementation might wrap an RDBMS access layer.
  *
- * @see org.apache.ojb.broker.core.PersistenceBrokerImpl
- *
- * @author <a href="mailto:thomas.mahler@itellium.com">Thomas Mahler<a>
  * @version $Id$
- *
  */
 public interface PersistenceBroker extends ObjectContainer
 {
@@ -116,6 +112,7 @@
 
     /**
      * Return the {@link IdentityFactory} instance associated with this broker.
+     *
      * @return service to create {@link Identity} objects.
      */
     public IdentityFactory serviceIdentity();
@@ -147,7 +144,7 @@
     public void fireBrokerEvent(PBStateEvent event);
 
     /**
-     * Removes all temporary listeners from this PersistenceBroker instance
+     * Removes all temporary listeners from this broker.
      * <b>NOTE:</b> Use with care, because some internals rely on this mechanism.
      *
      * @see #removeListener(PBListener)
@@ -155,15 +152,12 @@
     public void removeAllListeners() throws PersistenceBrokerException;
 
     /**
-     * If parameter <code>permanet</code> was <code>true</code> all permanent and temporary listeners
-     * will be removed from this PersistenceBroker instance.
-     * <br/>
+     * Removes all temporary and, if desired, permanent listeners from this broker.
      * <b>NOTE:</b> Use with care, because some internals rely on this mechanism.
      *
      * @param permanent If <em>false</em> all temporary listener will be removed. If
      * <em>true</em> temporaray and permanent listern will be removed from this instance.
      * @see #removeListener(PBListener)
-     * @see #removeListener(PBListener listener)
      */
     public void removeAllListeners(boolean permanent) throws PersistenceBrokerException;
 
@@ -174,23 +168,21 @@
      * it to the pool).
      *
      * @param listener The listener to add
-     * @see #addListener(org.apache.ojb.broker.PBListener listener, boolean permanent)
+     * @see #addListener(PBListener, boolean)
      */
     public void addListener(PBListener listener) throws PersistenceBrokerException;
 
     /**
-     * Adds a permanent {@link org.apache.ojb.broker.PBListener}
-     * to this PersistenceBroker instance if parameter <code>permanent</code>
-     * was <code>true</code>. This means the listener will be
-     * hold the whole life time of the broker.
+     * Adds a temporary or permanent {@link org.apache.ojb.broker.PBListener} to this broker,
+     * depending on the parameter value. Note that temporary listeners will be removed upon
+     * closing a broker (returning it to the pool).
      * <br/>
      * <b>NOTE:</b> Handle carefully when using this method, keep in mind you don't
-     * know which instance was returned next time from the pool, with a permanent
-     * listener or without! To garantee that any pooled broker instance use the permanent
-     * listener, best way is to implement your own
+     * know which broker instance will be returned next time from the pool! To guarantee that
+     * a listener is connect to every broker, the best way is to define your own implementation of
      * {@link org.apache.ojb.broker.core.PersistenceBrokerFactoryIF} or extend the default
-     * implementation {@link org.apache.ojb.broker.core.PersistenceBrokerFactoryDefaultImpl}
-     * and add the listener at creation of the {@link org.apache.ojb.broker.PersistenceBroker}
+     * one, {@link org.apache.ojb.broker.core.PersistenceBrokerFactoryDefaultImpl}. There you
+     * can add the listener at creation of the {@link org.apache.ojb.broker.PersistenceBroker}
      * instances.
      *
      * @param listener  The listener to add
@@ -343,7 +335,18 @@
     /**
      * Makes the given object persistent in the underlying persistence system.
      * This is usually done by issuing an INSERT ... or UPDATE ...  in an RDBMS.
-     * The ObjectModification parameter can be used to generate optimized SQL code
+     *
+     * @param obj The object to store
+     * @param modification Specifies what operation to perform (for generating optimized SQL)
+     * @param ignoreReferences If set <em>true</em> OJB will ignore all referenced objects
+     * and only insert/update the fields of the object.
+     */
+    public void store(Object obj,
+                      ObjectModification modification, boolean ignoreReferences) throws PersistenceBrokerException;
+
+    /**
+     * Makes the given object persistent in the underlying persistence system.
+     * This is usually done by issuing an INSERT ... or UPDATE ...  in an RDBMS.
      *
      * @param obj The object to store
      * @param modification Specifies what operation to perform (for generating optimized SQL)

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/ChainingIterator.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/ChainingIterator.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/ChainingIterator.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/ChainingIterator.java Thu Mar  1 17:33:44 2007
@@ -1,6 +1,6 @@
 package org.apache.ojb.broker.accesslayer;
 
-/* Copyright 2002-2004 The Apache Software Foundation
+/* Copyright 2002-2005 The Apache Software Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Collection;
 
 import org.apache.ojb.broker.PersistenceBrokerException;
 
@@ -34,7 +35,6 @@
  * The ChainingIterator cannot return sorted results as the iterator is a 
  * collection of query results across different tables.
  *
- * @author matthew.baird (mattbaird@yahoo.com)
  * @version $Id$
  */
 public class ChainingIterator implements OJBIterator
@@ -64,9 +64,9 @@
     /**
      * Constructor for ChainingIterator.
      */
-    public ChainingIterator(List iterators)
+    public ChainingIterator(Collection ojbIterators)
     {
-        Iterator checkIterator = iterators.iterator();
+        Iterator checkIterator = ojbIterators.iterator();
         OJBIterator temp;
 
         /**
@@ -156,6 +156,65 @@
         return size();
     }
 
+    protected OJBIterator getActiveIterator()
+    {
+        OJBIterator result;
+        if(m_activeIterator == null)
+        {
+            if(m_rsIterators.size() > 0)
+            {
+                result = (OJBIterator) m_rsIterators.get(0);
+            }
+            else
+            {
+                result = OJBIterator.EMPTY_ITERATOR;
+            }
+        }
+        else
+        {
+            result = m_activeIterator;
+        }
+        return result;
+    }
+
+    protected OJBIterator getIterator(int index)
+    {
+        return (OJBIterator) m_rsIterators.get(index);
+    }
+
+    protected OJBIterator setActiveIterator(int iteratorNumber)
+    {
+        m_activeIterator = getIterator(iteratorNumber);
+        m_activeIteratorIndex = iteratorNumber;
+        return m_activeIterator;
+    }
+
+    protected boolean setActiveAbsolute(int row)
+    {
+        OJBIterator it = getActiveIterator();
+        boolean result = it.absolute(row);
+        if(result)
+        {
+            if(row > 0) m_currentCursorPosition = row;
+            else
+            {
+                m_currentCursorPosition = it.size() + 1 + row;
+            }
+        }
+        return result;
+    }
+
+    protected boolean setActiveRelative(int row)
+    {
+        OJBIterator it = getActiveIterator();
+        boolean result = it.relative(row);
+        if(result)
+        {
+            m_currentCursorPosition += row;
+        }
+        return result;
+    }
+
     /**
      * the absolute and relative calls are the trickiest parts. We have to
      * move across cursor boundaries potentially.
@@ -169,74 +228,65 @@
     public boolean absolute(int row) throws PersistenceBrokerException
     {
         checkOpen();
-        // 1. handle the special cases first.
+        // 1. handle the special cases first
         if (row == 0)
         {
             return true;
         }
-
         if (row == 1)
         {
-            m_activeIteratorIndex = 0;
-            m_activeIterator = (OJBIterator) m_rsIterators.get(m_activeIteratorIndex);
-            m_activeIterator.absolute(1);
-            return true;
+            setActiveIterator(0);
+            return setActiveAbsolute(1);
         }
         if (row == -1)
         {
-            m_activeIteratorIndex = m_rsIterators.size();
-            m_activeIterator = (OJBIterator) m_rsIterators.get(m_activeIteratorIndex);
-            m_activeIterator.absolute(-1);
-            return true;
+            setActiveIterator(m_rsIterators.size() - 1);
+            return setActiveAbsolute(-1);
         }
-
-        // now do the real work.
-        boolean movedToAbsolute = false;
+        // 2. now do the real work
         boolean retval = false;
-        setNextIterator();
-
         // row is positive, so index from beginning.
         if (row > 0)
         {
             int sizeCount = 0;
-            Iterator it = m_rsIterators.iterator();
             OJBIterator temp;
-            while (it.hasNext() && !movedToAbsolute)
+            for(int i = 0; i < m_rsIterators.size(); i++)
+            //while (it.hasNext() && !movedToAbsolute)
             {
-                temp = (OJBIterator) it.next();
-                if (temp.size() < row)
+                temp = getIterator(i);
+                int tempMax = temp.size();
+                if(sizeCount + tempMax < row)
                 {
-                    sizeCount += temp.size();
+                    sizeCount += tempMax;
                 }
                 else
                 {
-                    // move to the offset - sizecount
-                    m_currentCursorPosition = row - sizeCount;
-                    retval = temp.absolute(m_currentCursorPosition);
-                    movedToAbsolute = true;
+                    setActiveIterator(i);
+                    retval = setActiveAbsolute(row - sizeCount);
+                    break;
                 }
             }
 
         }
-
         // row is negative, so index from end
         else if (row < 0)
         {
             int sizeCount = 0;
+            int rowAbs = Math.abs(row);
             OJBIterator temp;
-            for (int i = m_rsIterators.size(); ((i >= 0) && !movedToAbsolute); i--)
+            for (int i = m_rsIterators.size() - 1; i >= 0; i--)
             {
-                temp = (OJBIterator) m_rsIterators.get(i);
-                if (temp.size() < row)
+                temp = getIterator(i);
+                int tempMax = temp.size();
+                if (sizeCount + tempMax < rowAbs)
                 {
                     sizeCount += temp.size();
                 }
                 else
                 {
-                    // move to the offset - sizecount
-                    m_currentCursorPosition = row + sizeCount;
-                    retval = temp.absolute(m_currentCursorPosition);
-                    movedToAbsolute = true;
+                    setActiveIterator(i);
+                    retval = setActiveAbsolute(row + sizeCount);
+                    break;
                 }
             }
         }
@@ -262,45 +312,79 @@
     public boolean relative(int row) throws PersistenceBrokerException
     {
         checkOpen();
+        // 1. handle the special cases first.
         if (row == 0)
         {
             return true;
         }
-
-        boolean movedToRelative = false;
+        // 2. now do the real work.
         boolean retval = false;
-        setNextIterator();
-
+        OJBIterator it = getActiveIterator();
+        // positive shift
         if (row > 0)
         {
             // special case checking for the iterator we're currently in
             // (since it isn't positioned on the boundary potentially)
-            if (row > (m_activeIterator.size() - m_currentCursorPosition))
+            if (row > (it.size() - m_currentCursorPosition))
             {
                 // the relative position lies over the border of the
                 // current iterator.
 
                 // starting position counter should be set to whatever we have left in
                 // active iterator.
-                int positionCounter = m_activeIterator.size() - m_currentCursorPosition;
-                for (int i = m_activeIteratorIndex + 1; ((i < m_rsIterators.size()) && !movedToRelative); i++)
+                int positionCounter = it.size() - m_currentCursorPosition;
+                for (int i = m_activeIteratorIndex + 1; i < m_rsIterators.size(); i++)
                 {
-                    m_activeIteratorIndex = i;
-                    m_currentCursorPosition = 0;
-                    m_activeIterator = (OJBIterator) m_rsIterators.get(m_activeIteratorIndex);
-                    if (!((row - positionCounter) > m_activeIterator.size()))
+                    OJBIterator temp = getIterator(i);
+                    if ((row - positionCounter) > temp.size())
+                    {
+                        positionCounter += temp.size();
+                    }
+                    else
                     {
                         // the relative position requested is within this iterator.
-                        m_currentCursorPosition = row - positionCounter;
-                        retval = m_activeIterator.relative(m_currentCursorPosition);
-                        movedToRelative = true;
+                        setActiveIterator(i);
+                        retval = setActiveRelative(row - positionCounter);
+                        break;
                     }
                 }
             }
             else
             {
                 // the relative position lays within the current iterator.
-                retval = m_activeIterator.relative(row);
+               retval = setActiveRelative(row);
+            }
+        }
+        else // negative shift
+        {
+            int rowAbs = Math.abs(row);
+            if(m_currentCursorPosition < rowAbs)
+            {
+                // the relative position lies over the border of the
+                // current iterator.
+
+                // starting position counter should be set to whatever we have left in
+                // active iterator.
+                int positionCounter = m_currentCursorPosition;
+                for (int i = m_activeIteratorIndex - 1; i > -1; i--)
+                {
+                    OJBIterator temp = getIterator(i);
+                    if ((rowAbs - positionCounter) > temp.size())
+                    {
+                        positionCounter += temp.size();
+                    }
+                    else
+                    {
+                        // the relative position requested is within this iterator.
+                        setActiveIterator(i);
+                        retval = setActiveRelative(row + positionCounter);
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                retval = setActiveRelative(row);
             }
         }
 
@@ -437,4 +521,5 @@
             iter.disableLifeCycleEvents();
         }
     }
+
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java Thu Mar  1 17:33:44 2007
@@ -59,6 +59,7 @@
 import org.apache.ojb.broker.query.NullCriteria;
 import org.apache.ojb.broker.query.FieldCriteria;
 import org.apache.ojb.broker.query.SqlCriteria;
+import org.apache.ojb.broker.query.AbstractQueryImpl;
 import org.apache.ojb.broker.util.BrokerHelper;
 import org.apache.ojb.broker.util.ExceptionHelper;
 import org.apache.ojb.broker.util.SqlHelper;
@@ -80,7 +81,7 @@
     /** The broker in use. */
     protected PersistenceBrokerInternal broker;
     protected BatchManager batchManager;
-    protected Platform platform;
+    protected Platform m_platform;
     protected BrokerHelper helper;
 
     /**
@@ -91,7 +92,7 @@
     {
         this.broker = broker;
         this.helper = broker.serviceBrokerHelper();
-        this.platform = broker.serviceConnectionManager().getSupportedPlatform();
+        this.m_platform = broker.serviceConnectionManager().getSupportedPlatform();
         this.batchManager = broker.serviceBatchManager();
     }
 
@@ -255,7 +256,7 @@
             try
             {
                 batchManager.add(batcher, values, 1);
-                postSequenceProcess(cld, obj);
+                postSequenceProcess(null, cld, obj);
             }
             catch(SQLException e)
             {
@@ -285,7 +286,7 @@
                 // TODO: return execution result int value in method
                 stmt.executeUpdate();
                 // perform identity column based autoincrement
-                postSequenceProcess(cld, obj);
+                postSequenceProcess(stmt, cld, obj);
 
                 // Harvest any return values.
                 if(isStoredProcedure) harvestReturnValues(cld.getInsertProcedure(), obj, (CallableStatement) stmt);
@@ -647,6 +648,16 @@
     {
         if(log.isDebugEnabled()) log.debug("executeQuery: " + query);
 
+        /*
+        arminw:
+        we need platform dependent information below, so we have to pre-process the
+        query object, this can cause twice invocation of method Query.preprocess
+        because in class PersistencebrokerImpl#getRsIteratorFromQuery this method
+        is called too
+        TODO: fix twice call of method Query.preprocess if possible
+        */
+        query.preprocess(broker);
+
         final StatementManager stmtManager = broker.serviceStatementManager();
         final boolean scrollable = isScrollable(query);
         SelectStatement sql = null;
@@ -670,7 +681,7 @@
             {
                 // Query implemented as a stored procedure, which must return a result set.
                 // Query sytax is: { ?= call PROCEDURE_NAME(?,...,?)}
-                platform.registerOutResultSet((CallableStatement) stmt, 1);
+                m_platform.registerOutResultSet((CallableStatement) stmt, 1);
                 bindStatement(stmt, query, cld, 2);
                 stmt.execute();
                 rs = (ResultSet) ((CallableStatement) stmt).getObject(1);
@@ -727,7 +738,7 @@
             {
                 // Query implemented as a stored procedure, which must return a result set.
                 // Query sytax is: { ?= call PROCEDURE_NAME(?,...,?)}
-                platform.registerOutResultSet((CallableStatement) stmt, 1);
+                m_platform.registerOutResultSet((CallableStatement) stmt, 1);
                 bindValues((CallableStatement) stmt, values, 2, null);
                 stmt.execute();
                 rs = (ResultSet) ((CallableStatement) stmt).getObject(1);
@@ -881,7 +892,7 @@
             boolean useResultSet = procedure.hasReturnValue();
             if(useResultSet)
             {
-                platform.registerOutResultSet(cs, index);
+                m_platform.registerOutResultSet(cs, index);
                 if(log.isDebugEnabled()) log.debug("[SP] Register OUT ResultSet a index " + index);
                 ++index;
             }
@@ -1204,11 +1215,11 @@
     /**
      * Perform assignment of database identity column based autoincrement values
      */
-    protected void postSequenceProcess(ClassDescriptor cld, Object target) throws SequenceManagerException
+    protected void postSequenceProcess(Statement stmt, ClassDescriptor cld, Object target) throws SequenceManagerException
     {
         // post insert sequence manager call, e.g. to lookup identity column PK value
         // from DB and set PK in persistent object
-        broker.serviceSequenceManager().afterStore(broker, this, cld, target);
+        broker.serviceSequenceManager().afterStore(broker, this, stmt, cld, target);
     }
 
     /**
@@ -1264,7 +1275,7 @@
         {
             if(index == 1 && descriptor.hasReturnValue())
             {
-                platform.registerOutResultSet(cs, index);
+                m_platform.registerOutResultSet(cs, index);
                 if(log.isDebugEnabled()) log.debug("[SP] Register OUT ResultSet a index " + index);
                 ++index;
             }
@@ -1325,11 +1336,11 @@
     {
         if(value == null)
         {
-            platform.setNullForStatement(stmt, index, sqlType);
+            m_platform.setNullForStatement(stmt, index, sqlType);
         }
         else
         {
-            platform.setObjectForStatement(stmt, index, value, sqlType);
+            m_platform.setObjectForStatement(stmt, index, value, sqlType);
         }
     }
 
@@ -1432,11 +1443,11 @@
             // BRJ: use field conversions and platform
             if(value != null)
             {
-                platform.setObjectForStatement(stmt, index, fld.getFieldConversion().javaToSql(value), fld.getJdbcType().getType());
+                m_platform.setObjectForStatement(stmt, index, fld.getFieldConversion().javaToSql(value), fld.getJdbcType().getType());
             }
             else
             {
-                platform.setNullForStatement(stmt, index, fld.getJdbcType().getType());
+                m_platform.setNullForStatement(stmt, index, fld.getJdbcType().getType());
             }
         }
         else
@@ -1517,18 +1528,51 @@
     public int bindStatement(final PreparedStatement stmt, final Query query,
                              final ClassDescriptor cld, int param) throws SQLException
     {
-        int index;
+        int result = param;
+        //TODO: rework limit/offset support, avoid this cast
+        int[] limitValues = ((AbstractQueryImpl) query).getLimitValues();
+        boolean limitOrOffset = query.usePaging() && limitValues.length > 0;
+        if(limitOrOffset)
+        {
+            if(m_platform.limitAfterSelect())
+            {
+                for(int i = 0; i < limitValues.length; i++)
+                {
+                    int limitValue = limitValues[i];
+                    m_platform.setObjectForStatement(stmt, result, new Integer(limitValue), Types.INTEGER);
+                    ++result;
+                }
+            }
 
-        // check type of subquery
-        if (query instanceof QueryByCriteria)
+            // check type of subquery
+            if (query instanceof QueryByCriteria)
+            {
+                QueryByCriteria qbq = (QueryByCriteria) query;
+                result = bindStatement(stmt, qbq.getCriteria(), cld, param);
+                result = bindStatement(stmt, qbq.getHavingCriteria(), cld, result);
+            }
+
+            if(!m_platform.limitAfterSelect())
+            {
+                for(int i = 0; i < limitValues.length; i++)
+                {
+                    int limitValue = limitValues[i];
+                    m_platform.setObjectForStatement(stmt, result, new Integer(limitValue), Types.INTEGER);
+                    ++result;
+                }
+            }
+        }
+        else
         {
-            QueryByCriteria qbq = (QueryByCriteria) query;
-            index = bindStatement(stmt, qbq.getCriteria(), cld, param);
-            index = bindStatement(stmt, qbq.getHavingCriteria(), cld, index);
-            return index;
+            // check type of subquery
+            if (query instanceof QueryByCriteria)
+            {
+                QueryByCriteria qbq = (QueryByCriteria) query;
+                result = bindStatement(stmt, qbq.getCriteria(), cld, param);
+                result = bindStatement(stmt, qbq.getHavingCriteria(), cld, result);
+            }
         }
-
-        return param;
+        return result;
     }
 
     /** bind a Query based Select Statement */

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/OJBIterator.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/OJBIterator.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/OJBIterator.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/OJBIterator.java Thu Mar  1 17:33:44 2007
@@ -21,8 +21,8 @@
 
 /**
  * A {@link Iterator} extension internaly used by OJB to handle query results.
- * <p/>
- * <p/>
+ *
+ * <p>
  * NOTE: OJB is very strict in handling <em>OJBIterator</em> instances. The <em>OJBIterator</em> is
  * bound very closely to the used {@link org.apache.ojb.broker.PersistenceBroker} instance.
  * Thus if you do a
@@ -33,7 +33,7 @@
  * call, the current <em>OJBIterator</em> instance resources will be cleaned up automatic
  * and invalidate current instance by implicit {@link #releaseDbResources()} call.
  * </p>
- * <p/>
+ * <p>
  * Except user explicitly call {@link #setAutoRelease(boolean) setAutoRelease(false)}, then the
  * user is responsible for release resource call.
  * </p>
@@ -43,13 +43,27 @@
 public interface OJBIterator extends Iterator
 {
     /**
+     * Returns the size of the iterator in consideration of limit-seetings
+     * (see {@link org.apache.ojb.broker.query.Query#setStartAtIndex(int)}
+     * and {@link org.apache.ojb.broker.query.Query#setEndAtIndex(int)}) of the
+     * underlying {@link org.apache.ojb.broker.query.Query}.
+     * <br/>
+     * This may differ from the result of method {@link #fullSize()}.
+     *
      * @return the size of the iterator, aka the number of rows in this iterator.
      */
     int size() throws PersistenceBrokerException;
 
     /**
-     * @return the unlimited size of the iterator,
-     *         fullSize() may differ from size() for PagingIterator
+     * Returns the full size of the iterator.
+     *
+     * @return the unlimited size of the iterator, this may differ from {@link #size()}
+     *         dependent of the used implementation - e.g. if
+     *         {@link org.apache.ojb.broker.query.Query#setStartAtIndex(int)}
+     *         and {@link org.apache.ojb.broker.query.Query#setEndAtIndex(int)} is used in the
+     *         underlying {@link org.apache.ojb.broker.query.Query} but the used database does not
+     *         support native LIMIT/OFFSET, thus {@link #fullSize()} will return the full iterator size and
+     *         {@link #size()} take care of limit boundaries.
      */
     int fullSize() throws PersistenceBrokerException;
 
@@ -63,8 +77,9 @@
     boolean absolute(int row) throws PersistenceBrokerException;
 
     /**
-     * Moves the cursor a relative number of rows, either positive or negative. Attempting to move beyond the first/last
-     * row in the iterator positions the cursor before/after the the first/last row. Calling relative(0) is valid,
+     * Moves the cursor a relative number of rows, either positive or negative.
+     * Attempting to move beyond the first/last row in the iterator positions the
+     * cursor before/after the first/last row. Calling relative(0) is valid,
      * but does not change the cursor position.
      *
      * @param row the row to move to in this iterator, by relative number
@@ -113,4 +128,60 @@
      * Do not fire any PBLifeCycleEvent when reading next item. 
      */
     public void disableLifeCycleEvents();
+
+    /**
+     * A NOOP implementation of this interface.
+     */
+    public static final OJBIterator EMPTY_ITERATOR = new OJBIterator(){
+        public boolean absolute(int row) throws PersistenceBrokerException
+        {
+            return false;
+        }
+
+        public void disableLifeCycleEvents()
+        {
+        }
+
+        public int fullSize() throws PersistenceBrokerException
+        {
+            return 0;
+        }
+
+        public boolean relative(int row) throws PersistenceBrokerException
+        {
+            return false;
+        }
+
+        public void releaseDbResources()
+        {
+        }
+
+        public int size() throws PersistenceBrokerException
+        {
+            return 0;
+        }
+
+        public boolean hasNext()
+        {
+            return false;
+        }
+
+        public Object next()
+        {
+            return null;
+        }
+
+        public void remove()
+        {
+        }
+
+        public boolean isClosed()
+        {
+            return false;
+        }
+
+        public void setAutoRelease(boolean autoRelease)
+        {
+        }
+    };
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/PagingIterator.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/PagingIterator.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/PagingIterator.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/PagingIterator.java Thu Mar  1 17:33:44 2007
@@ -1,6 +1,6 @@
 package org.apache.ojb.broker.accesslayer;
 
-/* Copyright 2003-2004 The Apache Software Foundation
+/* Copyright 2003-2005 The Apache Software Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
  */
 
 import org.apache.ojb.broker.PersistenceBrokerException;
+import org.apache.ojb.broker.util.logging.Logger;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
 import org.apache.ojb.broker.query.Query;
 
 /**
@@ -26,18 +28,18 @@
  * startAt = 1, endAt = 11 returns rows 1 to 11 if available
  * if endAt == Query.NO_END_AT_INDEX endAt is set to the last available row
  * 
- * @author <a href="mailto:jbraeuchi@gmx.ch">Jakob Braeuchi</a>
  * @version $Id$
  */
 public class PagingIterator implements OJBIterator
 {
-
+    private Logger log = LoggerFactory.getLogger(PagingIterator.class);
     private final OJBIterator m_iterator;
     private int m_startAt;
     private int m_endAt;
-    private int m_rowLimit;
+    private int m_rowLimitSize;
     private int m_fullSize;
-    private int m_currentCursorPosition; // position of the wrapped iterator
+    // position of the wrapped iterator
+    private int m_currentCursorPosition;
 
     /**
      * Constructor 
@@ -48,36 +50,29 @@
     public PagingIterator(OJBIterator anIterator, int startAt, int endAt)
     {
         super();
-
-        if (endAt != Query.NO_START_AT_INDEX && startAt > endAt)
+        if (endAt != Query.NO_END_AT_INDEX && startAt > endAt)
         {
             throw new PersistenceBrokerException("startAt must be less than endAt.");
         }
 
-        m_iterator = anIterator;
-        m_fullSize = m_iterator.size();
-
-        if (startAt == Query.NO_START_AT_INDEX)
-        {
-            m_startAt = 1;
-        }
-        else
-        {
-            m_startAt = startAt;
-        }
-
-        if (endAt == Query.NO_END_AT_INDEX)
-        {
-            m_endAt = m_fullSize;
+        m_fullSize = anIterator.size();
+        m_startAt = (startAt == Query.NO_START_AT_INDEX ? 1 : startAt);
+        m_endAt = (endAt == Query.NO_END_AT_INDEX || endAt > m_fullSize ? m_fullSize : endAt);
+        m_rowLimitSize = Math.max(0, m_endAt - m_startAt + 1);
+        m_currentCursorPosition = m_startAt;
+        if(m_startAt > m_endAt || m_startAt > m_fullSize)
+        {
+            log.warn("Index out of bound, Query.startAt=" + m_startAt
+                    + " and Query.endAt=" + m_endAt + " doesn't match results");
+            m_iterator = OJBIterator.EMPTY_ITERATOR;
+            m_rowLimitSize = 0;
+            m_fullSize = 0;
+            anIterator.releaseDbResources();
         }
         else
         {
-            m_endAt = Math.min(endAt, m_fullSize);
+            m_iterator = anIterator;
         }
-        
-        m_rowLimit = Math.max(0, m_endAt - m_startAt + 1);
-        m_currentCursorPosition = m_startAt - 1;
-
         m_iterator.absolute(m_currentCursorPosition);
     }
 
@@ -99,13 +94,13 @@
 	 */
     public int size() throws PersistenceBrokerException
     {
-        if (m_fullSize < m_rowLimit)
+        if (m_fullSize < m_rowLimitSize)
         {
             return m_fullSize;
         }
         else
         {
-            return m_rowLimit;
+            return m_rowLimitSize;
         }
     }
 
@@ -122,20 +117,23 @@
 	 */
     public boolean absolute(int row) throws PersistenceBrokerException
     {
-        int newPosition = (m_startAt - 1) + row;
-        
-        if (newPosition < m_startAt)
+        boolean result = false;
+        int newPosition = 0;
+        if(row > 0)
+        {
+            newPosition = m_startAt - 1 + row;
+            result = m_iterator.absolute(newPosition);
+        }
+        else if(row < 0)
         {
-            newPosition = Math.max(m_endAt + row, m_startAt - 1);
+            newPosition = m_endAt + 1 + row;
+            result = m_iterator.absolute(newPosition);
         }
-        
-        if (newPosition > m_endAt)
+        if(result)
         {
-            newPosition = m_endAt;
+            m_currentCursorPosition = newPosition;
         }
-        
-        m_currentCursorPosition = newPosition;
-        return m_iterator.absolute(newPosition);
+        return result;
     }
 
     /**
@@ -143,7 +141,30 @@
 	 */
     public boolean relative(int row) throws PersistenceBrokerException
     {
-        return absolute(m_currentCursorPosition - (m_startAt - 1) + row);
+        boolean result = false;
+        if(row > 0)
+        {
+            if(row <= m_endAt - m_currentCursorPosition)
+            {
+                result = m_iterator.relative(row);
+                if(result)
+                {
+                    m_currentCursorPosition += row;
+                }
+            }
+        }
+        else if(row < 0)
+        {
+            if(Math.abs(row) <= m_currentCursorPosition - m_startAt)
+            {
+                result = m_iterator.relative(row);
+                if(result)
+                {
+                    m_currentCursorPosition += row;
+                }
+            }
+        }
+        return result;
     }
 
     /**
@@ -167,16 +188,12 @@
 	 */
     public boolean hasNext()
     {
-        if (m_currentCursorPosition < m_endAt)
-        {
-            return true;
-        }
-        else
+        boolean result = m_currentCursorPosition <= m_endAt && m_iterator.hasNext();
+        if(!result)
         {
             releaseDbResources();
-            return false;
         }
-
+        return result;
     }
 
     /**

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java Thu Mar  1 17:33:44 2007
@@ -69,17 +69,12 @@
  * It will NOT work with JDBC 1.0 Drivers (e.g. SUN's JdbcOdbcDriver) If you
  * are forced to use such a driver, you can use code from the 0.1.30 release.
  * </p>
- * @author <a href="mailto:thma@apache.org">Thomas Mahler <a>
- * @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
 {
     protected Logger logger = LoggerFactory.getLogger(this.getClass());
-
     private static final String INFO_MSG = "Resources already cleaned up, recommend to set" +
             " this flag before first use of the iterator";
     /*
@@ -215,6 +210,7 @@
             {
                 setHasCalledCheck(true);
                 setHasNext(getRsAndStmt().m_rs.next());
+                m_current_row++;
                 if (!getHasNext())
                 {
                     autoReleaseDbResources();
@@ -260,7 +256,7 @@
             if (getHasNext())
             {
                 Object obj = getObjectFromResultSet();
-                m_current_row++;
+                //m_current_row++;
 
                 // Invoke events on PersistenceBrokerAware instances and listeners
                 // set target object
@@ -507,8 +503,7 @@
     {
         if (!JDBCSupportAssessed)
         {
-            if (getConnectionDescriptor().getJdbcLevel() >= 2.0)
-                advancedJDBCSupport = true;
+            advancedJDBCSupport = getConnectionDescriptor().getJdbcLevel() >= 2.0;
             JDBCSupportAssessed = true;
         }
         return advancedJDBCSupport;
@@ -667,38 +662,47 @@
     private boolean absoluteBasic(int row)
     {
         boolean retval = false;
-        
-        if (row > m_current_row)
+        if(row == -1)
         {
-            try
+            int size = size();
+            if(getQueryObject().usePaging())
             {
-                while (m_current_row < row && getRsAndStmt().m_rs.next())
+                int span = getQueryObject().getEndIndex() + 1 - getQueryObject().getStartIndex();
+                if(span < size)
                 {
-                    m_current_row++;
+                    size = span;
                 }
-                if (m_current_row == row)
-                {
-                    retval = true;
-                }
-                else
+            }
+            row = size;
+        }
+        if (row > m_current_row)
+        {
+            try
+            {
+                retval = true;
+                while (m_current_row < row && retval)
                 {
-                    setHasCalledCheck(true);
-                    setHasNext(false);
-                    retval = false;
-                    autoReleaseDbResources();
+                    retval = getRsAndStmt().m_rs.next();
+                    if(retval) m_current_row++;
+                    else break;
                 }
+                setHasCalledCheck(true);
+                setHasNext(retval);
+                if(!retval) autoReleaseDbResources();
+                System.out.println("result: " + getRsAndStmt().m_rs.getString(1) +", "+ getRsAndStmt().m_rs.getString("Lagerbestand"));
             }
             catch (Exception ex)
             {
                 setHasCalledCheck(true);
                 setHasNext(false);
                 retval = false;
+                autoReleaseDbResources();
             }
         }
         else
         {
-            logger.info("Your driver does not support advanced JDBC Functionality, " +
-                    "you cannot call absolute() with a position < current");
+            logger.warn("Your driver does not support advanced JDBC Functionality, " +
+                    "you cannot call absolute() with a 'position' < 'current'");
         }
         return retval;
     }
@@ -709,21 +713,26 @@
     private boolean absoluteAdvanced(int row)
     {
         boolean retval = false;
-        
         try
         {
             if (getRsAndStmt().m_rs != null)
             {
-                if (row == 0)
+                if(row == 1 || row == 0)
+                {
+                    retval = getRsAndStmt().m_rs.first();
+                    //retval = getRsAndStmt().m_rs.absolute(1);
+                }
+                else if (row == -1)
                 {
-                    getRsAndStmt().m_rs.beforeFirst();
+                    retval = getRsAndStmt().m_rs.last();
                 }
                 else
                 {
-                    retval = getRsAndStmt().m_rs.absolute(row);                        
+                    retval = getRsAndStmt().m_rs.absolute(row);
                 }
-                m_current_row = row;
-                setHasCalledCheck(false);
+                if(retval) m_current_row = row;
+                setHasCalledCheck(retval);
+                setHasNext(retval);
             }
         }
         catch (SQLException e)
@@ -768,7 +777,8 @@
             }
             else
             {
-                logger.info("Your driver does not support advanced JDBC Functionality, you cannot call relative() with a negative value");
+                logger.warn("Your driver does not support advanced JDBC Functionality, you cannot call" +
+                        " relative() with a negative value");
             }
         }
         return retval;

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java Thu Mar  1 17:33:44 2007
@@ -15,12 +15,12 @@
  * limitations under the License.
  */
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.lang.ref.WeakReference;
 
 import org.apache.commons.collections.set.ListOrderedSet;
 import org.apache.ojb.broker.accesslayer.sql.TableAliasHandler.TableAlias;
@@ -33,6 +33,7 @@
 import org.apache.ojb.broker.query.Query;
 import org.apache.ojb.broker.query.QueryByCriteria;
 import org.apache.ojb.broker.query.ReportQueryByCriteria;
+import org.apache.ojb.broker.query.AbstractQueryImpl;
 import org.apache.ojb.broker.util.SqlHelper;
 import org.apache.ojb.broker.util.logging.Logger;
 
@@ -356,10 +357,10 @@
            ((ReportQueryByCriteria) query).setAttributeFieldDescriptors(getAttributesToFieldDescriptors());
         }
 
-        if(query.isSelectForUpdate())
-        {
-            stmt.append(getPlatform().getSelectForUpdateClause());
-        }
+        stmt = prepareLimitAndOffset(stmt);
+
+        appendSelectForUpdate(stmt);
+
         if(query.getQueryAffix() != null)
         {
             stmt.append(" ").append(query.getQueryAffix());
@@ -368,17 +369,25 @@
         return stmt.toString();
     }
 
-    /**
-     * @see org.apache.ojb.broker.accesslayer.sql.SelectStatement#getQueryInstance()
-     */
+    protected StringBuffer prepareLimitAndOffset(StringBuffer stmt)
+    {
+        //TODO: Rework this section
+        return ((AbstractQueryImpl) getQuery()).prepareLimitAndOffset(stmt);
+    }
+
+    protected void appendSelectForUpdate(StringBuffer stmt)
+    {
+        if(getQuery().isSelectForUpdate())
+        {
+            stmt.append(getPlatform().getSelectForUpdateClause());
+        }
+    }
+
     public Query getQueryInstance()
     {
         return getQuery();
     }
 
-    /**
-     * @see org.apache.ojb.broker.accesslayer.sql.SelectStatement#getColumnIndex(org.apache.ojb.broker.metadata.FieldDescriptor)
-     */
     public int getColumnIndex(FieldDescriptor fld)
     {
         int index = JdbcType.MIN_INT;
@@ -397,9 +406,6 @@
         return index;
     }
     
-    /**
-     * @see org.apache.ojb.broker.accesslayer.sql.SelectStatement#isUseOjbClassColumn()
-     */
     public boolean isUseOjbClassColumn()
     {
         // BRJ: force generation of sql-string.

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java Thu Mar  1 17:33:44 2007
@@ -277,7 +277,12 @@
 		getBroker().store(obj, modification);
 	}
 
-	public PBKey getPBKey()
+    public void store(Object obj, ObjectModification modification, boolean ignoreReferences) throws PersistenceBrokerException
+    {
+        getBroker().store(obj, modification, ignoreReferences);
+    }
+
+    public PBKey getPBKey()
 	{
 		return getBroker().getPBKey();
 	}

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java Thu Mar  1 17:33:44 2007
@@ -42,6 +42,7 @@
 import org.apache.ojb.broker.TransactionInProgressException;
 import org.apache.ojb.broker.TransactionNotInProgressException;
 import org.apache.ojb.broker.TransientObjectException;
+import org.apache.ojb.broker.platforms.Platform;
 import org.apache.ojb.broker.accesslayer.ChainingIterator;
 import org.apache.ojb.broker.accesslayer.CollectionCreationContext;
 import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
@@ -57,7 +58,6 @@
 import org.apache.ojb.broker.accesslayer.batch.BatchStrategy;
 import org.apache.ojb.broker.accesslayer.batch.ReturnValueValidator;
 import org.apache.ojb.broker.accesslayer.sql.SqlGenerator;
-import org.apache.ojb.broker.cache.ObjectCache;
 import org.apache.ojb.broker.cache.SessionCache;
 import org.apache.ojb.broker.core.configuration.ComponentContainer;
 import org.apache.ojb.broker.core.proxy.CollectionProxy;
@@ -1152,25 +1152,6 @@
         link(obj, cld, rds, ref, insert);
     }
 
-    private void afterStore(TrackingCollection tc, CollectionDescriptor cod)
-    {
-        if (cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT)
-        {
-            Iterator iter = tc.getDeletedObjects().iterator();
-            while (iter.hasNext())
-            {
-                Object obj = iter.next();
-                ClassDescriptor cld = getClassDescriptor(obj.getClass());
-                if (serviceBrokerHelper().assertValidPkForDelete(cld, obj))
-                {
-                    delete(obj);
-                }
-            }
-            tc.clearDeletedObjects();
-            tc.clearNewObjects();
-        }
-    }
-
     /**
      * Store/Link collections of objects poiting to <b>obj</b>.
      * More info please see comments in source.
@@ -1213,6 +1194,25 @@
         }
     }
 
+    private void afterStore(TrackingCollection tc, CollectionDescriptor cod)
+    {
+        if (cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT)
+        {
+            Iterator iter = tc.getDeletedObjects().iterator();
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+                ClassDescriptor cld = getClassDescriptor(obj.getClass());
+                if (serviceBrokerHelper().assertValidPkForDelete(cld, obj))
+                {
+                    delete(obj);
+                }
+            }
+            tc.clearDeletedObjects();
+            tc.clearNewObjects();
+        }
+    }
+
     /**
      * Store/Link m:n collection references.
      *
@@ -1940,23 +1940,23 @@
         return getIteratorFromQuery(query, cld);
     }
 
-    /**
-     * Get an extent aware Iterator based on the Query
-     *
-     * @param query
-     * @param cld the ClassDescriptor
-     * @return OJBIterator
-     */
-    protected OJBIterator getIteratorFromQuery(Query query, ClassDescriptor cld) throws PersistenceBrokerException
-    {
-        OJBIterator result = getRsIteratorFromQuery(query, cld, RsIteratorFactoryFactory.getRsIteratorFactory());
-
-        if (query.usePaging())
-        {
-            result = new PagingIterator(result, query.getStartAtIndex(), query.getEndAtIndex());
-        }
-        return result;
-    }
+//    /**
+//     * Get an extent aware Iterator based on the Query
+//     *
+//     * @param query
+//     * @param cld the ClassDescriptor
+//     * @return OJBIterator
+//     */
+//    protected OJBIterator getIteratorFromQuery(Query query, ClassDescriptor cld) throws PersistenceBrokerException
+//    {
+//        OJBIterator result = getRsIteratorFromQuery(query, cld, RsIteratorFactoryFactory.getRsIteratorFactory());
+//
+//        if (query.usePaging())
+//        {
+//            result = new PagingIterator(result, query.getStartAtIndex(), query.getEndAtIndex());
+//        }
+//        return result;
+//    }
 
     public Object getObjectByIdentity(Identity id) throws PersistenceBrokerException
     {
@@ -2277,16 +2277,13 @@
         return result;
     }
 
-    /**
-     * Makes object obj persistent in the underlying persistence system.
-     * E.G. by INSERT INTO ... or UPDATE ...  in an RDBMS.
-     * The ObjectModification parameter can be used to determine whether INSERT or update is to be used.
-     * This functionality is typically called from transaction managers, that
-     * track which objects have to be stored. If the object is an unmaterialized
-     * proxy the method return immediately.
-     */
     public void store(Object obj, ObjectModification mod) throws PersistenceBrokerException
     {
+        store(obj, mod, false);
+    }
+
+    public void store(Object obj, ObjectModification mod, boolean ignoreReferences) throws PersistenceBrokerException
+    {
         obj = extractObjectToStore(obj);
         // null for unmaterialized Proxy
         if (obj == null)
@@ -2300,11 +2297,11 @@
         // select flag for insert / update selection by checking the ObjectModification
         if (mod.needsInsert())
         {
-            store(obj, oid, cld, true);
+            store(obj, oid, cld, true, ignoreReferences);
         }
         else if (mod.needsUpdate())
         {
-            store(obj, oid, cld, false);
+            store(obj, oid, cld, false, ignoreReferences);
         }
         /*
         arminw
@@ -2516,6 +2513,32 @@
     }
 
     /**
+     * Get an extent aware Iterator based on the ReportQuery
+     *
+     * @param query
+     * @param cld
+     * @return OJBIterator
+     */
+    protected OJBIterator getReportQueryIteratorFromQuery(Query query, ClassDescriptor cld) throws PersistenceBrokerException
+    {
+        RsIteratorFactory factory = RsIteratorFactoryFactory.getReportRsIteratorFactory();
+        return getRsIteratorFromQuery(query, cld, factory);
+    }
+
+    /**
+     * Get an extent aware Iterator based on the Query
+     *
+     * @param query
+     * @param cld the ClassDescriptor
+     * @return OJBIterator
+     */
+    protected OJBIterator getIteratorFromQuery(Query query, ClassDescriptor cld) throws PersistenceBrokerException
+    {
+        RsIteratorFactory factory = RsIteratorFactoryFactory.getRsIteratorFactory();
+        return getRsIteratorFromQuery(query, cld, factory);
+    }
+
+    /**
      * Get an extent aware RsIterator based on the Query
      *
      * @param query
@@ -2526,60 +2549,90 @@
     private OJBIterator getRsIteratorFromQuery(Query query, ClassDescriptor cld, RsIteratorFactory factory)
         throws PersistenceBrokerException
     {
-        query.setFetchSize(1);
+        // arminw: we use iterator for all kind of query, so I think
+        // this setting doesn't make sense and will override user settings
+        //query.setFetchSize(1);
+        /*
+        arminw:
+        we need platform dependent information below, so we have to pre-process the
+        query object, this will cause twice invocation of method Query.preprocess
+        because in class JdbcAccess this method is called too
+        TODO: fix twice call of method Query.preprocess if possible
+        */
         query.preprocess(this);
+        OJBIterator result;
 
         if (query instanceof QueryBySQL)
         {
             if(logger.isDebugEnabled()) logger.debug("Creating SQL-RsIterator for class ["+cld.getClassNameOfObject()+"]");
-            return factory.createRsIterator((QueryBySQL) query, cld, this);
+            result = factory.createRsIterator((QueryBySQL) query, cld, this);
+            result = wrapWithPagingIteratorIfNeeded(result, query);
         }
-
-        if (!cld.isExtent() || !query.getWithExtents())
+        else if (!cld.isExtent() || !query.getWithExtents())
         {
             // no extents just use the plain vanilla RsIterator
             if(logger.isDebugEnabled()) logger.debug("Creating RsIterator for class ["+cld.getClassNameOfObject()+"]");
 
             Query theQuery = serviceBrokerHelper().setConcreteClassCriteria(this, (QueryByCriteria)query, cld);
-            return factory.createRsIterator(theQuery, cld, this);
+            result = factory.createRsIterator(theQuery, cld, this);
+            result = wrapWithPagingIteratorIfNeeded(result, query);
         }
-
-        if(logger.isDebugEnabled()) logger.debug("Creating ChainingIterator for class ["+cld.getClassNameOfObject()+"]");
-
-        ChainingIterator chainingIter = new ChainingIterator();
-        Collection cldInfos = serviceBrokerHelper().getExtentsDescriptors(cld);
-        Iterator extents = cldInfos.iterator();
-
-        while (extents.hasNext())
+        else
         {
-            BrokerHelper.CldInfo cldInfo = (BrokerHelper.CldInfo) extents.next();
-            Query theQuery = serviceBrokerHelper().setConcreteClassCriteria(this, (QueryByCriteria)query, cldInfo);
+            if(logger.isDebugEnabled()) logger.debug("Creating ChainingIterator for class ["+cld.getClassNameOfObject()+"]");
 
-            if(logger.isDebugEnabled()) logger.debug("Adding RsIterator of class ["+ cldInfo.cld.getClassNameOfObject()+"] to ChainingIterator");
+            ChainingIterator chainingIter = new ChainingIterator();
+            Collection cldInfos = serviceBrokerHelper().getExtentsDescriptors(cld);
+            Iterator extents = cldInfos.iterator();
 
-            // add the iterator to the chaining iterator.
-            chainingIter.addIterator(factory.createRsIterator(theQuery, cldInfo.cld, this));
-        }
+            while (extents.hasNext())
+            {
+                BrokerHelper.CldInfo cldInfo = (BrokerHelper.CldInfo) extents.next();
+                if(logger.isDebugEnabled()) logger.debug("Adding RsIterator of class ["+ cldInfo.cld.getClassNameOfObject()+"] to ChainingIterator");
+                Query theQuery = serviceBrokerHelper().setConcreteClassCriteria(this, (QueryByCriteria)query, cldInfo);
+                OJBIterator tmp = wrapWithPagingIteratorIfNeeded(factory.createRsIterator(theQuery, cldInfo.cld, this), theQuery);
+                // add the iterator to the chaining iterator.
+                chainingIter.addIterator(tmp);
+            }
 
-        return chainingIter;
+            result = chainingIter;
+        }
+        return result;
     }
 
     /**
-     * Get an extent aware Iterator based on the ReportQuery
+     * If native paging (LIMIT and/or LIMIT OFFSET) is not supported by the current
+     * database, wrap the current OJBIterator with a paging wrapper.
      *
-     * @param query
-     * @param cld
-     * @return OJBIterator
+     * @param iter The normal iterator.
+     * @param query The query.
+     * @return A paging capable iterator or the specified iterator if native paging
+     * is supported.
      */
-    private OJBIterator getReportQueryIteratorFromQuery(Query query, ClassDescriptor cld) throws PersistenceBrokerException
+    protected OJBIterator wrapWithPagingIteratorIfNeeded(OJBIterator iter, Query query)
     {
-        OJBIterator result = getRsIteratorFromQuery(query, cld, RsIteratorFactoryFactory.getReportRsIteratorFactory());
-
-        if (query.usePaging())
+        OJBIterator result = iter;
+        boolean isNativeLimitOffset = serviceConnectionManager().getConnectionDescriptor().isNativeLimitOffset();
+        if(query.usePaging())
         {
-            result = new PagingIterator(result, query.getStartAtIndex(), query.getEndAtIndex());
+            Platform platform = serviceConnectionManager().getSupportedPlatform();
+            // limit offset needed, full paging
+            if(query.hasOffset())
+            {
+                if(!isNativeLimitOffset || !platform.supportsOffset())
+                {
+                    result = new PagingIterator(iter, query.getStartAtIndex(), query.getEndAtIndex());
+                }
+            }
+            // only limit
+            else if (query.hasLimit())
+            {
+                if(!isNativeLimitOffset || !platform.supportsLimit())
+                {
+                    result = new PagingIterator(iter, query.getStartAtIndex(), query.getEndAtIndex());
+                }
+            }
         }
-
         return result;
     }
 

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/JdbcConnectionDescriptor.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/JdbcConnectionDescriptor.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/JdbcConnectionDescriptor.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/JdbcConnectionDescriptor.java Thu Mar  1 17:33:44 2007
@@ -28,6 +28,7 @@
 import org.apache.ojb.broker.util.logging.Logger;
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 import org.apache.ojb.broker.util.XmlHelper;
+import org.apache.ojb.broker.util.ConvertHelper;
 
 /**
  * JdbcConnectionDescriptor describes all relevant parameters of
@@ -43,6 +44,7 @@
     public static final int AUTO_COMMIT_IGNORE_STATE = 0;
     public static final int AUTO_COMMIT_SET_TRUE_AND_TEMPORARY_FALSE = 1;
     public static final int AUTO_COMMIT_SET_FALSE = 2;
+    protected static final String ATTRIBUTE_NATIVE_LIMIT_OFFSET = "nativeLimitOffset";
 
     private String m_jcdAlias;
     private String m_Dbms;
@@ -58,6 +60,7 @@
     private boolean defaultConnection = false;
     private int useAutoCommit = AUTO_COMMIT_SET_TRUE_AND_TEMPORARY_FALSE;
     private boolean ignoreAutoCommitExceptions = false;
+    private Boolean nativeLimitOffset;
     private PBKey pbKey;
     private ConnectionFactoryDescriptor cpd;
     private SequenceDescriptor sequenceDescriptor;
@@ -418,6 +421,42 @@
         m_batchMode = flag;
     }
 
+    /**
+     * Get the query limit/offset mode. If set <em>true</em> OJB use the native database specific
+     * LIMIT and OFFSET arguments for limit and paging queries (if it's supported by the DB and
+     * OJB's {@link Platform} implementation class). If set <em>false</em> OJB simulate limit
+     * and paging by a specific result set iterator (this can result in bad performance on big
+     * result sets).
+     *
+     * @return The current used limit and paging mode.
+     */
+    public boolean isNativeLimitOffset()
+    {
+        if(nativeLimitOffset == null)
+        {
+            nativeLimitOffset = ConvertHelper.toBoolean(getAttribute(ATTRIBUTE_NATIVE_LIMIT_OFFSET));
+            // by default we support native limit/paging
+            if(nativeLimitOffset == null)
+            {
+                nativeLimitOffset = Boolean.TRUE;
+            }
+        }
+        return nativeLimitOffset.booleanValue();
+    }
+
+    /**
+     * Sets the query limit/paging mode - see {@link #isNativeLimitOffset()}.
+     *
+     * @param nativeLimitOffset The limit paging mode.
+     */
+    public void setNativeLimitOffset(boolean nativeLimitOffset)
+    {
+        this.nativeLimitOffset = nativeLimitOffset ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Returns the associated {@link org.apache.ojb.broker.platforms.Platform}.
+     */
     public Platform getPlatform()
     {
         // no need to synchronize, dosen't matter if we use different instances

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/Platform.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/Platform.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/Platform.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/Platform.java Thu Mar  1 17:33:44 2007
@@ -25,6 +25,7 @@
 
 import org.apache.ojb.broker.metadata.FieldDescriptor;
 import org.apache.ojb.broker.query.LikeCriteria;
+import org.apache.ojb.broker.query.Query;
 
 /**
  * This interface provides callbacks that allow to perform
@@ -51,7 +52,7 @@
     /**
      * Called by {@link org.apache.ojb.broker.accesslayer.StatementManager} implementation
      * after invoking <tt>stmt.close()</tt> method.
-     * @see #beforeStatementClose(java.sql.Statement, java.sql.ResultSet) 
+     * @see #beforeStatementClose(java.sql.Statement, java.sql.ResultSet)
      */
     public void afterStatementClose(Statement stmt, ResultSet rs) throws PlatformException;
 
@@ -161,15 +162,6 @@
     String createSequenceQuery(String sequenceName, Properties prop);
 
     /**
-     * Returns a query to create a sequence entry.
-     *
-     * @param sequenceName The name of the sequence to create.
-     * @return a sql string to create a sequence
-     * @deprecated use {@link #createSequenceQuery(String)} instead.
-     */
-    String createSequenceQuery(String sequenceName);
-
-    /**
      * Returns a query to obtain the next sequence key.
      * @return a sql string to get next sequence value
      */
@@ -205,33 +197,80 @@
      */
     public String getLastInsertIdentityQuery(String tableName);
 
+
+    //===================================================================
+    // Limit and paging methods
+    //===================================================================
+
     /**
-     * Answer true if LIMIT or equivalent is supported
-     * <b> SQL-Paging is not yet supported </b>
+     * Answer <em>true</em> if LIMIT or equivalent is supported.
      */
-    public boolean supportsPaging();
+    boolean supportsLimit();
 
     /**
-     * Add the LIMIT or equivalent to the SQL 
-     * <b> SQL-Paging is not yet supported </b>
+     * Add the LIMIT to the SQL.
      */
-    public void addPagingSql(StringBuffer anSqlString);
+    StringBuffer addLimitSql(Query query, StringBuffer anSqlString);
 
     /**
-     * Answer true if the LIMIT parameters are bound before the query parameters
-     * <b> SQL-Paging is not yet supported </b>
+     * Answer <em>true</em> if LIMIT OFFSET or equivalent is supported.
      */
-    public boolean bindPagingParametersFirst();
+    boolean supportsOffset();
 
     /**
-     * Bind the Paging Parameters
-     * <b> SQL-Paging is not yet supported </b>
-     * @param ps
-     * @param index parameter index
-     * @param startAt
-     * @param endAt
+     * Add the LIMIT with LIMIT OFFSET to the SQL.
      */
-    public int bindPagingParameters(PreparedStatement ps, int index, int startAt, int endAt) throws SQLException;
+    StringBuffer addPagingSql(Query query, StringBuffer anSqlString);
+
+    /**
+     * Builds the platform dependend LIMIT OFFSET value of the
+     * {@link org.apache.ojb.broker.query.Query#getStartAtIndex()} value
+     * (Note: take care of include/exclude boundary conditions).
+     *
+     * @param query The query.
+     * @return The platform dependend limit offset value.
+     */
+    int buildOffset(Query query);
+
+    /**
+     * Builds the platform dependend LIMIT value of the
+     * {@link org.apache.ojb.broker.query.Query#getEndAtIndex()} value
+     * (Note: take care of include/exclude boundary conditions).
+     *
+     * @param query The query.
+     * @return The platform dependend limit value.
+     */
+    int buildLimit(Query query);
+
+    /**
+     * Returns the order of the LIMIT and OFFSET value setting
+     * in the LIMIT/OFFSET clause (e.g. in "LIMIT ?, ?").
+     * If <em>true</em> the limit argument have to be set before the offset
+     * argument. If <em>false</em> the reverse order is mandatory.
+     *
+     * @return The order of the LIMIT/OFFSET values.
+     */
+    boolean limitBeforeOffset();
+
+    /**
+     * Returns <em>true</em> if the LIMIT/OFFSET clause is added after the
+     * SELECT-expression (e.g. "SELECT TOP n ..."). If <em>false</em> the
+     * LIMIT/OFFSET clause is added after the ORDER BY clause (e.g. "SELECT ... ORDER BY 1 LIMIT n,m").
+     */
+    boolean limitAfterSelect();
+
+    /**
+     * If <em>true</em> the LIMIT/OFFSET values will be embedded in
+     * the limit/paging SQL-query when calling {@link #addLimitSql(org.apache.ojb.broker.query.Query, StringBuffer)}
+     * or {@link #addPagingSql(org.apache.ojb.broker.query.Query, StringBuffer)}. If <em>false</em> prepared statement
+     * paceholder "?" are used in these methods and OJB have bind the values.
+     *
+     * @return Whether or not the LIMIT/OFFSET values will be embedded in the SQL-query.
+     */
+    boolean limitOffsetValuesEmbedded();
+
+    //===================================================================
+
 
     /**
      * Whether the platform supports a COUNT DISTINCT across multiple columns.
@@ -308,4 +347,20 @@
      * @return The post prepared column value.
      */
     public Object postPrepareReadInValue(FieldDescriptor fld, Object value);
+
+    /**
+     * If <em>true</em> auto-generated keys can be retrieved after a statement
+     * has been executed.
+     */
+    boolean supportsGetGeneratedKeys();
+
+    /**
+     * Show same behavior as <em>Statement.getGeneratedKeys()</em> - JDBC quotation:
+     * <br/>
+     * "Retrieves any auto-generated keys created as a result of executing this Statement object.
+     * If this Statement object did not generate any keys, an empty ResultSet object is returned."
+     * @param stmt
+     * @return The generated keys.
+     */
+    ResultSet getGeneratedKeys(Statement stmt) throws SQLException;
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDb2Impl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDb2Impl.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDb2Impl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDb2Impl.java Thu Mar  1 17:33:44 2007
@@ -22,6 +22,7 @@
 
 import org.apache.ojb.broker.util.sequence.SequenceManagerHelper;
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
+import org.apache.ojb.broker.query.Query;
 
 /**
  * This class extends <code>PlatformDefaultImpl</code> and defines specific
@@ -141,11 +142,6 @@
         }
     }
 
-    public String createSequenceQuery(String sequenceName)
-    {
-        return "create sequence " + sequenceName;
-    }
-
     public String createSequenceQuery(String sequenceName, Properties prop)
     {
         /*
@@ -253,4 +249,76 @@
         //
 		return "select IDENTITY_VAL_LOCAL() from sysibm.sysdummy1";
 	}
+
+
+
+    public boolean supportsLimit()
+    {
+        return true;
+}
+
+    public StringBuffer addLimitSql(Query query, StringBuffer anSqlString)
+    {
+        /*
+        see http://troels.arvin.dk/db/rdbms/
+        "When doing casual work, it's often easier to use DB2's non-standard
+        SELECT ... FETCH FIRST n ROWS ONLY construct."
+        Seems parameter marker '?' are not allowed.
+        */
+        return anSqlString
+                .append(" FETCH FIRST ")
+                .append(buildLimit(query))
+                .append(" ROWS ONLY");
+    }
+
+    public boolean supportsOffset()
+    {
+        return false;
+    }
+
+    public StringBuffer addPagingSql(Query query, StringBuffer anSqlString)
+    {
+        // TODO: native paging support
+        // not supported
+        throw new UnsupportedOperationException("OFFSET is not supported by this platform" +
+                " implementation class (" + this.getClass().getName() +
+                "), please disable the native limit/offset flag in the" +
+                " connection metadata mapping file using attribute 'nativeLimitOffset'" +
+                " then OJB will use specific paging/limit result set iterator to simulate it!");
+    }
+
+    public int buildLimit(Query query)
+    {
+        int result = 0;
+        if(query.hasLimit())
+        {
+            return query.getEndAtIndex();
+        }
+        else if(query.hasOffset())
+        {
+            return MAX_LIMIT_VALUE;
+        }
+        return result;
+    }
+
+    public int buildOffset(Query query)
+    {
+        return query.getStartAtIndex();
+    }
+
+    public boolean limitOffsetValuesEmbedded()
+    {
+        // parameter marker '?' are not allowed, we embed limit/offset values
+        return true;
+    }
+
+    public boolean limitBeforeOffset()
+    {
+        return false;
+    }
+
+    public boolean limitAfterSelect()
+    {
+        return false;
+    }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDefaultImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDefaultImpl.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDefaultImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformDefaultImpl.java Thu Mar  1 17:33:44 2007
@@ -36,6 +36,7 @@
 import org.apache.ojb.broker.metadata.FieldDescriptor;
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
 import org.apache.ojb.broker.query.LikeCriteria;
+import org.apache.ojb.broker.query.Query;
 import org.apache.ojb.broker.util.SqlHelper;
 import org.apache.ojb.broker.util.logging.Logger;
 import org.apache.ojb.broker.util.logging.LoggerFactory;
@@ -54,9 +55,17 @@
     private static final String INITIALIZATION_CHECK_AUTOCOMMIT = "initializationCheck";
     private static final String FALSE_STR = "false";
 
+    /**
+     * Doesn't make sense to use the maximal possible integer as maximal limit value,
+     * thus OJB use '900000000'. Don't use Integer.MAX because not all DB INTEGER
+     * data type support it.
+     */
+    protected static final int MAX_LIMIT_VALUE = 900000000;
+
     protected boolean m_batchUpdatesChecked = false;
     protected boolean m_supportsBatchUpdates = false;
-    protected Boolean locatorsUpdateCopy;
+    private Boolean locatorsUpdateCopy;
+    private Boolean supportsGetGeneratedKeys;
     protected JdbcConnectionDescriptor jcd;
 
     public PlatformDefaultImpl(JdbcConnectionDescriptor jcd)
@@ -98,6 +107,40 @@
         }
     }
 
+    /**
+     * Sets platform information for if the jdbc driver/db combo support
+     * get auto-generated keys. Will only be checked once.
+     *
+     * @param conn
+     */
+    protected void checkForGetGeneratedKeys(Connection conn)
+    {
+        if(supportsGetGeneratedKeys == null)
+        {
+            try
+            {
+//#ifdef JDBC30
+
+                DatabaseMetaData meta = conn.getMetaData();
+                boolean result = meta.supportsGetGeneratedKeys();
+
+//#else
+
+/*
+                boolean result = false;
+*/
+
+//#endif
+                supportsGetGeneratedKeys = result ? Boolean.TRUE : Boolean.FALSE;
+            }
+            catch(Exception e)
+            {
+                log.warn("Get auto-generated keys support check failed", e);
+                supportsGetGeneratedKeys = Boolean.FALSE;
+            }
+        }
+    }
+
     public void afterStatementCreate(Statement stmt) throws PlatformException
     {
         //noop
@@ -159,6 +202,7 @@
     public void initializeJdbcConnection(Connection conn) throws PlatformException
     {
         if (jcd.getBatchMode()) checkForBatchSupport(conn);
+        checkForGetGeneratedKeys(conn);
 
         switch (jcd.getUseAutoCommit())
         {
@@ -446,14 +490,6 @@
 
     public String createSequenceQuery(String sequenceName, Properties prop)
     {
-        return createSequenceQuery(sequenceName);
-    }
-
-    /**
-     * Override this method to enable database based sequence generation
-     */
-    public String createSequenceQuery(String sequenceName)
-    {
         /*default implementation does not support this*/
         throw new UnsupportedOperationException("This feature is not supported by this implementation");
     }
@@ -489,42 +525,77 @@
         throw new UnsupportedOperationException("This feature is not supported by this implementation");
     }
 
-    /**
-     * @see org.apache.ojb.broker.platforms.Platform#addPagingSql(java.lang.StringBuffer)
-     */
-    public void addPagingSql(StringBuffer anSqlString)
+
+
+    public boolean supportsLimit()
     {
-        // do nothing
+        return false;
     }
 
-    /**
-     * @see org.apache.ojb.broker.platforms.Platform#bindPagingParametersFirst()
-     */
-    public boolean bindPagingParametersFirst()
+    public StringBuffer addLimitSql(Query query, StringBuffer anSqlString)
+    {
+        // not supported
+        throw new UnsupportedOperationException("LIMIT/OFFSET is not supported by this platform" +
+                " implementation class (" + this.getClass().getName() +
+                "), please disable the native limit/offset flag in the" +
+                " connection metadata mapping file using attribute 'nativeLimitOffset'" +
+                " then OJB will use specific paging/limit result set iterator to simulate it!");
+    }
+
+    public boolean supportsOffset()
     {
         return false;
     }
 
-    /**
-     * @see org.apache.ojb.broker.platforms.Platform#supportsPaging()
-     */
-    public boolean supportsPaging()
+    public StringBuffer addPagingSql(Query query, StringBuffer anSqlString)
+    {
+        // not supported
+        throw new UnsupportedOperationException("LIMIT/OFFSET is not supported by this platform" +
+                " implementation class (" + this.getClass().getName() +
+                "), please disable the native limit/offset flag in the" +
+                " connection metadata mapping file using attribute 'nativeLimitOffset'" +
+                " then OJB will use specific paging/limit result set iterator to simulate it!");
+    }
+
+    public int buildOffset(Query query)
+    {
+        // if start index not set return 0
+        return query.hasOffset() ? query.getStartAtIndex() - 1 : 0;
+    }
+
+    public int buildLimit(Query query)
+    {
+        if(query.hasLimit())
+        {
+            return query.getEndAtIndex() - (query.getStartAtIndex() > 0 ? query.getStartAtIndex() - 1 : 0);
+        } // offset set without limit, we return all rows starting with the offset
+        else if(query.hasOffset())
+        {
+            return MAX_LIMIT_VALUE;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+
+    public boolean limitBeforeOffset()
     {
         return false;
     }
 
-    /**
-     * @see org.apache.ojb.broker.platforms.Platform#bindPagingParameters(java.sql.PreparedStatement, int, int, int)
-     */
-    public int bindPagingParameters(PreparedStatement ps, int index, int startAt, int endAt) throws SQLException
+    public boolean limitAfterSelect()
     {
-        ps.setInt(index, startAt - 1);              // zero based start
-        index++;
-        ps.setInt(index, endAt - (startAt - 1));    // number of rows to fetch
-        index++;
-        return index;
+        return false;
     }
 
+    public boolean limitOffsetValuesEmbedded()
+    {
+        return false;
+    }
+
+
+
     /**
      * Answer the Character for Concatenation
      */
@@ -691,5 +762,39 @@
     public Object postPrepareReadInValue(final FieldDescriptor fld, final Object value)
     {
         return value;
+    }
+
+    public boolean supportsGetGeneratedKeys()
+    {
+        return supportsGetGeneratedKeys != null && supportsGetGeneratedKeys.booleanValue();
+    }
+
+    public ResultSet getGeneratedKeys(Statement stmt) throws SQLException
+    {
+
+//#ifdef JDBC30
+
+        return stmt.getGeneratedKeys();
+
+//#else
+
+/*
+        // not supported
+        throw new UnsupportedOperationException("Not supported in used JDBC-specification version");
+*/
+
+//#endif
+
+    }
+
+    /**
+     * Build the default query to create a database sequence.
+     * 
+     * @param sequenceName The name of the sequence.
+     * @return The create-sequence query.
+     */
+    protected String createSequenceQuery(String sequenceName)
+    {
+        return "create sequence " + sequenceName;
     }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformFirebirdImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformFirebirdImpl.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformFirebirdImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformFirebirdImpl.java Thu Mar  1 17:33:44 2007
@@ -1,5 +1,7 @@
 package org.apache.ojb.broker.platforms;
 
+import java.util.Properties;
+
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
 
 /* Copyright 2003-2004 The Apache Software Foundation
@@ -33,7 +35,7 @@
         super(jcd);
     }
 
-    public String createSequenceQuery(String sequenceName)
+    public String createSequenceQuery(String sequenceName, Properties prop)
     {
         return "create generator " + sequenceName;
     }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformHsqldbImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformHsqldbImpl.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformHsqldbImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformHsqldbImpl.java Thu Mar  1 17:33:44 2007
@@ -19,6 +19,7 @@
 
 import org.apache.ojb.broker.util.sequence.SequenceManagerHelper;
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
+import org.apache.ojb.broker.query.Query;
 
 /**
  * This class extends <code>PlatformDefaultImpl</code> and defines specific
@@ -88,26 +89,29 @@
         return LAST_INSERT;
     }
 
-    /**
-     * @see org.apache.ojb.broker.platforms.Platform#addPagingSql(java.lang.StringBuffer)
-     */
-    public void addPagingSql(StringBuffer anSqlString)
+
+
+    public boolean supportsLimit()
     {
-        anSqlString.insert(6, " LIMIT ? ? ");
+        return true;
     }
 
-    /**
-     * @see org.apache.ojb.broker.platforms.Platform#bindPagingParametersFirst()
-     */
-    public boolean bindPagingParametersFirst()
+    public StringBuffer addLimitSql(Query query, StringBuffer anSqlString)
+    {
+        return anSqlString.append(" LIMIT ?");
+    }
+
+    public boolean supportsOffset()
     {
         return true;
     }
 
-    /**
-     * @see org.apache.ojb.broker.platforms.Platform#supportsPaging()
-     */
-    public boolean supportsPaging()
+    public StringBuffer addPagingSql(Query query, StringBuffer anSqlString)
+    {
+        return anSqlString.append(" LIMIT ? OFFSET ?");
+    }
+
+    public boolean limitBeforeOffset()
     {
         return true;
     }
@@ -117,6 +121,8 @@
         return false;
     }
 
+
+
     public String createSequenceQuery(String sequenceName, Properties prop)
     {
         // CREATE SEQUENCE <sequencename> [AS {INTEGER | BIGINT}]
@@ -146,14 +152,6 @@
             }
         }
         return query.toString();
-    }
-
-    /**
-     * @see org.apache.ojb.broker.platforms.Platform#createSequenceQuery(java.lang.String)
-     */
-    public String createSequenceQuery(String sequenceName)
-    {
-        return "CREATE SEQUENCE " + sequenceName;
     }
 
     /**

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMckoiImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMckoiImpl.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMckoiImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMckoiImpl.java Thu Mar  1 17:33:44 2007
@@ -22,6 +22,7 @@
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.sql.Types;
+import java.util.Properties;
 
 import org.apache.ojb.broker.query.LikeCriteria;
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
@@ -92,7 +93,7 @@
     /* (non-Javadoc)
      * @see org.apache.ojb.broker.platforms.Platform#createSequenceQuery(String)
      */
-    public String createSequenceQuery(String sequenceName)
+    public String createSequenceQuery(String sequenceName, Properties prop)
     {
         return "create sequence " + sequenceName;
     }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMsSQLServerImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMsSQLServerImpl.java?view=diff&rev=513577&r1=513576&r2=513577
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMsSQLServerImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/platforms/PlatformMsSQLServerImpl.java Thu Mar  1 17:33:44 2007
@@ -21,6 +21,8 @@
 import java.sql.SQLException;
 
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
+import org.apache.ojb.broker.query.Query;
+import org.apache.commons.lang.StringUtils;
 
 /**
  * This class extends <code>PlatformDefaultImpl</code> and defines specific behavior for the
@@ -93,5 +95,71 @@
     protected String getQuotedName(String aString)
     {
         return '[' + aString + ']';
+    }
+
+
+
+    public boolean supportsLimit()
+    {
+        return true;
+    }
+
+    public StringBuffer addLimitSql(Query query, StringBuffer anSqlString)
+    {
+        /*
+         See http://troels.arvin.dk/db/rdbms/#select-top-n-standard
+         SELECT TOP 3 WITH TIES * FROM person ORDER BY age ASC
+        */
+        return new StringBuffer(StringUtils.replace(anSqlString.toString(), "SELECT", "SELECT TOP ?", 1));
+    }
+
+    public boolean supportsOffset()
+    {
+        return true;
+    }
+
+    public StringBuffer addPagingSql(Query query, StringBuffer anSqlString)
+    {
+        /*
+        See http://troels.arvin.dk/db/rdbms/#select-top-n-standard
+        SELECT * FROM (
+            SELECT TOP n * FROM (
+                SELECT TOP z columns      -- (z=n+skip)
+                FROM tablename ORDER BY key ASC)
+            AS FOO ORDER BY key DESC -- ('FOO' may be anything)
+        ) AS BAR ORDER BY key ASC    -- ('BAR' may be anything)
+        */
+        StringBuffer tmp = new StringBuffer(StringUtils.replace(
+                anSqlString.toString(), "SELECT", "SELECT * FROM ( SELECT TOP ? * FROM ( SELECT TOP ?", 1));
+        return tmp.append(") AS FOO ORDER BY key DESC ) AS BAR ORDER BY key ASC");
+    }
+
+    public int buildLimit(Query query)
+    {
+        int result = 0;
+        if(query.hasLimit())
+        {
+            return query.getEndAtIndex();
+        }
+        else if(query.hasOffset())
+        {
+            return MAX_LIMIT_VALUE;
+        }
+        return result;
+    }
+
+    public int buildOffset(Query query)
+    {
+        return super.buildOffset(query);
+    }
+
+    public boolean limitBeforeOffset()
+    {
+        return false;
+    }
+
+    public boolean limitAfterSelect()
+    {
+        return true;
     }
 }



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