You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/07/07 19:58:32 UTC
[1/5] incubator-calcite git commit: [CALCITE-280] BigDecimal
underflow (Li Yang)
Repository: incubator-calcite
Updated Branches:
refs/heads/master 8774a671f -> 03111d2b6
[CALCITE-280] BigDecimal underflow (Li Yang)
Fix by Li Yang, test case by Julian Hyde.
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/e39911ed
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/e39911ed
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/e39911ed
Branch: refs/heads/master
Commit: e39911ed78221b23a8837f00b806a251ee496401
Parents: 8774a67
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jul 6 20:44:46 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 6 20:44:46 2015 -0700
----------------------------------------------------------------------
.../java/org/apache/calcite/runtime/SqlFunctions.java | 4 +++-
core/src/test/resources/sql/agg.oq | 13 +++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e39911ed/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 256d15a..652fb85 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -544,7 +544,9 @@ public class SqlFunctions {
/** SQL <code>/</code> operator applied to BigDecimal values. */
public static BigDecimal divide(BigDecimal b0, BigDecimal b1) {
- return (b0 == null || b1 == null) ? null : b0.divide(b1);
+ return (b0 == null || b1 == null)
+ ? null
+ : b0.divide(b1, MathContext.DECIMAL64);
}
// *
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e39911ed/core/src/test/resources/sql/agg.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/agg.oq b/core/src/test/resources/sql/agg.oq
index 802f1dc..d81fa9e 100644
--- a/core/src/test/resources/sql/agg.oq
+++ b/core/src/test/resources/sql/agg.oq
@@ -760,6 +760,19 @@ from "scott".emp;
!ok
+# [CALCITE-280] BigDecimal underflow
+# Previously threw "java.lang.ArithmeticException: Non-terminating decimal
+# expansion; no exact representable decimal result"
+select avg(comm) as a, count(comm) as c from "scott".emp where empno < 7844;
++-------------------+---+
+| A | C |
++-------------------+---+
+| 733.3333333333333 | 3 |
++-------------------+---+
+(1 row)
+
+!ok
+
# [CALCITE-729] IndexOutOfBoundsException in ROLLUP query on JDBC data source
!use jdbc_scott
select deptno, job, count(*) as c
[4/5] incubator-calcite git commit: In RelBuilder,
calling sort then limit has same effect as calling sortLimit
Posted by jh...@apache.org.
In RelBuilder, calling sort then limit has same effect as calling sortLimit
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/40c55fd4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/40c55fd4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/40c55fd4
Branch: refs/heads/master
Commit: 40c55fd463e4a249953bf298450110027d6c3bd6
Parents: d35df36
Author: Julian Hyde <jh...@apache.org>
Authored: Sun Jul 5 00:05:11 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 6 20:49:53 2015 -0700
----------------------------------------------------------------------
.../org/apache/calcite/tools/RelBuilder.java | 33 ++++++++++++
.../org/apache/calcite/test/RelBuilderTest.java | 54 ++++++++++++++++++++
2 files changed, 87 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/40c55fd4/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index f664baf..13cf96e 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -28,6 +28,7 @@ import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.AggregateCall;
import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.Sort;
import org.apache.calcite.rel.core.Values;
@@ -865,6 +866,38 @@ public class RelBuilder {
final RexNode offsetNode = offset <= 0 ? null : literal(offset);
final RexNode fetchNode = fetch < 0 ? null : literal(fetch);
final boolean addedFields = extraNodes.size() > originalExtraNodes.size();
+ if (fieldCollations.isEmpty()) {
+ assert !addedFields;
+ RelNode top = peek();
+ if (top instanceof Sort) {
+ final Sort sort2 = (Sort) top;
+ if (sort2.offset == null && sort2.fetch == null) {
+ Stacks.pop(stack);
+ push(sort2.getInput());
+ final RelNode sort =
+ sortFactory.createSort(build(), sort2.collation,
+ offsetNode, fetchNode);
+ push(sort);
+ return this;
+ }
+ }
+ if (top instanceof Project) {
+ final Project project = (Project) top;
+ if (project.getInput() instanceof Sort) {
+ final Sort sort2 = (Sort) project.getInput();
+ if (sort2.offset == null && sort2.fetch == null) {
+ Stacks.pop(stack);
+ push(sort2.getInput());
+ final RelNode sort =
+ sortFactory.createSort(build(), sort2.collation,
+ offsetNode, fetchNode);
+ push(sort);
+ project(project.getProjects());
+ return this;
+ }
+ }
+ }
+ }
if (addedFields) {
project(extraNodes);
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/40c55fd4/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 0a2b990..0474590 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -625,6 +625,60 @@ public class RelBuilderTest {
+ " LogicalTableScan(table=[[scott, EMP]])\n";
assertThat(str(root), is(expected));
}
+
+ /** Tests that a sort on a field followed by a limit gives the same
+ * effect as calling sortLimit.
+ *
+ * <p>In general a relational operator cannot rely on the order of its input,
+ * but it is reasonable to merge sort and limit if they were created by
+ * consecutive builder operations. And clients such as Piglet rely on it. */
+ @Test public void testSortThenLimit() {
+ final RelBuilder builder = RelBuilder.create(config().build());
+ final RelNode root =
+ builder.scan("EMP")
+ .sort(builder.desc(builder.field("DEPTNO")))
+ .limit(-1, 10)
+ .build();
+ final String expected = ""
+ + "LogicalSort(sort0=[$7], dir0=[DESC], fetch=[10])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n";
+ assertThat(RelOptUtil.toString(root), is(expected));
+
+ final RelNode root2 =
+ builder.scan("EMP")
+ .sortLimit(-1, 10, builder.desc(builder.field("DEPTNO")))
+ .build();
+ assertThat(RelOptUtil.toString(root2), is(expected));
+ }
+
+ /** Tests that a sort on an expression followed by a limit gives the same
+ * effect as calling sortLimit. */
+ @Test public void testSortExpThenLimit() {
+ final RelBuilder builder = RelBuilder.create(config().build());
+ final RelNode root =
+ builder.scan("DEPT")
+ .sort(
+ builder.desc(
+ builder.call(SqlStdOperatorTable.PLUS,
+ builder.field("DEPTNO"), builder.literal(1))))
+ .limit(3, 10)
+ .build();
+ final String expected = ""
+ + "LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2])\n"
+ + " LogicalSort(sort0=[$3], dir0=[DESC], offset=[3], fetch=[10])\n"
+ + " LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2], $f3=[+($0, 1)])\n"
+ + " LogicalTableScan(table=[[scott, DEPT]])\n";
+ assertThat(RelOptUtil.toString(root), is(expected));
+
+ final RelNode root2 =
+ builder.scan("DEPT")
+ .sortLimit(3, 10,
+ builder.desc(
+ builder.call(SqlStdOperatorTable.PLUS,
+ builder.field("DEPTNO"), builder.literal(1))))
+ .build();
+ assertThat(RelOptUtil.toString(root2), is(expected));
+ }
}
// End RelBuilderTest.java
[5/5] incubator-calcite git commit: [CALCITE-780] HTTP error 413 when
sending a long string to the Avatica server
Posted by jh...@apache.org.
[CALCITE-780] HTTP error 413 when sending a long string to the Avatica server
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/03111d2b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/03111d2b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/03111d2b
Branch: refs/heads/master
Commit: 03111d2b680c4f4eb4886d60cab9beebd1c7bdcb
Parents: 40c55fd
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jul 7 00:20:48 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jul 7 00:20:48 2015 -0700
----------------------------------------------------------------------
.../calcite/avatica/server/AvaticaHandler.java | 13 ++++-
.../calcite/avatica/remote/RemoteMetaTest.java | 51 +++++++++++++++++++-
.../apache/calcite/avatica/AvaticaUtils.java | 17 +++++++
.../calcite/avatica/remote/RemoteService.java | 28 ++++++-----
4 files changed, 94 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
index fa0e1ac..2ada444 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.avatica.server;
+import org.apache.calcite.avatica.AvaticaUtils;
import org.apache.calcite.avatica.remote.JsonHandler;
import org.apache.calcite.avatica.remote.Service;
@@ -27,6 +28,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
import java.io.IOException;
import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -48,9 +50,16 @@ public class AvaticaHandler extends AbstractHandler {
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
if (request.getMethod().equals("POST")) {
+ // First look for a request in the header, then look in the body.
+ // The latter allows very large requests without hitting HTTP 413.
+ String rawRequest = request.getHeader("request");
+ if (rawRequest == null) {
+ try (ServletInputStream inputStream = request.getInputStream()) {
+ rawRequest = AvaticaUtils.readFully(inputStream);
+ }
+ }
final String jsonRequest =
- new String(request.getHeader("request").getBytes("ISO-8859-1"),
- "UTF-8");
+ new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
if (LOG.isTraceEnabled()) {
LOG.trace("request: " + jsonRequest);
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 2439ac3..27dcfa4 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -41,8 +41,10 @@ import java.sql.Statement;
import java.util.List;
import java.util.Map;
+import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/** Tests covering {@link RemoteMeta}. */
@@ -98,7 +100,7 @@ public class RemoteMetaTest {
Method m = AvaticaConnection.class.getDeclaredMethod("prepareAndExecuteInternal",
AvaticaStatement.class, String.class, int.class);
m.setAccessible(true);
- return (Meta.ExecuteResult) m.invoke(conn, statement, sql, new Integer(maxRowCount));
+ return (Meta.ExecuteResult) m.invoke(conn, statement, sql, maxRowCount);
}
private static Connection getConnection(JdbcMeta m, String id) throws Exception {
@@ -128,6 +130,53 @@ public class RemoteMetaTest {
}
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-780">[CALCITE-780]
+ * HTTP error 413 when sending a long string to the Avatica server</a>. */
+ @Test public void testRemoteExecuteVeryLargeQuery() throws Exception {
+ // Before the bug was fixed, a value over 7998 caused an HTTP 413.
+ // 16K bytes, I guess.
+ checkLargeQuery(8);
+ checkLargeQuery(240);
+ checkLargeQuery(8000);
+ checkLargeQuery(240000);
+ }
+
+ private void checkLargeQuery(int n) throws Exception {
+ try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
+ final AvaticaStatement statement = conn.createStatement();
+ final String frenchDisko = "It said human existence is pointless\n"
+ + "As acts of rebellious solidarity\n"
+ + "Can bring sense in this world\n"
+ + "La resistance!\n";
+ final String sql = "select '"
+ + longString(frenchDisko, n)
+ + "' as s from (values 'x')";
+ prepareAndExecuteInternal(conn, statement, sql, -1);
+ ResultSet rs = statement.getResultSet();
+ int count = 0;
+ while (rs.next()) {
+ count++;
+ }
+ assertThat(count, is(1));
+ rs.close();
+ statement.close();
+ conn.close();
+ }
+ }
+
+ /** Creates a string of exactly {@code length} characters by concatenating
+ * {@code fragment}. */
+ private static String longString(String fragment, int length) {
+ assert fragment.length() > 0;
+ final StringBuilder buf = new StringBuilder();
+ while (buf.length() < length) {
+ buf.append(fragment);
+ }
+ buf.setLength(length);
+ return buf.toString();
+ }
+
@Test public void testRemoteConnectionProperties() throws Exception {
try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
String id = conn.id;
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
index 5ca5245..0ee030d 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
@@ -16,6 +16,9 @@
*/
package org.apache.calcite.avatica;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.HashMap;
@@ -165,6 +168,20 @@ public class AvaticaUtils {
+ "' not valid for plugin type " + pluginClass.getName(), e);
}
}
+
+ /** Reads the contents of an input stream and returns as a string. */
+ public static String readFully(InputStream inputStream) throws IOException {
+ final byte[] bytes = new byte[4096];
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ for (;;) {
+ int count = inputStream.read(bytes, 0, bytes.length);
+ if (count < 0) {
+ break;
+ }
+ baos.write(bytes, 0, count);
+ }
+ return baos.toString();
+ }
}
// End AvaticaUtils.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/03111d2b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
index 7cbdcf0..a5896f2 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteService.java
@@ -16,7 +16,9 @@
*/
package org.apache.calcite.avatica.remote;
-import java.io.ByteArrayOutputStream;
+import org.apache.calcite.avatica.AvaticaUtils;
+
+import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
@@ -39,22 +41,24 @@ public class RemoteService extends JsonService {
final HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
- connection.setRequestProperty("request", request);
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+ if (request.length() < 256) {
+ connection.setRequestProperty("request", request);
+ } else {
+ try (DataOutputStream wr
+ = new DataOutputStream(connection.getOutputStream())) {
+ wr.writeBytes(request);
+ wr.flush();
+ wr.close();
+ }
+ }
final int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
throw new RuntimeException("response code " + responseCode);
}
final InputStream inputStream = connection.getInputStream();
- final byte[] bytes = new byte[4096];
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for (;;) {
- int count = inputStream.read(bytes, 0, bytes.length);
- if (count < 0) {
- break;
- }
- baos.write(bytes, 0, count);
- }
- return baos.toString();
+ return AvaticaUtils.readFully(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
[2/5] incubator-calcite git commit: [CALCITE-788] Allow
EnumerableJoin to be sub-classed (Li Yang)
Posted by jh...@apache.org.
[CALCITE-788] Allow EnumerableJoin to be sub-classed (Li Yang)
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/a76a2015
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/a76a2015
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/a76a2015
Branch: refs/heads/master
Commit: a76a201524b7474be0e9bc281988d166c92431e5
Parents: e39911e
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jul 6 20:47:07 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 6 20:47:07 2015 -0700
----------------------------------------------------------------------
.../java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a76a2015/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
index ff80993..14fcf3b 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java
@@ -45,7 +45,7 @@ public class EnumerableJoin extends EquiJoin implements EnumerableRel {
/** Creates an EnumerableJoin.
*
* <p>Use {@link #create} unless you know what you're doing. */
- EnumerableJoin(
+ protected EnumerableJoin(
RelOptCluster cluster,
RelTraitSet traits,
RelNode left,
[3/5] incubator-calcite git commit: Add Ord.reverse
Posted by jh...@apache.org.
Add Ord.reverse
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/d35df363
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/d35df363
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/d35df363
Branch: refs/heads/master
Commit: d35df363b4eccc9c6dc85c507b38b3a2334148db
Parents: a76a201
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jun 30 11:49:59 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 6 20:49:53 2015 -0700
----------------------------------------------------------------------
.../java/org/apache/calcite/util/UtilTest.java | 20 ++++++++
.../java/org/apache/calcite/linq4j/Ord.java | 49 ++++++++++++++++++--
2 files changed, 65 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d35df363/core/src/test/java/org/apache/calcite/util/UtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/UtilTest.java b/core/src/test/java/org/apache/calcite/util/UtilTest.java
index 2d731a7..92b5c34 100644
--- a/core/src/test/java/org/apache/calcite/util/UtilTest.java
+++ b/core/src/test/java/org/apache/calcite/util/UtilTest.java
@@ -19,6 +19,7 @@ package org.apache.calcite.util;
import org.apache.calcite.avatica.AvaticaUtils;
import org.apache.calcite.avatica.util.Spaces;
import org.apache.calcite.examples.RelBuilderExample;
+import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.linq4j.function.Function1;
import org.apache.calcite.runtime.FlatLists;
import org.apache.calcite.runtime.Resources;
@@ -1381,6 +1382,25 @@ public class UtilTest {
@Test public void testRelBuilderExample() {
new RelBuilderExample(false).runAllExamples();
}
+
+ @Test public void testOrdReverse() {
+ checkOrdReverse(Ord.reverse(Arrays.asList("a", "b", "c")));
+ checkOrdReverse(Ord.reverse("a", "b", "c"));
+ assertThat(Ord.reverse(ImmutableList.<String>of()).iterator().hasNext(),
+ is(false));
+ assertThat(Ord.reverse().iterator().hasNext(), is(false));
+ }
+
+ private void checkOrdReverse(Iterable<Ord<String>> reverse1) {
+ final Iterator<Ord<String>> reverse = reverse1.iterator();
+ assertThat(reverse.hasNext(), is(true));
+ assertThat(reverse.next().i, is(2));
+ assertThat(reverse.hasNext(), is(true));
+ assertThat(reverse.next().e, is("b"));
+ assertThat(reverse.hasNext(), is(true));
+ assertThat(reverse.next().e, is("a"));
+ assertThat(reverse.hasNext(), is(false));
+ }
}
// End UtilTest.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d35df363/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java b/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java
index c7eedf5..0ef3df6 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/Ord.java
@@ -16,6 +16,8 @@
*/
package org.apache.calcite.linq4j;
+import com.google.common.collect.ImmutableList;
+
import java.util.AbstractList;
import java.util.Iterator;
import java.util.List;
@@ -43,7 +45,7 @@ public class Ord<E> implements Map.Entry<Integer, E> {
* Creates an Ord.
*/
public static <E> Ord<E> of(int n, E e) {
- return new Ord<E>(n, e);
+ return new Ord<>(n, e);
}
/**
@@ -82,7 +84,7 @@ public class Ord<E> implements Map.Entry<Integer, E> {
* Returns a numbered list based on an array.
*/
public static <E> List<Ord<E>> zip(final E[] elements) {
- return new OrdArrayList<E>(elements);
+ return new OrdArrayList<>(elements);
}
/**
@@ -90,8 +92,47 @@ public class Ord<E> implements Map.Entry<Integer, E> {
*/
public static <E> List<Ord<E>> zip(final List<? extends E> elements) {
return elements instanceof RandomAccess
- ? new OrdRandomAccessList<E>(elements)
- : new OrdList<E>(elements);
+ ? new OrdRandomAccessList<>(elements)
+ : new OrdList<>(elements);
+ }
+
+ /**
+ * Iterates over an array in reverse order.
+ *
+ * <p>Given the array ["a", "b", "c"], returns (2, "c") then (1, "b") then
+ * (0, "a").
+ */
+ public static <E> Iterable<Ord<E>> reverse(E... elements) {
+ return reverse(ImmutableList.copyOf(elements));
+ }
+
+ /**
+ * Iterates over a list in reverse order.
+ *
+ * <p>Given the list ["a", "b", "c"], returns (2, "c") then (1, "b") then
+ * (0, "a").
+ */
+ public static <E> Iterable<Ord<E>> reverse(Iterable<? extends E> elements) {
+ final ImmutableList<E> elementList = ImmutableList.copyOf(elements);
+ return new Iterable<Ord<E>>() {
+ public Iterator<Ord<E>> iterator() {
+ return new Iterator<Ord<E>>() {
+ int i = elementList.size() - 1;
+
+ public boolean hasNext() {
+ return i >= 0;
+ }
+
+ public Ord<E> next() {
+ return Ord.of(i, elementList.get(i--));
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("remove");
+ }
+ };
+ }
+ };
}
public Integer getKey() {