This commit makes the framework dependent on the Content component.

-Adrian

On 12/15/2012 11:20 AM, jler...@apache.org wrote:
Author: jleroux
Date: Sat Dec 15 11:20:13 2012
New Revision: 1422221

URL: http://svn.apache.org/viewvc?rev=1422221&view=rev
Log:
A patch from Shi Jinghai for "Support MySQL and Postgres's LIMIT and OFFSET 
options" https://issues.apache.org/jira/browse/OFBIZ-4346

Change the existing code to support the different syntax variations, and add an 
attribute to the datasource element in the entityengine.xml file so that the 
proper variation can be chosen for each database.
Inspired by Moqui code. Test successful

Modified:
     ofbiz/trunk/framework/entity/dtd/entity-config.xsd
     
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/config/DatasourceInfo.java
     
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java
     ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
     
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityFindOptions.java

Modified: ofbiz/trunk/framework/entity/dtd/entity-config.xsd
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/dtd/entity-config.xsd?rev=1422221&r1=1422220&r2=1422221&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/dtd/entity-config.xsd (original)
+++ ofbiz/trunk/framework/entity/dtd/entity-config.xsd Sat Dec 15 11:20:13 2012
@@ -399,6 +399,15 @@ under the License.
                  </xs:restriction>
              </xs:simpleType>
          </xs:attribute>
+        <xs:attribute name="offset-style" default="none">
+            <xs:simpleType>
+                <xs:restriction base="xs:token">
+                    <xs:enumeration value="none"/>
+                    <xs:enumeration value="fetch"/>
+                    <xs:enumeration value="limit"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
          <xs:attribute type="xs:string" name="table-type"/>
          <xs:attribute type="xs:string" name="character-set"/>
          <xs:attribute type="xs:string" name="collate"/>

Modified: 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/config/DatasourceInfo.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/config/DatasourceInfo.java?rev=1422221&r1=1422220&r2=1422221&view=diff
==============================================================================
--- 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/config/DatasourceInfo.java 
(original)
+++ 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/config/DatasourceInfo.java 
Sat Dec 15 11:20:13 2012
@@ -72,6 +72,7 @@ public class DatasourceInfo extends Name
      public boolean dropFkUseForeignKeyKeyword = false;
      public boolean useBinaryTypeForBlob = false;
      public boolean useOrderByNulls = false;
+    public String offsetStyle = null;
      public String tableType = null;
      public String characterSet = null;
      public String collate = null;
@@ -158,7 +159,8 @@ public class DatasourceInfo extends Name
              this.dropFkUseForeignKeyKeyword = 
"true".equals(datasourceElement.getAttribute("drop-fk-use-foreign-key-keyword"));
              this.useBinaryTypeForBlob = 
"true".equals(datasourceElement.getAttribute("use-binary-type-for-blob"));
              this.useOrderByNulls = 
"true".equals(datasourceElement.getAttribute("use-order-by-nulls"));
-
+
+            this.offsetStyle = datasourceElement.getAttribute("offset-style");
              this.tableType = datasourceElement.getAttribute("table-type");
              this.characterSet = 
datasourceElement.getAttribute("character-set");
              this.collate = datasourceElement.getAttribute("collate");

Modified: 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java?rev=1422221&r1=1422220&r2=1422221&view=diff
==============================================================================
--- 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java 
(original)
+++ 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java 
Sat Dec 15 11:20:13 2012
@@ -763,6 +763,9 @@ public class GenericDAO {
          }
          sqlBuffer.append(SqlJdbcUtil.makeOrderByClause(modelEntity, 
orderByExpanded, datasourceInfo));
+ // OFFSET clause
+        makeOffsetString(sqlBuffer, findOptions);
+
          // make the final SQL String
          String sql = sqlBuffer.toString();
@@ -884,6 +887,29 @@ public class GenericDAO {
          return havingString;
      }
+ protected StringBuilder makeOffsetString(StringBuilder offsetString, EntityFindOptions findOptions) {
+        if (UtilValidate.isNotEmpty(datasourceInfo.offsetStyle)) {
+            if (datasourceInfo.offsetStyle.equals("limit")) {
+                // use the LIMIT/OFFSET style
+                if (findOptions.getLimit() > -1) {
+                    offsetString.append(" LIMIT " + findOptions.getLimit());
+                    if (findOptions.getOffset() > -1) {
+                        offsetString.append(" OFFSET " + 
findOptions.getOffset());
+                    }
+                }
+            } else if (datasourceInfo.offsetStyle.equals("fetch")) {
+                // use SQL2008 OFFSET/FETCH style by default
+                if (findOptions.getOffset() > -1) {
+                    offsetString.append(" OFFSET 
").append(findOptions.getOffset()).append(" ROWS");
+                    if (findOptions.getLimit() > -1) {
+                        offsetString.append(" FETCH FIRST 
").append(findOptions.getLimit()).append(" ROWS ONLY");
+                    }
+                }
+            }
+        }
+        return offsetString;
+    }
+
      public List<GenericValue> selectByMultiRelation(GenericValue value, 
ModelRelation modelRelationOne, ModelEntity modelEntityOne,
          ModelRelation modelRelationTwo, ModelEntity modelEntityTwo, 
List<String> orderBy) throws GenericEntityException {
          SQLProcessor sqlP = new SQLProcessor(helperInfo);

Modified: 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java?rev=1422221&r1=1422220&r2=1422221&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java 
(original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java 
Sat Dec 15 11:20:13 2012
@@ -31,6 +31,7 @@ import java.util.Map;
  import org.ofbiz.base.util.Debug;
  import org.ofbiz.base.util.UtilDateTime;
  import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilValidate;
  import org.ofbiz.base.util.UtilXml;
  import org.ofbiz.entity.Delegator;
  import org.ofbiz.entity.DelegatorFactory;
@@ -44,6 +45,8 @@ import org.ofbiz.entity.condition.Entity
  import org.ofbiz.entity.condition.EntityOperator;
  import org.ofbiz.entity.config.DatasourceInfo;
  import org.ofbiz.entity.config.EntityConfigUtil;
+import org.ofbiz.entity.datasource.GenericHelperDAO;
+import org.ofbiz.entity.model.ModelEntity;
  import org.ofbiz.entity.testtools.EntityTestCase;
  import org.ofbiz.entity.transaction.GenericTransactionException;
  import org.ofbiz.entity.transaction.TransactionUtil;
@@ -604,4 +607,94 @@ public class EntityTestSuite extends Ent
          strBufTemp.append(iNum);
          return strBufTemp.toString();
      }
+
+    /*
+     * This test will verify that the LIMIT and OFFSET options can work 
properly.
+     */
+    public void testLimitOffsetOptions() throws Exception {
+        String entityName = "Content";
+        DatasourceInfo datasourceInfo = 
EntityConfigUtil.getDatasourceInfo(delegator.getEntityHelper(entityName).getHelperName());
+        if (UtilValidate.isEmpty(datasourceInfo.offsetStyle) || 
datasourceInfo.offsetStyle.equals("none")) {
+            Debug.logInfo("The offset-stype configured in datasource is " + 
datasourceInfo.offsetStyle +  ", this test is skipped.", module);
+            return;
+        } else {
+            Debug.logInfo("The offset-stype configured in datasource is " + 
datasourceInfo.offsetStyle +  ".", module);
+        }
+        try {
+            EntityFindOptions findOptions = new EntityFindOptions();
+            long count = delegator.findCountByCondition("Content", null, null, 
null);
+            Debug.logInfo("Content entity has " + count + " rows", module);
+            int rowsPerPage = 10;
+            // use rows/page as limit option
+            findOptions.setLimit(rowsPerPage);
+            int pages = (int) count/rowsPerPage;
+            if (count > pages * rowsPerPage) {
+                pages += 1;
+            }
+            Debug.logInfo("These rows will be displayed in " + pages + " pages, each page has 
" + rowsPerPage + " rows.", module);
+            ModelEntity modelEntity = delegator.getModelEntity(entityName);
+
+            long start = UtilDateTime.nowTimestamp().getTime();
+            for (int page = 1; page <= pages; page++) {
+                Debug.logInfo("Page " + page + ":", module);
+                // set offset option
+                findOptions.setOffset((page - 1) * rowsPerPage);
+                EntityListIterator iterator = null;
+                try {
+                    iterator = 
delegator.getEntityHelper(entityName).findListIteratorByCondition(modelEntity, null, 
null, null, UtilMisc.toList("lastUpdatedStamp DESC"), findOptions);
+                    while (iterator != null) {
+                        GenericValue gv = iterator.next();
+                        if (gv == null) {
+                            break;
+                        }
+                        Debug.logInfo(gv.getString("contentId") + ": " + gv.getString("contentName") + 
"       (updated: " + gv.getTimestamp("lastUpdatedStamp") + ")", module);
+                    }
+                } catch (GenericEntityException e) {
+                    Debug.logError(e, module);
+                } finally {
+                    if (iterator != null) {
+                        iterator.close();
+                    }
+                }
+            }
+            long end = UtilDateTime.nowTimestamp().getTime();
+            long time1 = end - start;
+            Debug.logInfo("Time consumed WITH limit and offset option (ms): " 
+ time1, module);
+
+            start = UtilDateTime.nowTimestamp().getTime();
+            for (int page = 1; page <= pages; page++) {
+                Debug.logInfo("Page " + page + ":", module);
+                EntityListIterator iterator = null;
+                try {
+                    iterator = ((GenericHelperDAO) 
delegator.getEntityHelper(entityName)).findListIteratorByCondition(modelEntity, null, 
null, null, UtilMisc.toList("lastUpdatedStamp DESC"), null);
+                    if (iterator == null) {
+                        continue;
+                    }
+                    iterator.setDelegator(delegator);
+                    List<GenericValue> gvs = iterator.getCompleteList();
+                    int fromIndex = (page - 1) * rowsPerPage;
+                    int toIndex = fromIndex + rowsPerPage;
+                    if (toIndex > count) {
+                        toIndex = (int) count;
+                    }
+                    gvs = gvs.subList(fromIndex, toIndex);
+                    for (GenericValue gv : gvs) {
+                        Debug.logInfo(gv.getString("contentId") + ": " + gv.getString("contentName") + 
"       (updated: " + gv.getTimestamp("lastUpdatedStamp") + ")", module);
+                    }
+                } catch (GenericEntityException e) {
+                    Debug.logError(e, module);
+                } finally {
+                    if (iterator != null) {
+                        iterator.close();
+                    }
+                }
+            }
+            end = UtilDateTime.nowTimestamp().getTime();
+            long time2 = end - start;
+            Debug.logInfo("Time consumed WITHOUT limit and offset option (ms): 
" + time2, module);
+            Debug.logInfo("Time saved (ms): " + (time2 - time1), module);
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+    }
  }

Modified: 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityFindOptions.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityFindOptions.java?rev=1422221&r1=1422220&r2=1422221&view=diff
==============================================================================
--- 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityFindOptions.java 
(original)
+++ 
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/EntityFindOptions.java 
Sat Dec 15 11:20:13 2012
@@ -48,6 +48,12 @@ public class EntityFindOptions implement
      protected int maxRows = -1;
      protected boolean distinct = false;
+ /** LIMIT option */
+    protected int limit = -1;
+
+    /** OFFSET option */
+    protected int offset = -1;
+
      /** Default constructor. Defaults are as follows:
       *      specifyTypeAndConcur = true
       *      resultSetType = TYPE_FORWARD_ONLY
@@ -145,4 +151,25 @@ public class EntityFindOptions implement
      public void setDistinct(boolean distinct) {
          this.distinct = distinct;
      }
+
+
+    /** Get the LIMIT number. */
+    public int getLimit() {
+        return limit;
+    }
+
+    /** Specifies the LIMIT number. */
+    public void setLimit(int limit) {
+        this.limit = limit;
+    }
+
+    /** Get the OFFSET number. */
+    public int getOffset() {
+        return offset;
+    }
+
+    /** Specifies the OFFSET number. */
+    public void setOffset(int offset) {
+        this.offset = offset;
+    }
  }



Reply via email to