3892 Frazer Clement 2012-05-29 [merge]
Merge 7.2->7.3
added:
storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/QueryLimitsTest.java
storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/QueryLimitsTest.java
modified:
storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/Query.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryDomainTypeImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryExecutionContextImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryImpl.java
storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/ScanOperation.java
storage/ndb/clusterj/clusterj-core/src/main/resources/com/mysql/clusterj/core/Bundle.properties
storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java
storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractQueryTest.java
storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterTransactionImpl.java
storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/DbImpl.java
storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordScanOperationImpl.java
storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordScanResultDataImpl.java
storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ScanOperationImpl.java
storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ScanResultDataImpl.java
storage/ndb/include/mgmapi/ndbd_exit_codes.h
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/src/kernel/error/ndbd_exit_codes.c
3891 magnus.blaudd@stripped 2012-05-23 [merge]
Merge 7.2 -> 7.3
modified:
mysql-test/suite/ndb/r/ndb_condition_pushdown.result
mysql-test/suite/ndb/t/ndb_condition_pushdown.test
sql/ha_ndbcluster_cond.cc
storage/ndb/src/common/util/SocketClient.cpp
storage/ndb/src/kernel/vm/mt.cpp
support-files/mysql.spec.sh
=== modified file 'storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/Query.java'
--- a/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/Query.java 2011-02-03 14:37:50 +0000
+++ b/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/Query.java 2012-05-23 23:51:17 +0000
@@ -103,4 +103,20 @@ public interface Query<E> {
*/
Map<String, Object> explain();
+ /**
+ * Set limits on results to return. The execution of the query is
+ * modified to return only a subset of results. If the filter would
+ * normally return 100 instances, skip is set to 50, and
+ * limit is set to 40, then the first 50 results that would have
+ * been returned are skipped, the next 40 results are returned and the
+ * remaining 10 results are ignored.
+ * <p>
+ * Skip must be greater than or equal to 0. Limit must be greater than or equal to 0.
+ * Limits may not be used with deletePersistentAll.
+ * @param skip the number of results to skip
+ * @param limit the number of results to return after skipping;
+ * use Long.MAX_VALUE for no limit.
+ */
+ void setLimits (long skip, long limit);
+
}
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryDomainTypeImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryDomainTypeImpl.java 2012-05-07 07:51:09 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryDomainTypeImpl.java 2012-05-29 17:15:08 +0000
@@ -29,6 +29,8 @@ import com.mysql.clusterj.core.spi.Query
import com.mysql.clusterj.core.spi.SessionSPI;
import com.mysql.clusterj.core.spi.ValueHandlerBatching;
+import com.mysql.clusterj.core.store.Blob;
+import com.mysql.clusterj.core.store.Column;
import com.mysql.clusterj.core.store.Index;
import com.mysql.clusterj.core.store.IndexOperation;
import com.mysql.clusterj.core.store.IndexScanOperation;
@@ -45,6 +47,8 @@ import com.mysql.clusterj.query.Predicat
import com.mysql.clusterj.query.QueryDefinition;
import com.mysql.clusterj.query.QueryDomainType;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -147,10 +151,12 @@ public class QueryDomainTypeImpl<T> impl
}
/** Query.getResultList delegates to this method.
+ * @param skip the number of rows to skip
+ * @param limit the limit of rows to return after skipping
*
* @return the results of executing the query
*/
- public List<T> getResultList(QueryExecutionContext context) {
+ public List<T> getResultList(QueryExecutionContext context, long skip, long limit) {
assertAllParametersBound(context);
SessionSPI session = context.getSession();
@@ -159,7 +165,7 @@ public class QueryDomainTypeImpl<T> impl
List<T> resultList = new ArrayList<T>();
try {
// execute the query
- ResultData resultData = getResultData(context);
+ ResultData resultData = getResultData(context, skip, limit);
// put the result data into the result list
while (resultData.next()) {
T row = session.newInstance(resultData, domainTypeHandler);
@@ -182,10 +188,12 @@ public class QueryDomainTypeImpl<T> impl
* depends on the where clause and the bound parameter values.
*
* @param context the query context, including the bound parameters
+ * @param skip the number of rows to skip
+ * @param limit the limit of rows to return after skipping
* @return the raw result data from the query
* @throws ClusterJUserException if not all parameters are bound
*/
- public ResultData getResultData(QueryExecutionContext context) {
+ public ResultData getResultData(QueryExecutionContext context, long skip, long limit) {
SessionSPI session = context.getSession();
// execute query based on what kind of scan is needed
// if no where clause, scan the entire table
@@ -204,6 +212,10 @@ public class QueryDomainTypeImpl<T> impl
switch (scanType) {
case PRIMARY_KEY: {
+ // if skipping any results or limit is zero, return no results
+ if (skip > 0 || limit < 1) {
+ return resultDataEmpty;
+ }
if (logger.isDetailEnabled()) logger.detail("Using primary key find for query.");
// perform a select operation
op = session.getSelectOperation(domainTypeHandler.getStoreTable());
@@ -238,7 +250,7 @@ public class QueryDomainTypeImpl<T> impl
where.filterCmpValue(context, (IndexScanOperation)op);
op.endDefinition();
// execute the scan and get results
- result = op.resultData();
+ result = ((ScanOperation)op).resultData(true, skip, limit);
break;
}
@@ -255,11 +267,15 @@ public class QueryDomainTypeImpl<T> impl
}
op.endDefinition();
// execute the scan and get results
- result = op.resultData();
+ result = ((ScanOperation)op).resultData(true, skip, limit);
break;
}
case UNIQUE_KEY: {
+ // if skipping any results or limit is zero, return no results
+ if (skip > 0 || limit < 1) {
+ return resultDataEmpty;
+ }
storeIndex = index.getStoreIndex();
if (logger.isDetailEnabled()) logger.detail("Using lookup with unique index " + index.getIndexName() + " for query.");
// perform a unique lookup operation
@@ -581,4 +597,184 @@ public class QueryDomainTypeImpl<T> impl
return cls;
}
+ private ResultData resultDataEmpty = new ResultData() {
+
+ public boolean next() {
+ // this ResultData has no results
+ return false;
+ }
+
+ public BigInteger getBigInteger(Column columnName) {
+ return null;
+ }
+
+ public BigInteger getBigInteger(int columnNumber) {
+ return null;
+ }
+
+ public Blob getBlob(Column storeColumn) {
+ return null;
+ }
+
+ public Blob getBlob(int columnNumber) {
+ return null;
+ }
+
+ public boolean getBoolean(Column storeColumn) {
+ return false;
+ }
+
+ public boolean getBoolean(int columnNumber) {
+ return false;
+ }
+
+ public boolean[] getBooleans(Column storeColumn) {
+ return null;
+ }
+
+ public boolean[] getBooleans(int columnNumber) {
+ return null;
+ }
+
+ public byte getByte(Column storeColumn) {
+ return 0;
+ }
+
+ public byte getByte(int columnNumber) {
+ return 0;
+ }
+
+ public byte[] getBytes(Column storeColumn) {
+ return null;
+ }
+
+ public byte[] getBytes(int columnNumber) {
+ return null;
+ }
+
+ public Column[] getColumns() {
+ return null;
+ }
+
+ public BigDecimal getDecimal(Column storeColumn) {
+ return null;
+ }
+
+ public BigDecimal getDecimal(int columnNumber) {
+ return null;
+ }
+
+ public double getDouble(Column storeColumn) {
+ return 0;
+ }
+
+ public double getDouble(int columnNumber) {
+ return 0;
+ }
+
+ public float getFloat(Column storeColumn) {
+ return 0;
+ }
+
+ public float getFloat(int columnNumber) {
+ return 0;
+ }
+
+ public int getInt(Column storeColumn) {
+ return 0;
+ }
+
+ public int getInt(int columnNumber) {
+ return 0;
+ }
+
+ public long getLong(Column storeColumn) {
+ return 0;
+ }
+
+ public long getLong(int columnNumber) {
+ return 0;
+ }
+
+ public Object getObject(Column storeColumn) {
+ return null;
+ }
+
+ public Object getObject(int column) {
+ return null;
+ }
+
+ public Boolean getObjectBoolean(Column storeColumn) {
+ return null;
+ }
+
+ public Boolean getObjectBoolean(int columnNumber) {
+ return null;
+ }
+
+ public Byte getObjectByte(Column storeColumn) {
+ return null;
+ }
+
+ public Byte getObjectByte(int columnNumber) {
+ return null;
+ }
+
+ public Double getObjectDouble(Column storeColumn) {
+ return null;
+ }
+
+ public Double getObjectDouble(int columnNumber) {
+ return null;
+ }
+
+ public Float getObjectFloat(Column storeColumn) {
+ return null;
+ }
+
+ public Float getObjectFloat(int columnNumber) {
+ return null;
+ }
+
+ public Integer getObjectInteger(Column storeColumn) {
+ return null;
+ }
+
+ public Integer getObjectInteger(int columnNumber) {
+ return null;
+ }
+
+ public Long getObjectLong(Column storeColumn) {
+ return null;
+ }
+
+ public Long getObjectLong(int columnNumber) {
+ return null;
+ }
+
+ public Short getObjectShort(Column storeColumn) {
+ return null;
+ }
+
+ public Short getObjectShort(int columnNumber) {
+ return null;
+ }
+
+ public short getShort(Column storeColumn) {
+ return 0;
+ }
+
+ public short getShort(int columnNumber) {
+ return 0;
+ }
+
+ public String getString(Column storeColumn) {
+ return null;
+ }
+
+ public String getString(int columnNumber) {
+ return null;
+ }
+
+ };
}
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryExecutionContextImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryExecutionContextImpl.java 2011-10-20 19:41:56 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryExecutionContextImpl.java 2012-05-29 17:15:08 +0000
@@ -127,7 +127,8 @@ public class QueryExecutionContextImpl i
}
public ResultData getResultData(QueryDomainType<?> queryDomainType) {
- return ((QueryDomainTypeImpl<?>)queryDomainType).getResultData(this);
+ // TODO handle skip and limit
+ return ((QueryDomainTypeImpl<?>)queryDomainType).getResultData(this, 0, Long.MAX_VALUE);
}
/** Add a filter to the list of filters created for this query.
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryImpl.java 2011-02-03 14:37:50 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/query/QueryImpl.java 2012-05-23 23:51:17 +0000
@@ -18,6 +18,7 @@
package com.mysql.clusterj.core.query;
+import com.mysql.clusterj.ClusterJUserException;
import com.mysql.clusterj.Results;
import com.mysql.clusterj.core.*;
import com.mysql.clusterj.Query;
@@ -45,12 +46,49 @@ public class QueryImpl<E> implements Que
/** My query execution context. */
protected QueryExecutionContextImpl context = null;
+ /** The number to skip */
+ protected long skip = 0;
+
+ /** The limit */
+ protected long limit = Long.MAX_VALUE;
+
public QueryImpl(SessionImpl session, QueryDomainTypeImpl<E> dobj) {
this.session = session;
context = new QueryExecutionContextImpl(session);
this.dobj = dobj;
}
+ /**
+ * Set limits on results to return. The execution of the query is
+ * modified to return only a subset of results. If the filter would
+ * normally return 100 instances, skip is set to 50, and
+ * limit is set to 40, then the first 50 results that would have
+ * been returned are skipped, the next 40 results are returned and the
+ * remaining 10 results are ignored.
+ * <p>
+ * Skip must be greater than or equal to 0. Limit must be greater than or equal to 0.
+ * Limits may not be used with deletePersistentAll.
+ * <p>
+ * The limits as specified by the user are converted here into an internal form
+ * where the limit is the last record to deliver instead of the number of records
+ * to deliver. So if the user specifies limits of (10, 20) we convert this
+ * to limits of (10, 30) for the lower layers of the implementation.
+ * @param skip the number of results to skip
+ * @param limit the number of results to return after skipping;
+ * use Long.MAX_VALUE for no limit.
+ */
+ public void setLimits(long skip, long limit) {
+ if (skip < 0 || limit < 0) {
+ throw new ClusterJUserException(local.message("ERR_Invalid_Limits", skip, limit));
+ }
+ this.skip = skip;
+ if (Long.MAX_VALUE - skip < limit) {
+ limit = Long.MAX_VALUE;
+ } else {
+ this.limit = limit + skip;
+ }
+ }
+
public Results<E> execute(Object arg0) {
throw new UnsupportedOperationException(
local.message("ERR_NotImplemented"));
@@ -71,7 +109,7 @@ public class QueryImpl<E> implements Que
}
public List<E> getResultList() {
- List<E> results = dobj.getResultList(context);
+ List<E> results = dobj.getResultList(context, skip, limit);
// create new context, copying the parameters, for another execution
context = new QueryExecutionContextImpl(context);
return results;
@@ -81,6 +119,9 @@ public class QueryImpl<E> implements Que
* @return the number of instances deleted
*/
public int deletePersistentAll() {
+ if (skip != 0 || limit != Long.MAX_VALUE) {
+ throw new ClusterJUserException(local.message("ERR_Invalid_Limits", skip, limit));
+ }
int result = dobj.deletePersistentAll(context);
return result;
}
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/ScanOperation.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/ScanOperation.java 2011-07-05 12:46:07 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/ScanOperation.java 2012-05-29 17:15:08 +0000
@@ -32,4 +32,6 @@ public interface ScanOperation extends O
public int nextResult(boolean fetch);
+ public ResultData resultData(boolean execute, long skip, long limit);
+
}
=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/resources/com/mysql/clusterj/core/Bundle.properties'
--- a/storage/ndb/clusterj/clusterj-core/src/main/resources/com/mysql/clusterj/core/Bundle.properties 2011-12-29 14:39:37 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/resources/com/mysql/clusterj/core/Bundle.properties 2012-05-23 23:51:17 +0000
@@ -138,3 +138,5 @@ either an array of Object types or a Lis
ERR_Parameter_Too_Big_For_In:For field ''{0}'', the parameter of length {1} for query operator ''in'' \
is too big; it must contain fewer than 4097 items.
MSG_Removing_Schema:Removing schema {0} after failure to initialize domain type handler for class {1}.
+ERR_Invalid_Limits:The limits {0}, {1} are invalid: the first parameter must be greater than or equal to zero; \
+the second parameter must be greater than or equal to zero; and limits cannot be applied to delete.
=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java 2011-11-22 22:53:33 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java 2012-05-23 23:51:17 +0000
@@ -186,7 +186,8 @@ public class SQLExecutor {
session.startAutoTransaction();
try {
valueHandlerBatching.next();
- ResultData resultData = queryDomainType.getResultData(context);
+ // TODO get skip and limit from the SQL query
+ ResultData resultData = queryDomainType.getResultData(context, 0, Long.MAX_VALUE);
// session.endAutoTransaction();
return new ResultSetInternalMethodsImpl(resultData, columnNumberToFieldNumberMap,
columnNameToFieldNumberMap, session);
=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractQueryTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractQueryTest.java 2012-04-15 03:43:47 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractQueryTest.java 2012-05-23 23:51:17 +0000
@@ -58,6 +58,12 @@ abstract public class AbstractQueryTest
private boolean autotransaction;
+ /** The lower limit (number of returned rows to skip) */
+ protected Long skip = null;
+
+ /** The upper limit (number of rows to return) */
+ protected Long limit = null;
+
@Override
public void localSetUp() {
setAutotransaction(false);
@@ -76,6 +82,16 @@ abstract public class AbstractQueryTest
autotransaction = b;
}
+ protected void setLimit(long limit) {
+ this.skip = null;
+ this.limit = limit;
+ }
+
+ protected void setLimits(long skip, long limit) {
+ this.skip = skip;
+ this.limit = limit;
+ }
+
class QueryHolder {
public QueryBuilder builder;
public QueryDomainType<?> dobj;
@@ -246,6 +262,13 @@ abstract public class AbstractQueryTest
@SuppressWarnings("unchecked")
public void checkResults(String theQuery) {
+ if (limit != null) {
+ if (skip != null) {
+ query.setLimits(skip, limit);
+ } else {
+ query.setLimits(0, limit);
+ }
+ }
Set<Integer> actualSet = new HashSet<Integer>();
List<IdBase> resultList = (List<IdBase>) query.getResultList();
for (IdBase result: resultList) {
@@ -259,6 +282,13 @@ abstract public class AbstractQueryTest
}
public void checkDeletePersistentAll(String where, int expectedNumberOfDeletedInstances) {
+ if (limit != null) {
+ if (skip != null) {
+ query.setLimits(skip, limit);
+ } else {
+ query.setLimits(0, limit);
+ }
+ }
int result = query.deletePersistentAll();
errorIfNotEqual("Wrong index used for " + where + " delete query: ",
expectedIndex, query.explain().get("IndexUsed"));
=== added file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/QueryLimitsTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/QueryLimitsTest.java 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/QueryLimitsTest.java 2012-05-23 23:51:17 +0000
@@ -0,0 +1,168 @@
+/*
+Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+package testsuite.clusterj;
+
+import com.mysql.clusterj.ClusterJUserException;
+
+import testsuite.clusterj.model.AllPrimitives;
+
+/** Query for limits used to skip query results and limit the number
+ * of results returned.
+ */
+public class QueryLimitsTest extends AbstractQueryTest {
+ /*
+ drop table if exists allprimitives;
+ create table allprimitives (
+ id int not null primary key,
+
+ int_not_null_hash int not null,
+ int_not_null_btree int not null,
+ int_not_null_both int not null,
+ int_not_null_none int not null,
+ int_null_hash int,
+ int_null_btree int,
+ int_null_both int,
+ int_null_none int,
+
+ byte_not_null_hash tinyint not null,
+ byte_not_null_btree tinyint not null,
+ byte_not_null_both tinyint not null,
+ byte_not_null_none tinyint not null,
+ byte_null_hash tinyint,
+ byte_null_btree tinyint,
+ byte_null_both tinyint,
+ byte_null_none tinyint,
+
+ short_not_null_hash smallint not null,
+ short_not_null_btree smallint not null,
+ short_not_null_both smallint not null,
+ short_not_null_none smallint not null,
+ short_null_hash smallint,
+ short_null_btree smallint,
+ short_null_both smallint,
+ short_null_none smallint,
+
+ long_not_null_hash bigint not null,
+ long_not_null_btree bigint not null,
+ long_not_null_both bigint not null,
+ long_not_null_none bigint not null,
+ long_null_hash bigint,
+ long_null_btree bigint,
+ long_null_both bigint,
+ long_null_none bigint
+ */
+
+ @Override
+ public Class<?> getInstanceType() {
+ return AllPrimitives.class;
+ }
+
+ @Override
+ void createInstances(int number) {
+ createAllPrimitivesInstances(10);
+ }
+
+ public void test() {
+ setLimits(1, 2);
+ inQuery("int_not_null_both", new Object[] {4, 6, 9}, "idx_int_not_null_both", 6, 9);
+ setLimits(1, 2);
+ inQuery("int_not_null_btree", new Object[] {4, 6, 9}, "idx_int_not_null_btree", 6, 9);
+ setLimits(1, 0);
+ equalQuery("int_not_null_btree", "idx_int_not_null_btree", 8);
+ setLimits(1, Long.MAX_VALUE);
+ greaterEqualQuery("int_not_null_btree", "idx_int_not_null_btree", 7, 8, 9);
+ setLimits(1, 2);
+ greaterThanQuery("int_not_null_btree", "idx_int_not_null_btree", 6, 8, 9);
+ setLimits(2, 2);
+ lessEqualQuery("int_not_null_btree", "idx_int_not_null_btree", 4, 2, 3);
+ setLimits(1, 2);
+ lessThanQuery("int_not_null_btree", "idx_int_not_null_btree", 4, 1, 2);
+ setLimits(1, 2);
+ betweenQuery("int_not_null_btree", "idx_int_not_null_btree", 4, 6, 5, 6);
+ setLimits(0, 3);
+ equalQuery("int_not_null_hash", "idx_int_not_null_hash", 8, 8);
+ setLimits(1, 2);
+ equalQuery("int_not_null_both", "idx_int_not_null_both", 8);
+ setLimits(1, 2);
+ greaterEqualQuery("int_not_null_both", "idx_int_not_null_both", 7, 8, 9);
+ setLimits(1, 2);
+ greaterThanQuery("int_not_null_both", "idx_int_not_null_both", 6, 8, 9);
+ setLimits(1, 2);
+ lessEqualQuery("int_not_null_both", "idx_int_not_null_both", 4, 1, 2);
+ setLimits(1, 2);
+ lessThanQuery("int_not_null_both", "idx_int_not_null_both", 4, 1, 2);
+ setLimits(1, 2);
+ betweenQuery("int_not_null_both", "idx_int_not_null_both", 4, 6, 5, 6);
+ setLimits(1, 2);
+ equalQuery("int_not_null_none", "none", 8);
+ setLimits(0, 0);
+ equalQuery("int_not_null_none", "none", 8);
+ setLimits(1, 0);
+ equalQuery("int_not_null_none", "none", 8);
+ failOnError();
+ }
+
+ public void testNegative() {
+ if (session.currentTransaction().isActive()) {
+ session.currentTransaction().rollback();
+ }
+ try {
+ // bad limit; first parameter must be greater than or equal to zero
+ setLimits(-1, 1);
+ equalQuery("int_not_null_none", "none", 8);
+ error("Bad limit (-1, 1) should fail.");
+ } catch (ClusterJUserException ex) {
+ // good catch
+ }
+ if (session.currentTransaction().isActive()) {
+ session.currentTransaction().rollback();
+ }
+ try {
+ // bad limit; second parameter must be greater than or equal to zero
+ setLimits(1, -1);
+ equalQuery("int_not_null_none", "none", 8);
+ error("Bad limit (1, -1) should fail.");
+ } catch (ClusterJUserException ex) {
+ // good catch
+ }
+ if (session.currentTransaction().isActive()) {
+ session.currentTransaction().rollback();
+ }
+ try {
+ // bad limit; cannot use limits for delete operations
+ setLimits(0, 1);
+ deleteEqualQuery("int_not_null_none", "none", 8, 1);
+ error("Bad limit for delete should fail.");
+ } catch (ClusterJUserException ex) {
+ // good catch
+ }
+ if (session.currentTransaction().isActive()) {
+ session.currentTransaction().rollback();
+ }
+ try {
+ // bad limit; cannot use limits for delete operations
+ setLimits(1, 1);
+ deleteEqualQuery("int_not_null_none", "none", 8, 1);
+ error("Bad limit for delete should fail.");
+ } catch (ClusterJUserException ex) {
+ // good catch
+ }
+ failOnError();
+ }
+
+}
=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterTransactionImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterTransactionImpl.java 2012-04-02 20:43:14 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterTransactionImpl.java 2012-05-24 06:39:40 +0000
@@ -273,10 +273,10 @@ class ClusterTransactionImpl implements
handleError(ndbIndex, ndbDictionary);
NdbIndexScanOperation ndbOperation = ndbTransaction.getNdbIndexScanOperation(ndbIndex);
handleError(ndbOperation, ndbTransaction);
- int scanFlags = 0;
+ int scanFlags = ScanFlag.SF_OrderBy;
int lockMode = indexScanLockMode;
if (lockMode != com.mysql.ndbjtie.ndbapi.NdbOperationConst.LockMode.LM_CommittedRead) {
- scanFlags = ScanFlag.SF_KeyInfo;
+ scanFlags |= ScanFlag.SF_KeyInfo;
}
scanFlags |= ScanFlag.SF_MultiRange;
int parallel = 0;
=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/DbImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/DbImpl.java 2012-05-17 01:36:46 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/DbImpl.java 2012-05-23 23:51:17 +0000
@@ -431,9 +431,9 @@ class DbImpl implements com.mysql.cluste
IndexBound.delete(ndbIndexBound);
}
- public NdbInterpretedCode createInterpretedCode(TableConst ndbTable, ByteBuffer buffer, int i) {
+ public NdbInterpretedCode createInterpretedCode(TableConst ndbTable, int i) {
++numberOfInterpretedCodeCreated;
- return NdbInterpretedCode.create(ndbTable, buffer, i);
+ return NdbInterpretedCode.create(ndbTable, null, i);
}
public void delete(NdbInterpretedCode ndbInterpretedCode) {
=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordScanOperationImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordScanOperationImpl.java 2012-05-06 13:55:09 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordScanOperationImpl.java 2012-05-24 13:50:07 +0000
@@ -69,8 +69,14 @@ public abstract class NdbRecordScanOpera
*/
@Override
public ResultData resultData(boolean execute) {
+ return resultData(execute, 0, Long.MAX_VALUE);
+ }
+
+ /** Construct a new ResultData and if requested, execute the operation.
+ */
+ public ResultData resultData(boolean execute, long skip, long limit) {
NdbRecordResultDataImpl result =
- new NdbRecordScanResultDataImpl(this);
+ new NdbRecordScanResultDataImpl(this, skip, limit);
if (execute) {
clusterTransaction.executeNoCommit(false, true);
}
@@ -111,31 +117,24 @@ public abstract class NdbRecordScanOpera
/** Create scan options for this scan.
* Scan options are used to set a filter into the NdbScanOperation,
* set the key info flag if using a lock mode that requires lock takeover, and set the multi range flag.
+ * always set SF_OrderBy to get ordered scans.
*/
protected void getScanOptions() {
- long options = 0L;
- int flags = 0;
- if (multiRange | (ndbScanFilter != null) |
- (lockMode != com.mysql.ndbjtie.ndbapi.NdbOperationConst.LockMode.LM_CommittedRead)) {
-
- scanOptions = db.createScanOptions();
- if (multiRange) {
- flags |= ScanFlag.SF_MultiRange;
- options |= (long)Type.SO_SCANFLAGS;
- scanOptions.scan_flags(flags);
- }
- if (lockMode != com.mysql.ndbjtie.ndbapi.NdbOperationConst.LockMode.LM_CommittedRead) {
- flags |= ScanFlag.SF_KeyInfo;
- options |= (long)Type.SO_SCANFLAGS;
- scanOptions.scan_flags(flags);
- }
- if (ndbScanFilter != null) {
- options |= (long)Type.SO_INTERPRETED;
- scanOptions.interpretedCode(ndbScanFilter.getInterpretedCode());
- }
-
- scanOptions.optionsPresent(options);
+ long options = (long)Type.SO_SCANFLAGS;
+ int flags = ScanFlag.SF_OrderBy;
+ scanOptions = db.createScanOptions();
+ if (multiRange) {
+ flags |= ScanFlag.SF_MultiRange;
+ }
+ if (lockMode != com.mysql.ndbjtie.ndbapi.NdbOperationConst.LockMode.LM_CommittedRead) {
+ flags |= ScanFlag.SF_KeyInfo;
+ }
+ if (ndbScanFilter != null) {
+ options |= (long)Type.SO_INTERPRETED;
+ scanOptions.interpretedCode(ndbScanFilter.getInterpretedCode());
}
+ scanOptions.scan_flags(flags);
+ scanOptions.optionsPresent(options);
if (logger.isDebugEnabled()) logger.debug("ScanOptions: " + dumpScanOptions(options, flags));
}
@@ -167,7 +166,7 @@ public abstract class NdbRecordScanOpera
*/
public ScanFilter getScanFilter(QueryExecutionContext context) {
- ndbInterpretedCode = db.createInterpretedCode(ndbRecordValues.getNdbTable(), null, 0);
+ ndbInterpretedCode = db.createInterpretedCode(ndbRecordValues.getNdbTable(), 0);
handleError(ndbInterpretedCode, ndbOperation);
ndbScanFilter = db.createScanFilter(ndbInterpretedCode);
handleError(ndbScanFilter, ndbOperation);
=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordScanResultDataImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordScanResultDataImpl.java 2012-04-02 20:43:14 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordScanResultDataImpl.java 2012-05-23 23:51:17 +0000
@@ -47,19 +47,37 @@ class NdbRecordScanResultDataImpl extend
/** The NdbScanOperation */
private NdbScanOperation ndbScanOperation = null;
+ /** The number to skip */
+ protected long skip = 0;
+
+ /** The limit */
+ protected long limit = Long.MAX_VALUE;
+
+ /** The record counter during the scan */
+ protected long recordCounter = 0;
+
/** Construct the ResultDataImpl based on an NdbRecordOperationImpl.
* When used with the compatibility operations, delegate to the NdbRecordOperation
* to copy data.
* @param operation the NdbRecordOperationImpl
+ * @param skip the number of rows to skip
+ * @param limit the last row number
*/
- public NdbRecordScanResultDataImpl(NdbRecordScanOperationImpl scanOperation) {
+ public NdbRecordScanResultDataImpl(NdbRecordScanOperationImpl scanOperation, long skip, long limit) {
super(scanOperation);
this.scanOperation = scanOperation;
this.ndbScanOperation = (NdbScanOperation)scanOperation.ndbOperation;
+ this.skip = skip;
+ this.limit = limit;
}
@Override
public boolean next() {
+ if (recordCounter >= limit) {
+ // the next record is past the limit; we have delivered all the rows
+ ndbScanOperation.close(true, true);
+ return false;
+ }
// NdbScanOperation may have many results.
boolean done = false;
boolean fetch = false;
@@ -68,9 +86,15 @@ class NdbRecordScanResultDataImpl extend
int result = scanOperation.nextResultCopyOut(fetch, force);
switch (result) {
case RESULT_READY:
- // if scanning with locks, grab the lock for the current transaction
- scanOperation.lockCurrentTuple();
- return true;
+ if (++recordCounter > skip) {
+ // this record is past the skip
+ // if scanning with locks, grab the lock for the current transaction
+ scanOperation.lockCurrentTuple();
+ return true;
+ } else {
+ // skip this record
+ break;
+ }
case SCAN_FINISHED:
ndbScanOperation.close(true, true);
return false;
=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ScanOperationImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ScanOperationImpl.java 2011-07-05 12:46:07 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ScanOperationImpl.java 2012-05-29 17:15:08 +0000
@@ -66,8 +66,12 @@ class ScanOperationImpl extends Operatio
@Override
public ResultData resultData() {
+ return resultData(true, 0, Long.MAX_VALUE);
+ }
+
+ public ResultData resultData(boolean execute, long skip, long limit) {
ResultData result = new ScanResultDataImpl(ndbScanOperation, storeColumns,
- maximumColumnId, bufferSize, offsets, lengths, maximumColumnLength, bufferManager);
+ maximumColumnId, bufferSize, offsets, lengths, maximumColumnLength, bufferManager, skip, limit);
clusterTransaction.executeNoCommit(false, true);
return result;
}
=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ScanResultDataImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ScanResultDataImpl.java 2012-04-02 20:43:14 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ScanResultDataImpl.java 2012-05-23 23:51:17 +0000
@@ -44,6 +44,14 @@ class ScanResultDataImpl extends ResultD
private NdbScanOperation ndbScanOperation = null;
+ /** The number to skip */
+ protected long skip = 0;
+
+ /** The limit */
+ protected long limit = Long.MAX_VALUE;
+
+ /** The record counter during the scan */
+ protected long recordCounter = 0;
/** Flags for iterating a scan */
protected final int RESULT_READY = 0;
@@ -52,14 +60,21 @@ class ScanResultDataImpl extends ResultD
public ScanResultDataImpl(NdbScanOperation ndbScanOperation, List<Column> storeColumns,
int maximumColumnId, int bufferSize, int[] offsets, int[] lengths, int maximumColumnLength,
- BufferManager bufferManager) {
+ BufferManager bufferManager, long skip, long limit) {
super(ndbScanOperation, storeColumns, maximumColumnId, bufferSize, offsets, lengths,
bufferManager, false);
this.ndbScanOperation = ndbScanOperation;
+ this.skip = skip;
+ this.limit = limit;
}
@Override
public boolean next() {
+ if (recordCounter >= limit) {
+ // the next record is past the limit; we have delivered all the rows
+ ndbScanOperation.close(true, true);
+ return false;
+ }
// NdbScanOperation may have many results.
boolean done = false;
boolean fetch = false;
@@ -68,10 +83,17 @@ class ScanResultDataImpl extends ResultD
int result = ndbScanOperation.nextResult(fetch, force);
switch (result) {
case RESULT_READY:
- if (ndbScanOperation.getLockMode() != LockMode.LM_CommittedRead) {
- ndbScanOperation.lockCurrentTuple();
+ if (++recordCounter > skip) {
+ // this record is past the skip
+ // if scanning with locks, grab the lock for the current transaction
+ if (ndbScanOperation.getLockMode() != LockMode.LM_CommittedRead) {
+ ndbScanOperation.lockCurrentTuple();
+ }
+ return true;
+ } else {
+ // skip this record
+ break;
}
- return true;
case SCAN_FINISHED:
ndbScanOperation.close(true, true);
return false;
=== added file 'storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/QueryLimitsTest.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/QueryLimitsTest.java 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/QueryLimitsTest.java 2012-05-23 23:51:17 +0000
@@ -0,0 +1,22 @@
+/*
+ Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package testsuite.clusterj.tie;
+
+public class QueryLimitsTest extends testsuite.clusterj.QueryLimitsTest {
+
+}
=== modified file 'storage/ndb/include/mgmapi/ndbd_exit_codes.h'
--- a/storage/ndb/include/mgmapi/ndbd_exit_codes.h 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/include/mgmapi/ndbd_exit_codes.h 2012-05-29 17:04:36 +0000
@@ -129,7 +129,7 @@ typedef ndbd_exit_classification_enum nd
/* TUP 6800-> */
#define NDBD_EXIT_SR_OUT_OF_DATAMEMORY 6800
/* LQH 7200-> */
-
+#define NDBD_EXIT_LCP_SCAN_WATCHDOG_FAIL 7200
/* Errorcodes for NDB filesystem */
#define NDBD_EXIT_AFS_NOPATH 2801
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2012-05-21 23:05:17 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp 2012-05-29 17:15:08 +0000
@@ -23507,7 +23507,7 @@ Dblqh::execDUMP_STATE_ORD(Signal* signal
{
CRASH_INSERTION(5075);
- progError(__LINE__, NDBD_EXIT_SYSTEM_ERROR,
+ progError(__LINE__, NDBD_EXIT_LCP_SCAN_WATCHDOG_FAIL,
"Please report this as a bug. "
"Provide as much info as possible, expecially all the "
"ndb_*_out.log files, Thanks. "
=== modified file 'storage/ndb/src/kernel/error/ndbd_exit_codes.c'
--- a/storage/ndb/src/kernel/error/ndbd_exit_codes.c 2011-10-20 13:01:37 +0000
+++ b/storage/ndb/src/kernel/error/ndbd_exit_codes.c 2012-05-29 17:04:36 +0000
@@ -144,6 +144,10 @@ static const ErrStruct errArray[] =
{NDBD_EXIT_SR_OUT_OF_DATAMEMORY, XCR,
"Out of data memory during system restart, please increase DataMemory"},
+ /* LQH */
+ {NDBD_EXIT_LCP_SCAN_WATCHDOG_FAIL, XIE,
+ "LCP fragment scan watchdog detected a problem. Please report a bug."},
+
/* Ndbfs error messages */
/* Most codes will have additional info, such as OS error code */
{NDBD_EXIT_AFS_NOPATH, XIE, "No file system path"},
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.5-cluster-7.3 branch (frazer.clement:3891 to 3892) | Frazer Clement | 29 May |