From 2254d3e9b7e09a528b7c34aed1b98507f8f5e28f Mon Sep 17 00:00:00 2001 From: Yang Li Date: Sat, 26 Sep 2015 20:15:23 +0800 Subject: [PATCH] KYLIN-1047 Upgrade to Calcite 1.4 --- .../calcite/adapter/enumerable/EnumerableJoin.java | 146 --- .../org/apache/calcite/runtime/SqlFunctions.java | 1315 -------------------- .../apache/calcite/sql2rel/SqlToRelConverter.java | 253 +--- .../main/java/org/apache/kylin/jdbc/KylinMeta.java | 9 +- pom.xml | 2 +- .../apache/kylin/query/relnode/OLAPJoinRel.java | 24 +- .../apache/kylin/query/relnode/OLAPTableScan.java | 13 +- 7 files changed, 100 insertions(+), 1662 deletions(-) delete mode 100644 atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java delete mode 100644 atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java diff --git a/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java b/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java deleted file mode 100644 index 17f1b38..0000000 --- a/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableJoin.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.calcite.adapter.enumerable; - -import java.util.Set; - -import org.apache.calcite.linq4j.tree.BlockBuilder; -import org.apache.calcite.linq4j.tree.Expression; -import org.apache.calcite.linq4j.tree.Expressions; -import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptCost; -import org.apache.calcite.plan.RelOptPlanner; -import org.apache.calcite.plan.RelTraitSet; -import org.apache.calcite.rel.InvalidRelException; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.RelNodes; -import org.apache.calcite.rel.core.EquiJoin; -import org.apache.calcite.rel.core.JoinInfo; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.rel.metadata.RelMetadataQuery; -import org.apache.calcite.rex.RexNode; -import org.apache.calcite.util.BuiltInMethod; -import org.apache.calcite.util.ImmutableIntList; -import org.apache.calcite.util.Util; - -import com.google.common.collect.ImmutableList; - -/* - * OVERRIDE POINT: - * - constructor was private instead of protected - */ - -/** Implementation of {@link org.apache.calcite.rel.core.Join} in - * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */ -public class EnumerableJoin extends EquiJoin implements EnumerableRel { - /** Creates an EnumerableJoin. - * - *

Use {@link #create} unless you know what you're doing. */ - public EnumerableJoin(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode right, RexNode condition, ImmutableIntList leftKeys, ImmutableIntList rightKeys, JoinRelType joinType, Set variablesStopped) throws InvalidRelException { - super(cluster, traits, left, right, condition, leftKeys, rightKeys, joinType, variablesStopped); - } - - /** Creates an EnumerableJoin. */ - public static EnumerableJoin create(RelNode left, RelNode right, RexNode condition, ImmutableIntList leftKeys, ImmutableIntList rightKeys, JoinRelType joinType, Set variablesStopped) throws InvalidRelException { - final RelOptCluster cluster = left.getCluster(); - final RelTraitSet traitSet = cluster.traitSetOf(EnumerableConvention.INSTANCE); - return new EnumerableJoin(cluster, traitSet, left, right, condition, leftKeys, rightKeys, joinType, variablesStopped); - } - - @Override - public EnumerableJoin copy(RelTraitSet traitSet, RexNode condition, RelNode left, RelNode right, JoinRelType joinType, boolean semiJoinDone) { - final JoinInfo joinInfo = JoinInfo.of(left, right, condition); - assert joinInfo.isEqui(); - try { - return new EnumerableJoin(getCluster(), traitSet, left, right, condition, joinInfo.leftKeys, joinInfo.rightKeys, joinType, variablesStopped); - } catch (InvalidRelException e) { - // Semantic error not possible. Must be a bug. Convert to - // internal error. - throw new AssertionError(e); - } - } - - @Override - public RelOptCost computeSelfCost(RelOptPlanner planner) { - double rowCount = RelMetadataQuery.getRowCount(this); - - // Joins can be flipped, and for many algorithms, both versions are viable - // and have the same cost. To make the results stable between versions of - // the planner, make one of the versions slightly more expensive. - switch (joinType) { - case RIGHT: - rowCount = addEpsilon(rowCount); - break; - default: - if (RelNodes.COMPARATOR.compare(left, right) > 0) { - rowCount = addEpsilon(rowCount); - } - } - - // Cheaper if the smaller number of rows is coming from the LHS. - // Model this by adding L log L to the cost. - final double rightRowCount = right.getRows(); - final double leftRowCount = left.getRows(); - if (Double.isInfinite(leftRowCount)) { - rowCount = leftRowCount; - } else { - rowCount += Util.nLogN(leftRowCount); - } - if (Double.isInfinite(rightRowCount)) { - rowCount = rightRowCount; - } else { - rowCount += rightRowCount; - } - return planner.getCostFactory().makeCost(rowCount, 0, 0); - } - - private double addEpsilon(double d) { - assert d >= 0d; - final double d0 = d; - if (d < 10) { - // For small d, adding 1 would change the value significantly. - d *= 1.001d; - if (d != d0) { - return d; - } - } - // For medium d, add 1. Keeps integral values integral. - ++d; - if (d != d0) { - return d; - } - // For large d, adding 1 might not change the value. Add .1%. - // If d is NaN, this still will probably not change the value. That's OK. - d *= 1.001d; - return d; - } - - public Result implement(EnumerableRelImplementor implementor, Prefer pref) { - BlockBuilder builder = new BlockBuilder(); - final Result leftResult = implementor.visitChild(this, 0, (EnumerableRel) left, pref); - Expression leftExpression = builder.append("left", leftResult.block); - final Result rightResult = implementor.visitChild(this, 1, (EnumerableRel) right, pref); - Expression rightExpression = builder.append("right", rightResult.block); - final PhysType physType = PhysTypeImpl.of(implementor.getTypeFactory(), getRowType(), pref.preferArray()); - final PhysType keyPhysType = leftResult.physType.project(leftKeys, JavaRowFormat.LIST); - return implementor.result(physType, builder.append(Expressions.call(leftExpression, BuiltInMethod.JOIN.method, Expressions.list(rightExpression, leftResult.physType.generateAccessor(leftKeys), rightResult.physType.generateAccessor(rightKeys), EnumUtils.joinSelector(joinType, physType, ImmutableList.of(leftResult.physType, rightResult.physType))).append(Util.first(keyPhysType.comparer(), Expressions.constant(null))).append(Expressions.constant(joinType.generatesNullsOnLeft())).append(Expressions.constant(joinType.generatesNullsOnRight())))).toBlock()); - } - -} - -// End EnumerableJoin.java diff --git a/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java deleted file mode 100644 index 4b3d589..0000000 --- a/atopcalcite/src/main/java/org/apache/calcite/runtime/SqlFunctions.java +++ /dev/null @@ -1,1315 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.calcite.runtime; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.MathContext; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.text.DecimalFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; -import java.util.concurrent.atomic.AtomicLong; -import java.util.regex.Pattern; - -import org.apache.calcite.DataContext; -import org.apache.calcite.avatica.util.ByteString; -import org.apache.calcite.avatica.util.DateTimeUtils; -import org.apache.calcite.linq4j.Enumerable; -import org.apache.calcite.linq4j.Linq4j; -import org.apache.calcite.linq4j.function.Deterministic; -import org.apache.calcite.linq4j.function.Function1; -import org.apache.calcite.linq4j.function.NonDeterministic; -import org.apache.calcite.linq4j.tree.Primitive; - -/** - * OVERRIDE POINT: - * - divide(BigDecimal,BigDecimal), was `b0.divide(b1)`, now `b0.divide(b1, MathContext.DECIMAL64);` - * Helper methods to implement SQL functions in generated code. - * - *

Not present: and, or, not (builtin operators are better, because they - * use lazy evaluation. Implementations do not check for null values; the - * calling code must do that.

- * - *

Many of the functions do not check for null values. This is intentional. - * If null arguments are possible, the code-generation framework checks for - * nulls before calling the functions.

- */ -@SuppressWarnings("UnnecessaryUnboxing") -@Deterministic -public class SqlFunctions { - private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("0.0E0"); - - private static final TimeZone LOCAL_TZ = TimeZone.getDefault(); - - private static final Function1, Enumerable> LIST_AS_ENUMERABLE = new Function1, Enumerable>() { - public Enumerable apply(List list) { - return Linq4j.asEnumerable(list); - } - }; - - /** Holds, for each thread, a map from sequence name to sequence current - * value. - * - *

This is a straw man of an implementation whose main goal is to prove - * that sequences can be parsed, validated and planned. A real application - * will want persistent values for sequences, shared among threads. */ - private static final ThreadLocal> THREAD_SEQUENCES = new ThreadLocal>() { - @Override - protected Map initialValue() { - return new HashMap(); - } - }; - - private SqlFunctions() { - } - - /** SQL SUBSTRING(string FROM ... FOR ...) function. */ - public static String substring(String s, int from, int for_) { - return s.substring(from - 1, Math.min(from - 1 + for_, s.length())); - } - - /** SQL SUBSTRING(string FROM ...) function. */ - public static String substring(String s, int from) { - return s.substring(from - 1); - } - - /** SQL UPPER(string) function. */ - public static String upper(String s) { - return s.toUpperCase(); - } - - /** SQL LOWER(string) function. */ - public static String lower(String s) { - return s.toLowerCase(); - } - - /** SQL INITCAP(string) function. */ - public static String initcap(String s) { - // Assumes Alpha as [A-Za-z0-9] - // white space is treated as everything else. - final int len = s.length(); - boolean start = true; - final StringBuilder newS = new StringBuilder(); - - for (int i = 0; i < len; i++) { - char curCh = s.charAt(i); - final int c = (int) curCh; - if (start) { // curCh is whitespace or first character of word. - if (c > 47 && c < 58) { // 0-9 - start = false; - } else if (c > 64 && c < 91) { // A-Z - start = false; - } else if (c > 96 && c < 123) { // a-z - start = false; - curCh = (char) (c - 32); // Uppercase this character - } - // else {} whitespace - } else { // Inside of a word or white space after end of word. - if (c > 47 && c < 58) { // 0-9 - // noop - } else if (c > 64 && c < 91) { // A-Z - curCh = (char) (c + 32); // Lowercase this character - } else if (c > 96 && c < 123) { // a-z - // noop - } else { // whitespace - start = true; - } - } - newS.append(curCh); - } // for each character in s - return newS.toString(); - } - - /** SQL CHARACTER_LENGTH(string) function. */ - public static int charLength(String s) { - return s.length(); - } - - /** SQL {@code string || string} operator. */ - public static String concat(String s0, String s1) { - return s0 + s1; - } - - /** SQL {@code binary || binary} operator. */ - public static ByteString concat(ByteString s0, ByteString s1) { - return s0.concat(s1); - } - - /** SQL {@code RTRIM} function applied to string. */ - public static String rtrim(String s) { - return trim_(s, false, true, ' '); - } - - /** SQL {@code LTRIM} function. */ - public static String ltrim(String s) { - return trim_(s, true, false, ' '); - } - - /** SQL {@code TRIM(... seek FROM s)} function. */ - public static String trim(boolean leading, boolean trailing, String seek, String s) { - return trim_(s, leading, trailing, seek.charAt(0)); - } - - /** SQL {@code TRIM} function. */ - private static String trim_(String s, boolean left, boolean right, char c) { - int j = s.length(); - if (right) { - for (;;) { - if (j == 0) { - return ""; - } - if (s.charAt(j - 1) != c) { - break; - } - --j; - } - } - int i = 0; - if (left) { - for (;;) { - if (i == j) { - return ""; - } - if (s.charAt(i) != c) { - break; - } - ++i; - } - } - return s.substring(i, j); - } - - /** SQL {@code TRIM} function applied to binary string. */ - public static ByteString trim(ByteString s) { - return trim_(s, true, true); - } - - /** Helper for CAST. */ - public static ByteString rtrim(ByteString s) { - return trim_(s, false, true); - } - - /** SQL {@code TRIM} function applied to binary string. */ - private static ByteString trim_(ByteString s, boolean left, boolean right) { - int j = s.length(); - if (right) { - for (;;) { - if (j == 0) { - return ByteString.EMPTY; - } - if (s.byteAt(j - 1) != 0) { - break; - } - --j; - } - } - int i = 0; - if (left) { - for (;;) { - if (i == j) { - return ByteString.EMPTY; - } - if (s.byteAt(i) != 0) { - break; - } - ++i; - } - } - return s.substring(i, j); - } - - /** SQL {@code OVERLAY} function. */ - public static String overlay(String s, String r, int start) { - if (s == null || r == null) { - return null; - } - return s.substring(0, start - 1) + r + s.substring(start - 1 + r.length()); - } - - /** SQL {@code OVERLAY} function. */ - public static String overlay(String s, String r, int start, int length) { - if (s == null || r == null) { - return null; - } - return s.substring(0, start - 1) + r + s.substring(start - 1 + length); - } - - /** SQL {@code OVERLAY} function applied to binary strings. */ - public static ByteString overlay(ByteString s, ByteString r, int start) { - if (s == null || r == null) { - return null; - } - return s.substring(0, start - 1).concat(r).concat(s.substring(start - 1 + r.length())); - } - - /** SQL {@code OVERLAY} function applied to binary strings. */ - public static ByteString overlay(ByteString s, ByteString r, int start, int length) { - if (s == null || r == null) { - return null; - } - return s.substring(0, start - 1).concat(r).concat(s.substring(start - 1 + length)); - } - - /** SQL {@code LIKE} function. */ - public static boolean like(String s, String pattern) { - final String regex = Like.sqlToRegexLike(pattern, null); - return Pattern.matches(regex, s); - } - - /** SQL {@code LIKE} function with escape. */ - public static boolean like(String s, String pattern, String escape) { - final String regex = Like.sqlToRegexLike(pattern, escape); - return Pattern.matches(regex, s); - } - - /** SQL {@code SIMILAR} function. */ - public static boolean similar(String s, String pattern) { - final String regex = Like.sqlToRegexSimilar(pattern, null); - return Pattern.matches(regex, s); - } - - /** SQL {@code SIMILAR} function with escape. */ - public static boolean similar(String s, String pattern, String escape) { - final String regex = Like.sqlToRegexSimilar(pattern, escape); - return Pattern.matches(regex, s); - } - - // = - - /** SQL = operator applied to Object values (including String; neither - * side may be null). */ - public static boolean eq(Object b0, Object b1) { - return b0.equals(b1); - } - - /** SQL = operator applied to BigDecimal values (neither may be null). */ - public static boolean eq(BigDecimal b0, BigDecimal b1) { - return b0.stripTrailingZeros().equals(b1.stripTrailingZeros()); - } - - // <> - - /** SQL <> operator applied to Object values (including String; - * neither side may be null). */ - public static boolean ne(Object b0, Object b1) { - return !b0.equals(b1); - } - - /** SQL <> operator applied to BigDecimal values. */ - public static boolean ne(BigDecimal b0, BigDecimal b1) { - return b0.compareTo(b1) != 0; - } - - // < - - /** SQL < operator applied to boolean values. */ - public static boolean lt(boolean b0, boolean b1) { - return compare(b0, b1) < 0; - } - - /** SQL < operator applied to String values. */ - public static boolean lt(String b0, String b1) { - return b0.compareTo(b1) < 0; - } - - /** SQL < operator applied to ByteString values. */ - public static boolean lt(ByteString b0, ByteString b1) { - return b0.compareTo(b1) < 0; - } - - /** SQL < operator applied to BigDecimal values. */ - public static boolean lt(BigDecimal b0, BigDecimal b1) { - return b0.compareTo(b1) < 0; - } - - // <= - - /** SQL ≤ operator applied to boolean values. */ - public static boolean le(boolean b0, boolean b1) { - return compare(b0, b1) <= 0; - } - - /** SQL ≤ operator applied to String values. */ - public static boolean le(String b0, String b1) { - return b0.compareTo(b1) <= 0; - } - - /** SQL ≤ operator applied to ByteString values. */ - public static boolean le(ByteString b0, ByteString b1) { - return b0.compareTo(b1) <= 0; - } - - /** SQL ≤ operator applied to BigDecimal values. */ - public static boolean le(BigDecimal b0, BigDecimal b1) { - return b0.compareTo(b1) <= 0; - } - - // > - - /** SQL > operator applied to boolean values. */ - public static boolean gt(boolean b0, boolean b1) { - return compare(b0, b1) > 0; - } - - /** SQL > operator applied to String values. */ - public static boolean gt(String b0, String b1) { - return b0.compareTo(b1) > 0; - } - - /** SQL > operator applied to ByteString values. */ - public static boolean gt(ByteString b0, ByteString b1) { - return b0.compareTo(b1) > 0; - } - - /** SQL > operator applied to BigDecimal values. */ - public static boolean gt(BigDecimal b0, BigDecimal b1) { - return b0.compareTo(b1) > 0; - } - - // >= - - /** SQL ≥ operator applied to boolean values. */ - public static boolean ge(boolean b0, boolean b1) { - return compare(b0, b1) >= 0; - } - - /** SQL ≥ operator applied to String values. */ - public static boolean ge(String b0, String b1) { - return b0.compareTo(b1) >= 0; - } - - /** SQL ≥ operator applied to ByteString values. */ - public static boolean ge(ByteString b0, ByteString b1) { - return b0.compareTo(b1) >= 0; - } - - /** SQL ≥ operator applied to BigDecimal values. */ - public static boolean ge(BigDecimal b0, BigDecimal b1) { - return b0.compareTo(b1) >= 0; - } - - // + - - /** SQL + operator applied to int values. */ - public static int plus(int b0, int b1) { - return b0 + b1; - } - - /** SQL + operator applied to int values; left side may be - * null. */ - public static Integer plus(Integer b0, int b1) { - return b0 == null ? null : (b0 + b1); - } - - /** SQL + operator applied to int values; right side may be - * null. */ - public static Integer plus(int b0, Integer b1) { - return b1 == null ? null : (b0 + b1); - } - - /** SQL + operator applied to nullable int values. */ - public static Integer plus(Integer b0, Integer b1) { - return (b0 == null || b1 == null) ? null : (b0 + b1); - } - - /** SQL + operator applied to nullable long and int values. */ - public static Long plus(Long b0, Integer b1) { - return (b0 == null || b1 == null) ? null : (b0.longValue() + b1.longValue()); - } - - /** SQL + operator applied to nullable int and long values. */ - public static Long plus(Integer b0, Long b1) { - return (b0 == null || b1 == null) ? null : (b0.longValue() + b1.longValue()); - } - - /** SQL + operator applied to BigDecimal values. */ - public static BigDecimal plus(BigDecimal b0, BigDecimal b1) { - return (b0 == null || b1 == null) ? null : b0.add(b1); - } - - // - - - /** SQL - operator applied to int values. */ - public static int minus(int b0, int b1) { - return b0 - b1; - } - - /** SQL - operator applied to int values; left side may be - * null. */ - public static Integer minus(Integer b0, int b1) { - return b0 == null ? null : (b0 - b1); - } - - /** SQL - operator applied to int values; right side may be - * null. */ - public static Integer minus(int b0, Integer b1) { - return b1 == null ? null : (b0 - b1); - } - - /** SQL - operator applied to nullable int values. */ - public static Integer minus(Integer b0, Integer b1) { - return (b0 == null || b1 == null) ? null : (b0 - b1); - } - - /** SQL - operator applied to nullable long and int values. */ - public static Long minus(Long b0, Integer b1) { - return (b0 == null || b1 == null) ? null : (b0.longValue() - b1.longValue()); - } - - /** SQL - operator applied to nullable int and long values. */ - public static Long minus(Integer b0, Long b1) { - return (b0 == null || b1 == null) ? null : (b0.longValue() - b1.longValue()); - } - - /** SQL - operator applied to BigDecimal values. */ - public static BigDecimal minus(BigDecimal b0, BigDecimal b1) { - return (b0 == null || b1 == null) ? null : b0.subtract(b1); - } - - // / - - /** SQL / operator applied to int values. */ - public static int divide(int b0, int b1) { - return b0 / b1; - } - - /** SQL / operator applied to int values; left side may be - * null. */ - public static Integer divide(Integer b0, int b1) { - return b0 == null ? null : (b0 / b1); - } - - /** SQL / operator applied to int values; right side may be - * null. */ - public static Integer divide(int b0, Integer b1) { - return b1 == null ? null : (b0 / b1); - } - - /** SQL / operator applied to nullable int values. */ - public static Integer divide(Integer b0, Integer b1) { - return (b0 == null || b1 == null) ? null : (b0 / b1); - } - - /** SQL / operator applied to nullable long and int values. */ - public static Long divide(Long b0, Integer b1) { - return (b0 == null || b1 == null) ? null : (b0.longValue() / b1.longValue()); - } - - /** SQL / operator applied to nullable int and long values. */ - public static Long divide(Integer b0, Long b1) { - return (b0 == null || b1 == null) ? null : (b0.longValue() / b1.longValue()); - } - - /** SQL / operator applied to BigDecimal values. */ - public static BigDecimal divide(BigDecimal b0, BigDecimal b1) { - return (b0 == null || b1 == null) ? null : b0.divide(b1, MathContext.DECIMAL64); - } - - // * - - /** SQL * operator applied to int values. */ - public static int multiply(int b0, int b1) { - return b0 * b1; - } - - /** SQL * operator applied to int values; left side may be - * null. */ - public static Integer multiply(Integer b0, int b1) { - return b0 == null ? null : (b0 * b1); - } - - /** SQL * operator applied to int values; right side may be - * null. */ - public static Integer multiply(int b0, Integer b1) { - return b1 == null ? null : (b0 * b1); - } - - /** SQL * operator applied to nullable int values. */ - public static Integer multiply(Integer b0, Integer b1) { - return (b0 == null || b1 == null) ? null : (b0 * b1); - } - - /** SQL * operator applied to nullable long and int values. */ - public static Long multiply(Long b0, Integer b1) { - return (b0 == null || b1 == null) ? null : (b0.longValue() * b1.longValue()); - } - - /** SQL * operator applied to nullable int and long values. */ - public static Long multiply(Integer b0, Long b1) { - return (b0 == null || b1 == null) ? null : (b0.longValue() * b1.longValue()); - } - - /** SQL * operator applied to BigDecimal values. */ - public static BigDecimal multiply(BigDecimal b0, BigDecimal b1) { - return (b0 == null || b1 == null) ? null : b0.multiply(b1); - } - - // EXP - - /** SQL EXP operator applied to double values. */ - public static double exp(double b0) { - return Math.exp(b0); - } - - public static double exp(long b0) { - return Math.exp(b0); - } - - // POWER - - /** SQL POWER operator applied to double values. */ - public static double power(double b0, double b1) { - return Math.pow(b0, b1); - } - - public static double power(long b0, long b1) { - return Math.pow(b0, b1); - } - - public static double power(long b0, BigDecimal b1) { - return Math.pow(b0, b1.doubleValue()); - } - - // LN - - /** SQL {@code LN(number)} function applied to double values. */ - public static double ln(double d) { - return Math.log(d); - } - - /** SQL {@code LN(number)} function applied to long values. */ - public static double ln(long b0) { - return Math.log(b0); - } - - /** SQL {@code LN(number)} function applied to BigDecimal values. */ - public static double ln(BigDecimal d) { - return Math.log(d.doubleValue()); - } - - // LOG10 - - /** SQL LOG10(numeric) operator applied to double values. */ - public static double log10(double b0) { - return Math.log10(b0); - } - - /** SQL {@code LOG10(number)} function applied to long values. */ - public static double log10(long b0) { - return Math.log10(b0); - } - - /** SQL {@code LOG10(number)} function applied to BigDecimal values. */ - public static double log10(BigDecimal d) { - return Math.log10(d.doubleValue()); - } - - // MOD - - /** SQL MOD operator applied to byte values. */ - public static byte mod(byte b0, byte b1) { - return (byte) (b0 % b1); - } - - /** SQL MOD operator applied to short values. */ - public static short mod(short b0, short b1) { - return (short) (b0 % b1); - } - - /** SQL MOD operator applied to int values. */ - public static int mod(int b0, int b1) { - return b0 % b1; - } - - /** SQL MOD operator applied to long values. */ - public static long mod(long b0, long b1) { - return b0 % b1; - } - - // temporary - public static BigDecimal mod(BigDecimal b0, int b1) { - return mod(b0, BigDecimal.valueOf(b1)); - } - - // temporary - public static int mod(int b0, BigDecimal b1) { - return mod(b0, b1.intValue()); - } - - public static BigDecimal mod(BigDecimal b0, BigDecimal b1) { - final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1); - return bigDecimals[1]; - } - - // FLOOR - - public static double floor(double b0) { - return Math.floor(b0); - } - - public static float floor(float b0) { - return (float) Math.floor(b0); - } - - public static BigDecimal floor(BigDecimal b0) { - return b0.setScale(0, BigDecimal.ROUND_FLOOR); - } - - /** SQL FLOOR operator applied to byte values. */ - public static byte floor(byte b0, byte b1) { - return (byte) floor((int) b0, (int) b1); - } - - /** SQL FLOOR operator applied to short values. */ - public static short floor(short b0, short b1) { - return (short) floor((int) b0, (int) b1); - } - - /** SQL FLOOR operator applied to int values. */ - public static int floor(int b0, int b1) { - int r = b0 % b1; - if (r < 0) { - r += b1; - } - return b0 - r; - } - - /** SQL FLOOR operator applied to long values. */ - public static long floor(long b0, long b1) { - long r = b0 % b1; - if (r < 0) { - r += b1; - } - return b0 - r; - } - - // temporary - public static BigDecimal floor(BigDecimal b0, int b1) { - return floor(b0, BigDecimal.valueOf(b1)); - } - - // temporary - public static int floor(int b0, BigDecimal b1) { - return floor(b0, b1.intValue()); - } - - public static BigDecimal floor(BigDecimal b0, BigDecimal b1) { - final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1); - BigDecimal r = bigDecimals[1]; - if (r.signum() < 0) { - r = r.add(b1); - } - return b0.subtract(r); - } - - // CEIL - - public static double ceil(double b0) { - return Math.ceil(b0); - } - - public static float ceil(float b0) { - return (float) Math.ceil(b0); - } - - public static BigDecimal ceil(BigDecimal b0) { - return b0.setScale(0, BigDecimal.ROUND_CEILING); - } - - /** SQL CEIL operator applied to byte values. */ - public static byte ceil(byte b0, byte b1) { - return floor((byte) (b0 + b1 - 1), b1); - } - - /** SQL CEIL operator applied to short values. */ - public static short ceil(short b0, short b1) { - return floor((short) (b0 + b1 - 1), b1); - } - - /** SQL CEIL operator applied to int values. */ - public static int ceil(int b0, int b1) { - int r = b0 % b1; - if (r > 0) { - r -= b1; - } - return b0 - r; - } - - /** SQL CEIL operator applied to long values. */ - public static long ceil(long b0, long b1) { - return floor(b0 + b1 - 1, b1); - } - - // temporary - public static BigDecimal ceil(BigDecimal b0, int b1) { - return ceil(b0, BigDecimal.valueOf(b1)); - } - - // temporary - public static int ceil(int b0, BigDecimal b1) { - return ceil(b0, b1.intValue()); - } - - public static BigDecimal ceil(BigDecimal b0, BigDecimal b1) { - final BigDecimal[] bigDecimals = b0.divideAndRemainder(b1); - BigDecimal r = bigDecimals[1]; - if (r.signum() > 0) { - r = r.subtract(b1); - } - return b0.subtract(r); - } - - // ABS - - /** SQL ABS operator applied to byte values. */ - public static byte abs(byte b0) { - return (byte) Math.abs(b0); - } - - /** SQL ABS operator applied to short values. */ - public static short abs(short b0) { - return (short) Math.abs(b0); - } - - /** SQL ABS operator applied to int values. */ - public static int abs(int b0) { - return Math.abs(b0); - } - - /** SQL ABS operator applied to long values. */ - public static long abs(long b0) { - return Math.abs(b0); - } - - /** SQL ABS operator applied to float values. */ - public static float abs(float b0) { - return Math.abs(b0); - } - - /** SQL ABS operator applied to double values. */ - public static double abs(double b0) { - return Math.abs(b0); - } - - /** SQL ABS operator applied to BigDecimal values. */ - public static BigDecimal abs(BigDecimal b0) { - return b0.abs(); - } - - // Helpers - - /** Helper for implementing MIN. Somewhat similar to LEAST operator. */ - public static > T lesser(T b0, T b1) { - return b0 == null || b0.compareTo(b1) > 0 ? b1 : b0; - } - - /** LEAST operator. */ - public static > T least(T b0, T b1) { - return b0 == null || b1 != null && b0.compareTo(b1) > 0 ? b1 : b0; - } - - public static boolean greater(boolean b0, boolean b1) { - return b0 || b1; - } - - public static boolean lesser(boolean b0, boolean b1) { - return b0 && b1; - } - - public static byte greater(byte b0, byte b1) { - return b0 > b1 ? b0 : b1; - } - - public static byte lesser(byte b0, byte b1) { - return b0 > b1 ? b1 : b0; - } - - public static char greater(char b0, char b1) { - return b0 > b1 ? b0 : b1; - } - - public static char lesser(char b0, char b1) { - return b0 > b1 ? b1 : b0; - } - - public static short greater(short b0, short b1) { - return b0 > b1 ? b0 : b1; - } - - public static short lesser(short b0, short b1) { - return b0 > b1 ? b1 : b0; - } - - public static int greater(int b0, int b1) { - return b0 > b1 ? b0 : b1; - } - - public static int lesser(int b0, int b1) { - return b0 > b1 ? b1 : b0; - } - - public static long greater(long b0, long b1) { - return b0 > b1 ? b0 : b1; - } - - public static long lesser(long b0, long b1) { - return b0 > b1 ? b1 : b0; - } - - public static float greater(float b0, float b1) { - return b0 > b1 ? b0 : b1; - } - - public static float lesser(float b0, float b1) { - return b0 > b1 ? b1 : b0; - } - - public static double greater(double b0, double b1) { - return b0 > b1 ? b0 : b1; - } - - public static double lesser(double b0, double b1) { - return b0 > b1 ? b1 : b0; - } - - /** Helper for implementing MAX. Somewhat similar to GREATEST operator. */ - public static > T greater(T b0, T b1) { - return b0 == null || b0.compareTo(b1) < 0 ? b1 : b0; - } - - /** GREATEST operator. */ - public static > T greatest(T b0, T b1) { - return b0 == null || b1 != null && b0.compareTo(b1) < 0 ? b1 : b0; - } - - /** Boolean comparison. */ - public static int compare(boolean x, boolean y) { - return x == y ? 0 : x ? 1 : -1; - } - - /** CAST(FLOAT AS VARCHAR). */ - public static String toString(float x) { - if (x == 0) { - return "0E0"; - } - BigDecimal bigDecimal = new BigDecimal(x, MathContext.DECIMAL32).stripTrailingZeros(); - final String s = bigDecimal.toString(); - return s.replaceAll("0*E", "E").replace("E+", "E"); - } - - /** CAST(DOUBLE AS VARCHAR). */ - public static String toString(double x) { - if (x == 0) { - return "0E0"; - } - BigDecimal bigDecimal = new BigDecimal(x, MathContext.DECIMAL64).stripTrailingZeros(); - final String s = bigDecimal.toString(); - return s.replaceAll("0*E", "E").replace("E+", "E"); - } - - /** CAST(DECIMAL AS VARCHAR). */ - public static String toString(BigDecimal x) { - final String s = x.toString(); - if (s.startsWith("0")) { - // we want ".1" not "0.1" - return s.substring(1); - } else if (s.startsWith("-0")) { - // we want "-.1" not "-0.1" - return "-" + s.substring(2); - } else { - return s; - } - } - - /** CAST(BOOLEAN AS VARCHAR). */ - public static String toString(boolean x) { - // Boolean.toString returns lower case -- no good. - return x ? "TRUE" : "FALSE"; - } - - @NonDeterministic - private static Object cannotConvert(Object o, Class toType) { - throw new RuntimeException("Cannot convert " + o + " to " + toType); - } - - /** CAST(VARCHAR AS BOOLEAN). */ - public static boolean toBoolean(String s) { - s = trim_(s, true, true, ' '); - if (s.equalsIgnoreCase("TRUE")) { - return true; - } else if (s.equalsIgnoreCase("FALSE")) { - return false; - } else { - throw new RuntimeException("Invalid character for cast"); - } - } - - public static boolean toBoolean(Number number) { - return !number.equals(0); - } - - public static boolean toBoolean(Object o) { - return o instanceof Boolean ? (Boolean) o : o instanceof Number ? toBoolean((Number) o) : o instanceof String ? toBoolean((String) o) : (Boolean) cannotConvert(o, boolean.class); - } - - // Don't need parseByte etc. - Byte.parseByte is sufficient. - - public static byte toByte(Object o) { - return o instanceof Byte ? (Byte) o : o instanceof Number ? toByte((Number) o) : Byte.parseByte(o.toString()); - } - - public static byte toByte(Number number) { - return number.byteValue(); - } - - public static char toChar(String s) { - return s.charAt(0); - } - - public static Character toCharBoxed(String s) { - return s.charAt(0); - } - - public static short toShort(String s) { - return Short.parseShort(s.trim()); - } - - public static short toShort(Number number) { - return number.shortValue(); - } - - public static short toShort(Object o) { - return o instanceof Short ? (Short) o : o instanceof Number ? toShort((Number) o) : o instanceof String ? toShort((String) o) : (Short) cannotConvert(o, short.class); - } - - public static int toInt(java.util.Date v) { - return toInt(v, LOCAL_TZ); - } - - public static int toInt(java.util.Date v, TimeZone timeZone) { - return (int) (toLong(v, timeZone) / DateTimeUtils.MILLIS_PER_DAY); - } - - public static Integer toIntOptional(java.util.Date v) { - return v == null ? null : toInt(v); - } - - public static Integer toIntOptional(java.util.Date v, TimeZone timeZone) { - return v == null ? null : toInt(v, timeZone); - } - - public static long toLong(Date v) { - return toLong(v, LOCAL_TZ); - } - - public static int toInt(java.sql.Time v) { - return (int) (toLong(v) % DateTimeUtils.MILLIS_PER_DAY); - } - - public static Integer toIntOptional(java.sql.Time v) { - return v == null ? null : toInt(v); - } - - public static int toInt(String s) { - return Integer.parseInt(s.trim()); - } - - public static int toInt(Number number) { - return number.intValue(); - } - - public static int toInt(Object o) { - return o instanceof Integer ? (Integer) o : o instanceof Number ? toInt((Number) o) : o instanceof String ? toInt((String) o) : (Integer) cannotConvert(o, int.class); - } - - public static long toLong(Timestamp v) { - return toLong(v, LOCAL_TZ); - } - - // mainly intended for java.sql.Timestamp but works for other dates also - public static long toLong(java.util.Date v, TimeZone timeZone) { - final long time = v.getTime(); - return time + timeZone.getOffset(time); - } - - // mainly intended for java.sql.Timestamp but works for other dates also - public static Long toLongOptional(java.util.Date v) { - return v == null ? null : toLong(v, LOCAL_TZ); - } - - public static Long toLongOptional(Timestamp v, TimeZone timeZone) { - if (v == null) { - return null; - } - return toLong(v, LOCAL_TZ); - } - - public static long toLong(String s) { - if (s.startsWith("199") && s.contains(":")) { - return Timestamp.valueOf(s).getTime(); - } - return Long.parseLong(s.trim()); - } - - public static long toLong(Number number) { - return number.longValue(); - } - - public static long toLong(Object o) { - return o instanceof Long ? (Long) o : o instanceof Number ? toLong((Number) o) : o instanceof String ? toLong((String) o) : (Long) cannotConvert(o, long.class); - } - - public static float toFloat(String s) { - return Float.parseFloat(s.trim()); - } - - public static float toFloat(Number number) { - return number.floatValue(); - } - - public static float toFloat(Object o) { - return o instanceof Float ? (Float) o : o instanceof Number ? toFloat((Number) o) : o instanceof String ? toFloat((String) o) : (Float) cannotConvert(o, float.class); - } - - public static double toDouble(String s) { - return Double.parseDouble(s.trim()); - } - - public static double toDouble(Number number) { - return number.doubleValue(); - } - - public static double toDouble(Object o) { - return o instanceof Double ? (Double) o : o instanceof Number ? toDouble((Number) o) : o instanceof String ? toDouble((String) o) : (Double) cannotConvert(o, double.class); - } - - public static BigDecimal toBigDecimal(String s) { - return new BigDecimal(s.trim()); - } - - public static BigDecimal toBigDecimal(Number number) { - // There are some values of "long" that cannot be represented as "double". - // Not so "int". If it isn't a long, go straight to double. - return number instanceof BigDecimal ? (BigDecimal) number : number instanceof BigInteger ? new BigDecimal((BigInteger) number) : number instanceof Long ? new BigDecimal(number.longValue()) : new BigDecimal(number.doubleValue()); - } - - public static BigDecimal toBigDecimal(Object o) { - return o instanceof Number ? toBigDecimal((Number) o) : toBigDecimal(o.toString()); - } - - // Don't need shortValueOf etc. - Short.valueOf is sufficient. - - /** Helper for CAST(... AS VARCHAR(maxLength)). */ - public static String truncate(String s, int maxLength) { - return s == null ? null : s.length() > maxLength ? s.substring(0, maxLength) : s; - } - - /** Helper for CAST(... AS VARBINARY(maxLength)). */ - public static ByteString truncate(ByteString s, int maxLength) { - return s == null ? null : s.length() > maxLength ? s.substring(0, maxLength) : s; - } - - /** SQL {@code POSITION(seek IN string)} function. */ - public static int position(String seek, String s) { - return s.indexOf(seek) + 1; - } - - /** SQL {@code POSITION(seek IN string)} function. */ - public static int position(ByteString seek, ByteString s) { - return s.indexOf(seek) + 1; - } - - /** Helper for rounding. Truncate(12345, 1000) returns 12000. */ - public static long round(long v, long x) { - return truncate(v + x / 2, x); - } - - /** Helper for rounding. Truncate(12345, 1000) returns 12000. */ - public static long truncate(long v, long x) { - long remainder = v % x; - if (remainder < 0) { - remainder += x; - } - return v - remainder; - } - - /** Helper for rounding. Truncate(12345, 1000) returns 12000. */ - public static int round(int v, int x) { - return truncate(v + x / 2, x); - } - - /** Helper for rounding. Truncate(12345, 1000) returns 12000. */ - public static int truncate(int v, int x) { - int remainder = v % x; - if (remainder < 0) { - remainder += x; - } - return v - remainder; - } - - /** SQL {@code CURRENT_TIMESTAMP} function. */ - @NonDeterministic - public static long currentTimestamp(DataContext root) { - // Cast required for JDK 1.6. - return (Long) DataContext.Variable.CURRENT_TIMESTAMP.get(root); - } - - /** SQL {@code CURRENT_TIME} function. */ - @NonDeterministic - public static int currentTime(DataContext root) { - int time = (int) (currentTimestamp(root) % DateTimeUtils.MILLIS_PER_DAY); - if (time < 0) { - time += DateTimeUtils.MILLIS_PER_DAY; - } - return time; - } - - /** SQL {@code CURRENT_DATE} function. */ - @NonDeterministic - public static int currentDate(DataContext root) { - final long timestamp = currentTimestamp(root); - int date = (int) (timestamp / DateTimeUtils.MILLIS_PER_DAY); - final int time = (int) (timestamp % DateTimeUtils.MILLIS_PER_DAY); - if (time < 0) { - --date; - } - return date; - } - - /** SQL {@code LOCAL_TIMESTAMP} function. */ - @NonDeterministic - public static long localTimestamp(DataContext root) { - // Cast required for JDK 1.6. - return (Long) DataContext.Variable.LOCAL_TIMESTAMP.get(root); - } - - /** SQL {@code LOCAL_TIME} function. */ - @NonDeterministic - public static int localTime(DataContext root) { - return (int) (localTimestamp(root) % DateTimeUtils.MILLIS_PER_DAY); - } - - /** Helper for "array element reference". Caller has already ensured that - * array and index are not null. Index is 1-based, per SQL. */ - public static Object arrayItem(List list, int item) { - if (item < 1 || item > list.size()) { - return null; - } - return list.get(item - 1); - } - - /** Helper for "map element reference". Caller has already ensured that - * array and index are not null. Index is 1-based, per SQL. */ - public static Object mapItem(Map map, Object item) { - return map.get(item); - } - - /** Implements the {@code [ ... ]} operator on an object whose type is not - * known until runtime. - */ - public static Object item(Object object, Object index) { - if (object instanceof Map) { - return ((Map) object).get(index); - } - if (object instanceof List && index instanceof Number) { - List list = (List) object; - return list.get(((Number) index).intValue()); - } - return null; - } - - /** NULL → FALSE, FALSE → FALSE, TRUE → TRUE. */ - public static boolean isTrue(Boolean b) { - return b != null && b; - } - - /** NULL → TRUE, FALSE → FALSE, TRUE → TRUE. */ - public static boolean isNotFalse(Boolean b) { - return b == null || b; - } - - /** NULL → NULL, FALSE → TRUE, TRUE → FALSE. */ - public static Boolean not(Boolean b) { - return (b == null) ? null : !b; - } - - /** Converts a JDBC array to a list. */ - public static List arrayToList(final java.sql.Array a) { - if (a == null) { - return null; - } - try { - return Primitive.asList(a.getArray()); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - /** Support the {@code CURRENT VALUE OF sequence} operator. */ - @NonDeterministic - public static long sequenceCurrentValue(String key) { - return getAtomicLong(key).get(); - } - - /** Support the {@code NEXT VALUE OF sequence} operator. */ - @NonDeterministic - public static long sequenceNextValue(String key) { - return getAtomicLong(key).incrementAndGet(); - } - - private static AtomicLong getAtomicLong(String key) { - final Map map = THREAD_SEQUENCES.get(); - AtomicLong atomic = map.get(key); - if (atomic == null) { - atomic = new AtomicLong(); - map.put(key, atomic); - } - return atomic; - } - - /** Support the SLICE function. */ - public static List slice(List list) { - return list; - } - - /** Support the ELEMENT function. */ - public static Object element(List list) { - switch (list.size()) { - case 0: - return null; - case 1: - return list.get(0); - default: - throw new RuntimeException("more than one value"); - } - } - - /** Returns a lambda that converts a list to an enumerable. */ - public static Function1, Enumerable> listToEnumerable() { - //noinspection unchecked - return (Function1, Enumerable>) (Function1) LIST_AS_ENUMERABLE; - } - -} - -// End SqlFunctions.java diff --git a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java index 0893408..c184f0b 100644 --- a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java +++ b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java @@ -15,26 +15,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.calcite.sql2rel; - -import static org.apache.calcite.sql.SqlUtil.stripAs; -import static org.apache.calcite.util.Static.RESOURCE; -import java.lang.reflect.Type; -import java.math.BigDecimal; -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.TreeSet; -import java.util.logging.Level; -import java.util.logging.Logger; +package org.apache.calcite.sql2rel; import org.apache.calcite.linq4j.Ord; import org.apache.calcite.plan.Convention; @@ -58,6 +40,7 @@ import org.apache.calcite.rel.core.Join; import org.apache.calcite.rel.core.JoinInfo; 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.Sample; import org.apache.calcite.rel.core.Uncollect; import org.apache.calcite.rel.logical.LogicalAggregate; @@ -161,7 +144,6 @@ import org.apache.calcite.util.NlsString; import org.apache.calcite.util.NumberUtil; import org.apache.calcite.util.Pair; import org.apache.calcite.util.Util; -import org.apache.calcite.util.mapping.Mappings; import org.apache.calcite.util.trace.CalciteTrace; import com.google.common.base.Function; @@ -173,6 +155,25 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.apache.calcite.sql.SqlUtil.stripAs; +import static org.apache.calcite.util.Static.RESOURCE; + /* * OVERRIDE POINT: * - getInSubqueryThreshold(), was `20`, now `Integer.MAX_VALUE` @@ -1449,6 +1450,12 @@ public class SqlToRelConverter { SqlCall aggCall = call.operand(0); SqlNode windowOrRef = call.operand(1); final SqlWindow window = validator.resolveWindow(windowOrRef, bb.scope, true); + // ROW_NUMBER() expects specific kind of framing. + if (aggCall.getOperator() == SqlStdOperatorTable.ROW_NUMBER) { + window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO)); + window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO)); + window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO)); + } final SqlNodeList partitionList = window.getPartitionList(); final ImmutableList.Builder partitionKeys = ImmutableList.builder(); for (SqlNode partition : partitionList) { @@ -1577,11 +1584,15 @@ public class SqlToRelConverter { RelNode rightRel = rightBlackboard.root; JoinRelType convertedJoinType = convertJoinType(joinType); RexNode conditionExp; + final SqlValidatorNamespace leftNamespace = validator.getNamespace(left); + final SqlValidatorNamespace rightNamespace = validator.getNamespace(right); if (isNatural) { - final List columnList = SqlValidatorUtil.deriveNaturalJoinColumnList(validator.getNamespace(left).getRowType(), validator.getNamespace(right).getRowType()); - conditionExp = convertUsing(leftRel, rightRel, columnList); + final RelDataType leftRowType = leftNamespace.getRowType(); + final RelDataType rightRowType = rightNamespace.getRowType(); + final List columnList = SqlValidatorUtil.deriveNaturalJoinColumnList(leftRowType, rightRowType); + conditionExp = convertUsing(leftNamespace, rightNamespace, columnList); } else { - conditionExp = convertJoinCondition(fromBlackboard, join.getCondition(), join.getConditionType(), leftRel, rightRel); + conditionExp = convertJoinCondition(fromBlackboard, leftNamespace, rightNamespace, join.getCondition(), join.getConditionType(), leftRel, rightRel); } final RelNode joinRel = createJoin(fromBlackboard, leftRel, rightRel, conditionExp, convertedJoinType); @@ -1777,58 +1788,9 @@ public class SqlToRelConverter { } } - final List extraLeftExprs = new ArrayList<>(); - final List extraRightExprs = new ArrayList<>(); - final int leftCount = leftRel.getRowType().getFieldCount(); - final int rightCount = rightRel.getRowType().getFieldCount(); - if (!containsGet(joinCond)) { - joinCond = pushDownJoinConditions(joinCond, leftCount, rightCount, extraLeftExprs, extraRightExprs); - } - if (!extraLeftExprs.isEmpty()) { - final List fields = leftRel.getRowType().getFieldList(); - leftRel = RelOptUtil.createProject(leftRel, new AbstractList>() { - @Override - public int size() { - return leftCount + extraLeftExprs.size(); - } - - @Override - public Pair get(int index) { - if (index < leftCount) { - RelDataTypeField field = fields.get(index); - return Pair. of(new RexInputRef(index, field.getType()), field.getName()); - } else { - return Pair.of(extraLeftExprs.get(index - leftCount), null); - } - } - }, true); - } - if (!extraRightExprs.isEmpty()) { - final List fields = rightRel.getRowType().getFieldList(); - final int newLeftCount = leftCount + extraLeftExprs.size(); - rightRel = RelOptUtil.createProject(rightRel, new AbstractList>() { - @Override - public int size() { - return rightCount + extraRightExprs.size(); - } + final Join originalJoin = (Join) RelFactories.DEFAULT_JOIN_FACTORY.createJoin(leftRel, rightRel, joinCond, joinType, ImmutableSet. of(), false); - @Override - public Pair get(int index) { - if (index < rightCount) { - RelDataTypeField field = fields.get(index); - return Pair. of(new RexInputRef(index, field.getType()), field.getName()); - } else { - return Pair.of(RexUtil.shift(extraRightExprs.get(index - rightCount), -newLeftCount), null); - } - } - }, true); - } - RelNode join = createJoin(leftRel, rightRel, joinCond, joinType, ImmutableSet. of()); - if (!extraLeftExprs.isEmpty() || !extraRightExprs.isEmpty()) { - Mappings.TargetMapping mapping = Mappings.createShiftMapping(leftCount + extraLeftExprs.size() + rightCount + extraRightExprs.size(), 0, 0, leftCount, leftCount, leftCount + extraLeftExprs.size(), rightCount); - return RelOptUtil.createProject(join, mapping); - } - return join; + return RelOptUtil.pushDownJoinConditions(originalJoin); } private static boolean containsGet(RexNode node) { @@ -1849,92 +1811,6 @@ public class SqlToRelConverter { } /** - * Pushes down parts of a join condition. For example, given - * "emp JOIN dept ON emp.deptno + 1 = dept.deptno", adds a project above - * "emp" that computes the expression - * "emp.deptno + 1". The resulting join condition is a simple combination - * of AND, equals, and input fields. - */ - private RexNode pushDownJoinConditions(RexNode node, int leftCount, int rightCount, List extraLeftExprs, List extraRightExprs) { - switch (node.getKind()) { - case AND: - case OR: - case EQUALS: - final RexCall call = (RexCall) node; - final List list = new ArrayList<>(); - List operands = Lists.newArrayList(call.getOperands()); - for (int i = 0; i < operands.size(); i++) { - RexNode operand = operands.get(i); - final int left2 = leftCount + extraLeftExprs.size(); - final int right2 = rightCount + extraRightExprs.size(); - final RexNode e = pushDownJoinConditions(operand, leftCount, rightCount, extraLeftExprs, extraRightExprs); - final List remainingOperands = Util.skip(operands, i + 1); - final int left3 = leftCount + extraLeftExprs.size(); - final int right3 = rightCount + extraRightExprs.size(); - fix(remainingOperands, left2, left3); - fix(list, left2, left3); - list.add(e); - } - if (!list.equals(call.getOperands())) { - return call.clone(call.getType(), list); - } - return call; - case INPUT_REF: - case LITERAL: - return node; - default: - ImmutableBitSet bits = RelOptUtil.InputFinder.bits(node); - final int mid = leftCount + extraLeftExprs.size(); - switch (Side.of(bits, mid)) { - case LEFT: - fix(extraRightExprs, mid, mid + 1); - extraLeftExprs.add(node); - return new RexInputRef(mid, node.getType()); - case RIGHT: - final int index2 = mid + rightCount + extraRightExprs.size(); - extraRightExprs.add(node); - return new RexInputRef(index2, node.getType()); - case BOTH: - case EMPTY: - default: - return node; - } - } - } - - private void fix(List operands, int before, int after) { - if (before == after) { - return; - } - for (int i = 0; i < operands.size(); i++) { - RexNode node = operands.get(i); - operands.set(i, RexUtil.shift(node, before, after - before)); - } - } - - /** - * Categorizes whether a bit set contains bits left and right of a - * line. - */ - enum Side { - LEFT, RIGHT, BOTH, EMPTY; - - static Side of(ImmutableBitSet bitSet, int middle) { - final int firstBit = bitSet.nextSetBit(0); - if (firstBit < 0) { - return EMPTY; - } - if (firstBit >= middle) { - return RIGHT; - } - if (bitSet.nextSetBit(middle) < 0) { - return LEFT; - } - return BOTH; - } - } - - /** * Determines whether a subquery is non-correlated. Note that a * non-correlated subquery can contain correlated references, provided those * references do not reference select statements that are parents of the @@ -1986,7 +1862,7 @@ public class SqlToRelConverter { return Collections.emptyList(); } - private RexNode convertJoinCondition(Blackboard bb, SqlNode condition, JoinConditionType conditionType, RelNode leftRel, RelNode rightRel) { + private RexNode convertJoinCondition(Blackboard bb, SqlValidatorNamespace leftNamespace, SqlValidatorNamespace rightNamespace, SqlNode condition, JoinConditionType conditionType, RelNode leftRel, RelNode rightRel) { if (condition == null) { return rexBuilder.makeLiteral(true); } @@ -2004,7 +1880,7 @@ public class SqlToRelConverter { String name = id.getSimple(); nameList.add(name); } - return convertUsing(leftRel, rightRel, nameList); + return convertUsing(leftNamespace, rightNamespace, nameList); default: throw Util.unexpected(conditionType); } @@ -2015,23 +1891,24 @@ public class SqlToRelConverter { * from NATURAL JOIN. "a JOIN b USING (x, y)" becomes "a.x = b.x AND a.y = * b.y". Returns null if the column list is empty. * - * @param leftRel Left input to the join - * @param rightRel Right input to the join + * @param leftNamespace Namespace of left input to join + * @param rightNamespace Namespace of right input to join * @param nameList List of column names to join on * @return Expression to match columns from name list, or true if name list * is empty */ - private RexNode convertUsing(RelNode leftRel, RelNode rightRel, List nameList) { + private RexNode convertUsing(SqlValidatorNamespace leftNamespace, SqlValidatorNamespace rightNamespace, List nameList) { final List list = Lists.newArrayList(); for (String name : nameList) { - final RelDataType leftRowType = leftRel.getRowType(); - RelDataTypeField leftField = catalogReader.field(leftRowType, name); - RexNode left = rexBuilder.makeInputRef(leftField.getType(), leftField.getIndex()); - final RelDataType rightRowType = rightRel.getRowType(); - RelDataTypeField rightField = catalogReader.field(rightRowType, name); - RexNode right = rexBuilder.makeInputRef(rightField.getType(), leftRowType.getFieldList().size() + rightField.getIndex()); - RexNode equalsCall = rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, left, right); - list.add(equalsCall); + List operands = new ArrayList<>(); + int offset = 0; + for (SqlValidatorNamespace n : ImmutableList.of(leftNamespace, rightNamespace)) { + final RelDataType rowType = n.getRowType(); + final RelDataTypeField field = catalogReader.field(rowType, name); + operands.add(rexBuilder.makeInputRef(field.getType(), offset + field.getIndex())); + offset += rowType.getFieldList().size(); + } + list.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, operands)); } return RexUtil.composeConjunction(rexBuilder, list, false); } @@ -2866,6 +2743,7 @@ public class SqlToRelConverter { for (int i = 0; i < joinList.size(); i++) { Object o = joinList.get(i); if (o instanceof List) { + @SuppressWarnings("unchecked") List projectList = (List) o; final List selectList = new ArrayList<>(); final List fieldNameList = new ArrayList<>(); @@ -2892,28 +2770,11 @@ public class SqlToRelConverter { RelNode ret = (RelNode) joinList.get(0); for (int i = 1; i < joinList.size(); i++) { RelNode relNode = (RelNode) joinList.get(i); - ret = createJoin(ret, relNode, rexBuilder.makeLiteral(true), JoinRelType.INNER, ImmutableSet. of()); + ret = RelFactories.DEFAULT_JOIN_FACTORY.createJoin(ret, relNode, rexBuilder.makeLiteral(true), JoinRelType.INNER, ImmutableSet. of(), false); } return ret; } - /** - * Factory method that creates a join. - * A subclass can override to use a different kind of join. - * - * @param left Left input - * @param right Right input - * @param condition Join condition - * @param joinType Join type - * @param variablesStopped Set of names of variables which are set by the - * LHS and used by the RHS and are not available to - * nodes above this LogicalJoin in the tree - * @return A relational expression representing a join - */ - protected RelNode createJoin(RelNode left, RelNode right, RexNode condition, JoinRelType joinType, Set variablesStopped) { - return LogicalJoin.create(left, right, condition, joinType, variablesStopped); - } - private void convertSelectList(Blackboard bb, SqlSelect select, List orderList) { SqlNodeList selectList = select.getSelectList(); selectList = validator.expandStar(selectList, select, false); @@ -3779,6 +3640,10 @@ public class SqlToRelConverter { // for now do not detect aggregates in subqueries. return null; } + // ignore window aggregates and ranking functions (associated with OVER operator) + if (call.getOperator().getKind() == SqlKind.OVER) { + return null; + } if (call.getOperator().isAggregator()) { translateAgg(call, null, call); return null; @@ -4067,7 +3932,7 @@ public class SqlToRelConverter { exprs.set(0, reinterpretCast ? rexBuilder.makeReinterpretCast(histogramType, exprs.get(0), rexBuilder.makeLiteral(false)) : rexBuilder.makeCast(histogramType, exprs.get(0))); } - RexCallBinding bind = new RexCallBinding(rexBuilder.getTypeFactory(), SqlStdOperatorTable.HISTOGRAM_AGG, exprs); + RexCallBinding bind = new RexCallBinding(rexBuilder.getTypeFactory(), SqlStdOperatorTable.HISTOGRAM_AGG, exprs, ImmutableList. of()); RexNode over = rexBuilder.makeOver(SqlStdOperatorTable.HISTOGRAM_AGG.inferReturnType(bind), SqlStdOperatorTable.HISTOGRAM_AGG, exprs, partitionKeys, orderKeys, lowerBound, upperBound, window.isRows(), window.isAllowPartial(), false); @@ -4152,6 +4017,10 @@ public class SqlToRelConverter { @Override public Void visit(SqlCall call) { + // ignore window aggregates and ranking functions (associated with OVER operator) + if (call.getOperator().getKind() == SqlKind.OVER) { + return null; + } if (call.getOperator().isAggregator()) { list.add(call); return null; diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java index 49f58fd..79defcc 100644 --- a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java +++ b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java @@ -50,7 +50,7 @@ public class KylinMeta extends MetaImpl { // insert/update/delete go this path, ignorable for Kylin @Override - public StatementHandle prepare(ConnectionHandle ch, String sql, int maxRowCount) { + public StatementHandle prepare(ConnectionHandle ch, String sql, long maxRowCount) { StatementHandle result = super.createStatement(ch); result.signature = connection().mockPreparedSignature(sql); return result; @@ -58,16 +58,15 @@ public class KylinMeta extends MetaImpl { // mimic from CalciteMetaImpl, real execution happens via callback in KylinResultSet.execute() @Override - public ExecuteResult prepareAndExecute(ConnectionHandle ch, String sql, int maxRowCount, PrepareCallback callback) { - final StatementHandle sh; + public ExecuteResult prepareAndExecute(StatementHandle sh, String sql, long maxRowCount, PrepareCallback callback) { try { synchronized (callback.getMonitor()) { callback.clear(); - sh = prepare(ch, sql, maxRowCount); + sh.signature = connection().mockPreparedSignature(sql); callback.assign(sh.signature, null, -1); } callback.execute(); - final MetaResultSet metaResultSet = MetaResultSet.create(ch.id, sh.id, false, sh.signature, null); + final MetaResultSet metaResultSet = MetaResultSet.create(sh.connectionId, sh.id, false, sh.signature, null); return new ExecuteResult(ImmutableList.of(metaResultSet)); } catch (SQLException e) { throw new RuntimeException(e); diff --git a/pom.xml b/pom.xml index ae9714c..d3ec961 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ 3.1.2.RELEASE - 1.3.0-incubating + 1.4.0-incubating 2.6.0 diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPJoinRel.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPJoinRel.java index 2b3d3e3..30f059c 100644 --- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPJoinRel.java +++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPJoinRel.java @@ -18,6 +18,7 @@ package org.apache.kylin.query.relnode; +import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; @@ -226,13 +227,32 @@ public class OLAPJoinRel extends EnumerableJoin implements OLAPRel { } } + // workaround that EnumerableJoin constructor is protected + private static Constructor constr; + static { + try { + constr = EnumerableJoin.class.getDeclaredConstructor(RelOptCluster.class, // + RelTraitSet.class, // + RelNode.class, // + RelNode.class, // + RexNode.class, // + ImmutableIntList.class, // + ImmutableIntList.class, // + JoinRelType.class, // + Set.class); + constr.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override public EnumerableRel implementEnumerable(List inputs) { if (this.hasSubQuery) { try { - return new EnumerableJoin(getCluster(), getCluster().traitSetOf(EnumerableConvention.INSTANCE), // + return constr.newInstance(getCluster(), getCluster().traitSetOf(EnumerableConvention.INSTANCE), // inputs.get(0), inputs.get(1), condition, leftKeys, rightKeys, joinType, variablesStopped); - } catch (InvalidRelException e) { + } catch (Exception e) { throw new IllegalStateException("Can't create EnumerableJoin!", e); } } else { diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java index b1d8d1a..d2661b4 100644 --- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java +++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java @@ -47,6 +47,7 @@ import org.apache.calcite.rel.rules.FilterJoinRule; import org.apache.calcite.rel.rules.FilterProjectTransposeRule; import org.apache.calcite.rel.rules.JoinCommuteRule; import org.apache.calcite.rel.rules.JoinPushThroughJoinRule; +import org.apache.calcite.rel.rules.ReduceExpressionsRule; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rel.type.RelDataTypeField; @@ -123,11 +124,21 @@ public class OLAPTableScan extends TableScan implements OLAPRel, EnumerableRel { planner.addRule(OLAPLimitRule.INSTANCE); planner.addRule(OLAPSortRule.INSTANCE); + // CalcitePrepareImpl.CONSTANT_REDUCTION_RULES + planner.addRule(ReduceExpressionsRule.PROJECT_INSTANCE); + planner.addRule(ReduceExpressionsRule.FILTER_INSTANCE); + planner.addRule(ReduceExpressionsRule.CALC_INSTANCE); + planner.addRule(ReduceExpressionsRule.JOIN_INSTANCE); + // the ValuesReduceRule breaks query test somehow... + // planner.addRule(ValuesReduceRule.FILTER_INSTANCE); + // planner.addRule(ValuesReduceRule.PROJECT_FILTER_INSTANCE); + // planner.addRule(ValuesReduceRule.PROJECT_INSTANCE); + // since join is the entry point, we can't push filter past join planner.removeRule(FilterJoinRule.FILTER_ON_JOIN); planner.removeRule(FilterJoinRule.JOIN); - // TODO : since we don't have statistic of table, the optimization of join is too cost + // since we don't have statistic of table, the optimization of join is too cost planner.removeRule(JoinCommuteRule.INSTANCE); planner.removeRule(JoinPushThroughJoinRule.LEFT); planner.removeRule(JoinPushThroughJoinRule.RIGHT); -- 1.9.5.msysgit.0