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 2017/12/11 23:15:11 UTC
[1/4] calcite git commit: [CALCITE-2080] Query with NOT IN operator
and literal throws AssertionError: 'Cast for just nullability not allowed'
(Volodymyr Vysotskyi)
Repository: calcite
Updated Branches:
refs/heads/master 314b5b78b -> b60b67eb8
[CALCITE-2080] Query with NOT IN operator and literal throws AssertionError: 'Cast for just nullability not allowed' (Volodymyr Vysotskyi)
Alternative fix (in SqlToRelConverter rather than RelOptUtil);
fix query formatting in SqlToRelConverterTest. (Julian Hyde)
Close apache/calcite#579
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/04cbdb2c
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/04cbdb2c
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/04cbdb2c
Branch: refs/heads/master
Commit: 04cbdb2cead5985322db737e1b0b8ce2259a7306
Parents: 314b5b7
Author: Volodymyr Vysotskyi <vv...@gmail.com>
Authored: Thu Dec 7 18:26:38 2017 +0200
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Dec 11 02:11:11 2017 -0800
----------------------------------------------------------------------
.../rel/rules/FilterProjectTransposeRule.java | 10 +-
.../org/apache/calcite/rex/RexSimplify.java | 5 +-
.../java/org/apache/calcite/rex/RexUtil.java | 11 ++
.../calcite/sql2rel/SqlToRelConverter.java | 6 +-
.../calcite/test/SqlToRelConverterTest.java | 96 +++++++++---------
.../calcite/test/SqlToRelConverterTest.xml | 101 ++++++++++++-------
6 files changed, 134 insertions(+), 95 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
index aaec8a8..3bdb5f5 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
@@ -16,7 +16,6 @@
*/
package org.apache.calcite.rel.rules;
-import org.apache.calcite.plan.RelOptPredicateList;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelOptRuleOperand;
@@ -27,7 +26,6 @@ import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexOver;
-import org.apache.calcite.rex.RexSimplify;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelBuilderFactory;
@@ -120,13 +118,9 @@ public class FilterProjectTransposeRule extends RelOptRule {
final RelBuilder relBuilder = call.builder();
RelNode newFilterRel;
if (copyFilter) {
- final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
- final RexSimplify simplify =
- new RexSimplify(relBuilder.getRexBuilder(), predicates, false,
- RexUtil.EXECUTOR);
- newCondition = simplify.removeNullabilityCast(newCondition);
newFilterRel = filter.copy(filter.getTraitSet(), project.getInput(),
- newCondition);
+ RexUtil.removeNullabilityCast(relBuilder.getTypeFactory(),
+ newCondition));
} else {
newFilterRel =
relBuilder.push(project.getInput()).filter(newCondition).build();
http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
index cd42c81..34e3814 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -953,10 +953,7 @@ public class RexSimplify {
*
* <p>For example, {@code CAST(1 = 0 AS BOOLEAN)} becomes {@code 1 = 0}. */
public RexNode removeNullabilityCast(RexNode e) {
- while (RexUtil.isNullabilityCast(rexBuilder.getTypeFactory(), e)) {
- e = ((RexCall) e).operands.get(0);
- }
- return e;
+ return RexUtil.removeNullabilityCast(rexBuilder.getTypeFactory(), e);
}
private static <C extends Comparable<C>> RexNode processRange(
http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index 1dd0396..6f467be 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -310,6 +310,17 @@ public class RexUtil {
return false;
}
+ /** Removes any casts that change nullability but not type.
+ *
+ * <p>For example, {@code CAST(1 = 0 AS BOOLEAN)} becomes {@code 1 = 0}. */
+ public static RexNode removeNullabilityCast(RelDataTypeFactory typeFactory,
+ RexNode node) {
+ while (isNullabilityCast(typeFactory, node)) {
+ node = ((RexCall) node).operands.get(0);
+ }
+ return node;
+ }
+
/** Creates a map containing each (e, constant) pair that occurs within
* a predicate list.
*
http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index ede2daf..e1b0d17 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -963,15 +963,17 @@ public class SqlToRelConverter {
SqlNode newWhere = pushDownNotForIn(bb.scope, where);
replaceSubQueries(bb, newWhere, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
final RexNode convertedWhere = bb.convertExpression(newWhere);
+ final RexNode convertedWhere2 =
+ RexUtil.removeNullabilityCast(typeFactory, convertedWhere);
// only allocate filter if the condition is not TRUE
- if (convertedWhere.isAlwaysTrue()) {
+ if (convertedWhere2.isAlwaysTrue()) {
return;
}
final RelFactories.FilterFactory factory =
RelFactories.DEFAULT_FILTER_FACTORY;
- final RelNode filter = factory.createFilter(bb.root, convertedWhere);
+ final RelNode filter = factory.createFilter(bb.root, convertedWhere2);
final RelNode r;
final CorrelationUse p = getCorrelationUse(bb, filter);
if (p != null) {
http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index de0b268..6c3651a 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -2371,6 +2371,19 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
sql(sql).with(getTesterWithDynamicTable()).ok();
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-2080">[CALCITE-2080]
+ * Query with NOT IN operator and literal fails throws AssertionError: 'Cast
+ * for just nullability not allowed'</a>. */
+ @Test public void testNotInWithLiteral() {
+ final String sql = "SELECT *\n"
+ + "FROM SALES.NATION\n"
+ + "WHERE n_name NOT IN\n"
+ + " (SELECT ''\n"
+ + " FROM SALES.NATION)";
+ sql(sql).with(getTesterWithDynamicTable()).ok();
+ }
+
/**
* Test case for Dynamic Table / Dynamic Star support
* <a href="https://issues.apache.org/jira/browse/CALCITE-1150">[CALCITE-1150]</a>
@@ -2570,27 +2583,24 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
+ " pattern (strt down+ up+)\n"
+ " define\n"
+ " down as down.mgr < PREV(down.mgr),\n"
- + " up as up.mgr > prev(up.mgr)\n"
- + " ) mr";
+ + " up as up.mgr > prev(up.mgr)) as mr";
sql(sql).ok();
}
@Test public void testMatchRecognizeMeasures1() {
final String sql = "select *\n"
- + " from emp match_recognize\n"
- + " (\n"
- + " partition by job, sal\n"
- + " order by job asc, sal desc\n"
- + " measures MATCH_NUMBER() as match_num, "
- + " CLASSIFIER() as var_match, "
- + " STRT.mgr as start_nw,"
- + " LAST(DOWN.mgr) as bottom_nw,"
- + " LAST(up.mgr) as end_nw"
- + " pattern (strt down+ up+)\n"
- + " define\n"
- + " down as down.mgr < PREV(down.mgr),\n"
- + " up as up.mgr > prev(up.mgr)\n"
- + " ) mr";
+ + "from emp match_recognize (\n"
+ + " partition by job, sal\n"
+ + " order by job asc, sal desc\n"
+ + " measures MATCH_NUMBER() as match_num,\n"
+ + " CLASSIFIER() as var_match,\n"
+ + " STRT.mgr as start_nw,\n"
+ + " LAST(DOWN.mgr) as bottom_nw,\n"
+ + " LAST(up.mgr) as end_nw\n"
+ + " pattern (strt down+ up+)\n"
+ + " define\n"
+ + " down as down.mgr < PREV(down.mgr),\n"
+ + " up as up.mgr > prev(up.mgr)) as mr";
sql(sql).ok();
}
@@ -2600,40 +2610,36 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
* columns</a>. */
@Test public void testMatchRecognizeMeasures2() {
final String sql = "select *\n"
- + " from emp match_recognize\n"
- + " (\n"
- + " partition by job\n"
- + " order by sal\n"
- + " measures MATCH_NUMBER() as match_num, "
- + " CLASSIFIER() as var_match, "
- + " STRT.mgr as start_nw,"
- + " LAST(DOWN.mgr) as bottom_nw,"
- + " LAST(up.mgr) as end_nw"
- + " pattern (strt down+ up+)\n"
- + " define\n"
- + " down as down.mgr < PREV(down.mgr),\n"
- + " up as up.mgr > prev(up.mgr)\n"
- + " ) mr";
+ + "from emp match_recognize (\n"
+ + " partition by job\n"
+ + " order by sal\n"
+ + " measures MATCH_NUMBER() as match_num,\n"
+ + " CLASSIFIER() as var_match,\n"
+ + " STRT.mgr as start_nw,\n"
+ + " LAST(DOWN.mgr) as bottom_nw,\n"
+ + " LAST(up.mgr) as end_nw\n"
+ + " pattern (strt down+ up+)\n"
+ + " define\n"
+ + " down as down.mgr < PREV(down.mgr),\n"
+ + " up as up.mgr > prev(up.mgr)) as mr";
sql(sql).ok();
}
@Test public void testMatchRecognizeMeasures3() {
final String sql = "select *\n"
- + " from emp match_recognize\n"
- + " (\n"
- + " partition by job\n"
- + " order by sal\n"
- + " measures MATCH_NUMBER() as match_num, "
- + " CLASSIFIER() as var_match, "
- + " STRT.mgr as start_nw,"
- + " LAST(DOWN.mgr) as bottom_nw,"
- + " LAST(up.mgr) as end_nw"
- + " ALL ROWS PER MATCH"
- + " pattern (strt down+ up+)\n"
- + " define\n"
- + " down as down.mgr < PREV(down.mgr),\n"
- + " up as up.mgr > prev(up.mgr)\n"
- + " ) mr";
+ + "from emp match_recognize (\n"
+ + " partition by job\n"
+ + " order by sal\n"
+ + " measures MATCH_NUMBER() as match_num,\n"
+ + " CLASSIFIER() as var_match,\n"
+ + " STRT.mgr as start_nw,\n"
+ + " LAST(DOWN.mgr) as bottom_nw,\n"
+ + " LAST(up.mgr) as end_nw\n"
+ + " ALL ROWS PER MATCH\n"
+ + " pattern (strt down+ up+)\n"
+ + " define\n"
+ + " down as down.mgr < PREV(down.mgr),\n"
+ + " up as up.mgr > prev(up.mgr)) as mr";
sql(sql).ok();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index c7d2b24..de4a0c1 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -361,7 +361,7 @@ window w as (partition by productId)]]>
</TestCase>
<TestCase name="testArrayOfRecord">
<Resource name="sql">
- <![CDATA[select*from unnest(array(select*from dept))]]>
+ <![CDATA[select employees[1].skills[2+3].desc from dept_nested]]>
</Resource>
<Resource name="plan">
<![CDATA[
@@ -648,7 +648,7 @@ LogicalProject(EXPR$0=[CASE(IS NULL($0), IS NOT NULL($1), IS NULL($1), IS NOT NU
<Resource name="sql">
<![CDATA[select empno is distinct from deptno
from (values (cast(null as int), 1),
- (2, cast(null as int))) as emp(empno, deptno)]]>
+ (2, cast(null as int))) as emp(empno, deptno)]]>
</Resource>
</TestCase>
<TestCase name="testIsNotDistinctFrom">
@@ -1511,7 +1511,7 @@ LogicalSort(offset=[10], fetch=[5])
]]>
</Resource>
</TestCase>
-<TestCase name="testOffsetFetchWithDynamicParameter">
+ <TestCase name="testOffsetFetchWithDynamicParameter">
<Resource name="sql">
<![CDATA[select empno from emp
offset ? rows fetch next ? rows only]]>
@@ -2444,8 +2444,7 @@ LogicalProject(DEPTNO=[$1], EXPR$1=[$2], EXPR$2=[$3], EXPR$3=[$4])
pattern (strt down+ up+)
define
down as down.mgr < PREV(down.mgr),
- up as up.mgr > prev(up.mgr)
- ) mr]]>
+ up as up.mgr > prev(up.mgr)) as mr]]>
</Resource>
<Resource name="plan">
<![CDATA[
@@ -2458,15 +2457,18 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
<TestCase name="testMatchRecognizeMeasures1">
<Resource name="sql">
<![CDATA[select *
- from emp match_recognize
- (
- partition by job, sal
- order by job asc, sal desc
- measures STRT.mgr as start_nw, LAST(DOWN.mgr) as bottom_nw, LAST(up.mgr) as end_nw pattern (strt down+ up+)
- define
- down as down.mgr < PREV(down.mgr),
- up as up.mgr > prev(up.mgr)
- ) mr]]>
+from emp match_recognize (
+ partition by job, sal
+ order by job asc, sal desc
+ measures MATCH_NUMBER() as match_num,
+ CLASSIFIER() as var_match,
+ STRT.mgr as start_nw,
+ LAST(DOWN.mgr) as bottom_nw,
+ LAST(up.mgr) as end_nw
+ pattern (strt down+ up+)
+ define
+ down as down.mgr < PREV(down.mgr),
+ up as up.mgr > prev(up.mgr)) as mr]]>
</Resource>
<Resource name="plan">
<![CDATA[
@@ -2479,15 +2481,18 @@ LogicalProject(JOB=[$0], SAL=[$1], MATCH_NUM=[$2], VAR_MATCH=[$3], START_NW=[$4]
<TestCase name="testMatchRecognizeMeasures2">
<Resource name="sql">
<![CDATA[select *
- from emp match_recognize
- (
- partition by job
- order by sal
- measures STRT.mgr as start_nw, LAST(DOWN.mgr) as bottom_nw, LAST(up.mgr) as end_nw pattern (strt down+ up+)
- define
- down as down.mgr < PREV(down.mgr),
- up as up.mgr > prev(up.mgr)
- ) mr]]>
+from emp match_recognize (
+ partition by job
+ order by sal
+ measures MATCH_NUMBER() as match_num,
+ CLASSIFIER() as var_match,
+ STRT.mgr as start_nw,
+ LAST(DOWN.mgr) as bottom_nw,
+ LAST(up.mgr) as end_nw
+ pattern (strt down+ up+)
+ define
+ down as down.mgr < PREV(down.mgr),
+ up as up.mgr > prev(up.mgr)) as mr]]>
</Resource>
<Resource name="plan">
<![CDATA[
@@ -2500,17 +2505,19 @@ LogicalProject(JOB=[$0], MATCH_NUM=[$1], VAR_MATCH=[$2], START_NW=[$3], BOTTOM_N
<TestCase name="testMatchRecognizeMeasures3">
<Resource name="sql">
<![CDATA[select *
- from emp match_recognize
- (
- partition by job
- order by sal
- measures STRT.mgr as start_nw, LAST(DOWN.mgr) as bottom_nw, LAST(up.mgr) as end_nw
- ALL ROWS PER MATCH
- pattern (strt down+ up+)
- define
- down as down.mgr < PREV(down.mgr),
- up as up.mgr > prev(up.mgr)
- ) mr]]>
+from emp match_recognize (
+ partition by job
+ order by sal
+ measures MATCH_NUMBER() as match_num,
+ CLASSIFIER() as var_match,
+ STRT.mgr as start_nw,
+ LAST(DOWN.mgr) as bottom_nw,
+ LAST(up.mgr) as end_nw
+ ALL ROWS PER MATCH
+ pattern (strt down+ up+)
+ define
+ down as down.mgr < PREV(down.mgr),
+ up as up.mgr > prev(up.mgr)) as mr]]>
</Resource>
<Resource name="plan">
<![CDATA[
@@ -2543,7 +2550,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
<TestCase name="testMatchRecognizePrevDown">
<Resource name="sql">
<![CDATA[SELECT *
-FROM tmp
+FROM emp
MATCH_RECOGNIZE (
MEASURES
STRT.mgr AS start_mgr,
@@ -2611,7 +2618,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
<TestCase name="testPrevClassifier">
<Resource name="sql">
<![CDATA[SELECT *
-FROM tmp
+FROM emp
MATCH_RECOGNIZE (
MEASURES
STRT.mgr AS start_mgr,
@@ -2916,6 +2923,28 @@ LogicalDelta
]]>
</Resource>
</TestCase>
+ <TestCase name="testNotInWithLiteral">
+ <Resource name="sql">
+ <![CDATA[SELECT *
+FROM SALES.NATION
+WHERE n_name NOT IN
+ (SELECT ''
+ FROM SALES.NATION)]]>
+ </Resource>
+ <Resource name="plan">
+ <![CDATA[
+LogicalProject(**=[$1])
+ LogicalFilter(condition=[NOT(AND(IS TRUE($4), IS NOT NULL($2)))])
+ LogicalJoin(condition=[=($2, $3)], joinType=[left])
+ LogicalProject($f0=[$0], $f1=[$1], $f2=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, NATION]])
+ LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
+ LogicalProject($f0=[$0], $f1=[true])
+ LogicalProject(EXPR$0=[''])
+ LogicalTableScan(table=[[CATALOG, SALES, NATION]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testSessionTable">
<Resource name="sql">
<![CDATA[select stream session_start(rowtime, interval '1' hour) as rowtime,
[3/4] calcite git commit: [CALCITE-2066]
RelOptUtil.splitJoinCondition() could not split CASE condition after applying
FilterReduceExpressionsRule (Volodymyr Vysotskyi)
Posted by jh...@apache.org.
[CALCITE-2066] RelOptUtil.splitJoinCondition() could not split CASE condition after applying FilterReduceExpressionsRule (Volodymyr Vysotskyi)
The solution is to less aggressively push "=" into CASE.
Close apache/calcite#573
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/b60b67eb
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/b60b67eb
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/b60b67eb
Branch: refs/heads/master
Commit: b60b67eb8f62463ccbc230358969ef2450cdbe05
Parents: c1749ad
Author: Volodymyr Vysotskyi <vv...@gmail.com>
Authored: Tue Nov 28 14:22:12 2017 +0200
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Dec 11 14:24:53 2017 -0800
----------------------------------------------------------------------
.../rel/rules/ReduceExpressionsRule.java | 12 ++++++++++
.../apache/calcite/test/RelOptRulesTest.java | 13 +++++++++++
.../org/apache/calcite/test/RelOptRulesTest.xml | 23 ++++++++++++++++++++
3 files changed, 48 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/b60b67eb/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 47a859c..264d123 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -20,6 +20,7 @@ import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptPredicateList;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Calc;
import org.apache.calcite.rel.core.EquiJoin;
@@ -61,6 +62,7 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelBuilderFactory;
+import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
@@ -702,6 +704,16 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
case AND:
case OR:
return call; // don't push CASE into CASE!
+ case EQUALS: {
+ // checks that the EQUALS operands may be splitted and
+ // doesn't push EQUALS into CASE
+ List<RexNode> equalsOperands = call.getOperands();
+ ImmutableBitSet left = RelOptUtil.InputFinder.bits(equalsOperands.get(0));
+ ImmutableBitSet right = RelOptUtil.InputFinder.bits(equalsOperands.get(1));
+ if (!left.isEmpty() && !right.isEmpty() && left.intersect(right).isEmpty()) {
+ return call;
+ }
+ }
}
int caseOrdinal = -1;
final List<RexNode> operands = call.getOperands();
http://git-wip-us.apache.org/repos/asf/calcite/blob/b60b67eb/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 7e1d1ec..b711ec8 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -1609,6 +1609,19 @@ public class RelOptRulesTest extends RelOptTestBase {
+ " else 0 end = 1");
}
+ @Test
+ public void testSkipReduceConstantsCaseEquals() throws Exception {
+ HepProgram program = new HepProgramBuilder()
+ .addRuleInstance(ReduceExpressionsRule.PROJECT_INSTANCE)
+ .addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
+ .addRuleInstance(FilterJoinRule.FilterIntoJoinRule.FILTER_ON_JOIN)
+ .build();
+
+ checkPlanning(program,
+ "select * from emp e1, emp e2\n"
+ + "where coalesce(e1.mgr, -1) = coalesce(e2.mgr, -1)");
+ }
+
@Test public void testReduceConstantsEliminatesFilter() throws Exception {
HepProgram program = new HepProgramBuilder()
.addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
http://git-wip-us.apache.org/repos/asf/calcite/blob/b60b67eb/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 8061eac..1b2287b 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -6128,6 +6128,29 @@ LogicalAggregate(group=[{}], EXPR$0=[COUNT()])
]]>
</Resource>
</TestCase>
+ <TestCase name="testSkipReduceConstantsCaseEquals">
+ <Resource name="sql">
+ <![CDATA[select * from emp e1, emp e2
+where coalesce(e1.mgr, -1) = coalesce(e2.mgr, -1)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], EMPNO0=[$9], ENAME0=[$10], JOB0=[$11], MGR0=[$12], HIREDATE0=[$13], SAL0=[$14], COMM0=[$15], DEPTNO0=[$16], SLACKER0=[$17])
+ LogicalFilter(condition=[=(CASE(IS NOT NULL($3), $3, -1), CASE(IS NOT NULL($12), $12, -1))])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], EMPNO0=[$9], ENAME0=[$10], JOB0=[$11], MGR0=[$12], HIREDATE0=[$13], SAL0=[$14], COMM0=[$15], DEPTNO0=[$16], SLACKER0=[$17])
+ LogicalJoin(condition=[=(CASE(IS NOT NULL($3), $3, -1), CASE(IS NOT NULL($12), $12, -1))], joinType=[inner])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testPushFilterPastAggThree">
<Resource name="sql">
<![CDATA[select deptno from emp
[2/4] calcite git commit: [CALCITE-2084] SqlValidatorImpl.findTable()
method incorrectly handles table schema with few schema levels (Volodymyr
Vysotskyi)
Posted by jh...@apache.org.
[CALCITE-2084] SqlValidatorImpl.findTable() method incorrectly handles table schema with few schema levels (Volodymyr Vysotskyi)
Close apache/calcite#580
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/26b4712d
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/26b4712d
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/26b4712d
Branch: refs/heads/master
Commit: 26b4712d4ac36c49aa8c80b2f0841be37c9de1df
Parents: 04cbdb2
Author: Volodymyr Vysotskyi <vv...@gmail.com>
Authored: Sun Dec 10 14:08:47 2017 +0200
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Dec 11 14:24:53 2017 -0800
----------------------------------------------------------------------
.../calcite/prepare/CalciteCatalogReader.java | 65 ++++------------
.../calcite/sql/validate/SqlValidatorImpl.java | 13 +---
.../calcite/sql/validate/SqlValidatorUtil.java | 79 ++++++++++++++++++++
.../apache/calcite/sql/test/SqlAdvisorTest.java | 4 +-
.../apache/calcite/test/MockCatalogReader.java | 33 +++++++-
.../apache/calcite/test/SqlValidatorTest.java | 3 +
6 files changed, 130 insertions(+), 67 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/26b4712d/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
index b7f32e1..af0d3a6 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
@@ -114,36 +114,7 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
public Prepare.PreparingTable getTable(final List<String> names) {
// First look in the default schema, if any.
// If not found, look in the root schema.
- for (List<String> schemaPath : schemaPaths) {
- Prepare.PreparingTable table =
- getTableFrom(names, schemaPath, nameMatcher);
- if (table != null) {
- return table;
- }
- }
- return null;
- }
-
- @Override public CalciteConnectionConfig getConfig() {
- return config;
- }
-
- private Prepare.PreparingTable getTableFrom(List<String> names,
- List<String> schemaNames,
- SqlNameMatcher nameMatcher) {
- CalciteSchema schema =
- getSchema(Iterables.concat(schemaNames, Util.skipLast(names)),
- nameMatcher);
- if (schema == null) {
- return null;
- }
- final String name = Util.last(names);
- CalciteSchema.TableEntry entry =
- schema.getTable(name, nameMatcher.isCaseSensitive());
- if (entry == null) {
- entry = schema.getTableBasedOnNullaryFunction(name,
- nameMatcher.isCaseSensitive());
- }
+ CalciteSchema.TableEntry entry = SqlValidatorUtil.getTableEntry(this, names);
if (entry != null) {
final Table table = entry.getTable();
if (table instanceof Wrapper) {
@@ -153,12 +124,16 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
return relOptTable;
}
}
- return RelOptTableImpl.create(this, table.getRowType(typeFactory), entry,
- null);
+ return RelOptTableImpl.create(this,
+ table.getRowType(typeFactory), entry, null);
}
return null;
}
+ @Override public CalciteConnectionConfig getConfig() {
+ return config;
+ }
+
private Collection<Function> getFunctionsFrom(List<String> names) {
final List<Function> functions2 = Lists.newArrayList();
final List<List<String>> schemaNameList = new ArrayList<>();
@@ -172,7 +147,8 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
}
} else {
for (List<String> schemaPath : schemaPaths) {
- CalciteSchema schema = getSchema(schemaPath, nameMatcher);
+ CalciteSchema schema =
+ SqlValidatorUtil.getSchema(rootSchema, schemaPath, nameMatcher);
if (schema != null) {
schemaNameList.addAll(schema.getPath());
}
@@ -180,8 +156,8 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
}
for (List<String> schemaNames : schemaNameList) {
CalciteSchema schema =
- getSchema(Iterables.concat(schemaNames, Util.skipLast(names)),
- nameMatcher);
+ SqlValidatorUtil.getSchema(rootSchema,
+ Iterables.concat(schemaNames, Util.skipLast(names)), nameMatcher);
if (schema != null) {
final String name = Util.last(names);
functions2.addAll(schema.getFunctions(name, true));
@@ -190,28 +166,13 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
return functions2;
}
- private CalciteSchema getSchema(Iterable<String> schemaNames,
- SqlNameMatcher nameMatcher) {
- CalciteSchema schema = rootSchema;
- for (String schemaName : schemaNames) {
- if (schema == rootSchema
- && nameMatcher.matches(schemaName, schema.getName())) {
- continue;
- }
- schema = schema.getSubSchema(schemaName, nameMatcher.isCaseSensitive());
- if (schema == null) {
- return null;
- }
- }
- return schema;
- }
-
public RelDataType getNamedType(SqlIdentifier typeName) {
return null;
}
public List<SqlMoniker> getAllSchemaObjectNames(List<String> names) {
- final CalciteSchema schema = getSchema(names, nameMatcher);
+ final CalciteSchema schema =
+ SqlValidatorUtil.getSchema(rootSchema, names, nameMatcher);
if (schema == null) {
return ImmutableList.of();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/26b4712d/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index 7c7c065..652bbe9 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -3440,17 +3440,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
catalogReader.nameMatcher().isCaseSensitive());
}
- String schemaName = names.get(0);
- String tableName = names.get(1);
-
- CalciteSchema schema = catalogReader.getRootSchema().getSubSchemaMap().get(schemaName);
-
- if (schema == null) {
- return null;
- }
-
- CalciteSchema.TableEntry entry = schema.getTable(tableName,
- catalogReader.nameMatcher().isCaseSensitive());
+ CalciteSchema.TableEntry entry =
+ SqlValidatorUtil.getTableEntry(catalogReader, names);
return entry == null ? null : entry.getTable();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/26b4712d/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
index 2200e01..8583cb1 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.sql.validate;
+import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.linq4j.Linq4j;
import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.plan.RelOptSchemaWithSampling;
@@ -51,6 +52,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -931,6 +933,83 @@ public class SqlValidatorUtil {
}
/**
+ * Finds a {@link org.apache.calcite.jdbc.CalciteSchema.TableEntry} in a
+ * given catalog reader whose table has the given name, possibly qualified.
+ *
+ * <p>Uses the case-sensitivity policy of the specified catalog reader.
+ *
+ * <p>If not found, returns null.
+ *
+ * @param catalogReader accessor to the table metadata
+ * @param names Name of table, may be qualified or fully-qualified
+ *
+ * @return TableEntry with a table with the given name, or null
+ */
+ public static CalciteSchema.TableEntry getTableEntry(
+ SqlValidatorCatalogReader catalogReader, List<String> names) {
+ // First look in the default schema, if any.
+ // If not found, look in the root schema.
+ for (List<String> schemaPath : catalogReader.getSchemaPaths()) {
+ CalciteSchema schema =
+ getSchema(catalogReader.getRootSchema(),
+ Iterables.concat(schemaPath, Util.skipLast(names)),
+ catalogReader.nameMatcher());
+ if (schema == null) {
+ continue;
+ }
+ CalciteSchema.TableEntry entry =
+ getTableEntryFrom(schema, Util.last(names),
+ catalogReader.nameMatcher().isCaseSensitive());
+ if (entry != null) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds and returns {@link CalciteSchema} nested to the given rootSchema
+ * with specified schemaPath.
+ *
+ * <p>Uses the case-sensitivity policy of specified nameMatcher.
+ *
+ * <p>If not found, returns null.
+ *
+ * @param rootSchema root schema
+ * @param schemaPath full schema path of required schema
+ * @param nameMatcher name matcher
+ *
+ * @return CalciteSchema that corresponds specified schemaPath
+ */
+ public static CalciteSchema getSchema(CalciteSchema rootSchema,
+ Iterable<String> schemaPath, SqlNameMatcher nameMatcher) {
+ CalciteSchema schema = rootSchema;
+ for (String schemaName : schemaPath) {
+ if (schema == rootSchema
+ && nameMatcher.matches(schemaName, schema.getName())) {
+ continue;
+ }
+ schema = schema.getSubSchema(schemaName,
+ nameMatcher.isCaseSensitive());
+ if (schema == null) {
+ return null;
+ }
+ }
+ return schema;
+ }
+
+ private static CalciteSchema.TableEntry getTableEntryFrom(
+ CalciteSchema schema, String name, boolean caseSensitive) {
+ CalciteSchema.TableEntry entry =
+ schema.getTable(name, caseSensitive);
+ if (entry == null) {
+ entry = schema.getTableBasedOnNullaryFunction(name,
+ caseSensitive);
+ }
+ return entry;
+ }
+
+ /**
* Returns whether there are any input columns that are sorted.
*
* <p>If so, it can be the default ORDER BY clause for a WINDOW specification.
http://git-wip-us.apache.org/repos/asf/calcite/blob/26b4712d/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
index e0f0d94..e877b2a 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
@@ -68,6 +68,7 @@ public class SqlAdvisorTest extends SqlValidatorTestCase {
protected static final List<String> SALES_TABLES =
Arrays.asList(
"SCHEMA(CATALOG.SALES)",
+ "SCHEMA(CATALOG.SALES.NEST)",
"TABLE(CATALOG.SALES.EMP)",
"TABLE(CATALOG.SALES.EMPDEFAULTS)",
"TABLE(CATALOG.SALES.EMPNULLABLES)",
@@ -92,7 +93,8 @@ public class SqlAdvisorTest extends SqlValidatorTestCase {
"SCHEMA(CATALOG.DYNAMIC)",
"SCHEMA(CATALOG.SALES)",
"SCHEMA(CATALOG.STRUCT)",
- "SCHEMA(CATALOG.CUSTOMER)");
+ "SCHEMA(CATALOG.CUSTOMER)",
+ "SCHEMA(CATALOG.SALES.NEST)");
private static final List<String> AB_TABLES =
Arrays.asList(
http://git-wip-us.apache.org/repos/asf/calcite/blob/26b4712d/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
index 5f96848..cd42747 100644
--- a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
+++ b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
@@ -87,6 +87,7 @@ import org.apache.calcite.sql.validate.SqlMonotonicity;
import org.apache.calcite.sql.validate.SqlNameMatcher;
import org.apache.calcite.sql.validate.SqlNameMatchers;
import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
import org.apache.calcite.sql2rel.InitializerContext;
import org.apache.calcite.sql2rel.InitializerExpressionFactory;
import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
@@ -527,6 +528,20 @@ public class MockCatalogReader extends CalciteCatalogReader {
deptSlackingTable.addColumn("SLACKINGMIN", f.intType);
registerTable(deptSlackingTable);
+ // Register nested schema NEST that contains table with a rolled up column.
+ MockSchema nestedSchema = new MockSchema("NEST");
+ registerNestedSchema(schema, nestedSchema);
+
+ // Register "EMP_R" table which contains a rolled up column in NEST schema.
+ ImmutableList<String> tablePath =
+ ImmutableList.of(schema.getCatalogName(), schema.name, nestedSchema.name, "EMP_R");
+ final MockTable nestedEmpRolledTable = MockTable.create(this, tablePath, false, 14);
+ nestedEmpRolledTable.addColumn("EMPNO", f.intType, true);
+ nestedEmpRolledTable.addColumn("DEPTNO", f.intType);
+ nestedEmpRolledTable.addColumn("SLACKER", f.booleanType);
+ nestedEmpRolledTable.addColumn("SLACKINGMIN", f.intType);
+ nestedEmpRolledTable.registerRolledUpColumn("SLACKINGMIN");
+ registerTable(nestedEmpRolledTable);
}
/** Adds some extra tables to the mock catalog. These increase the time and
@@ -622,9 +637,10 @@ public class MockCatalogReader extends CalciteCatalogReader {
private void registerTable(final List<String> names, final Table table) {
assert names.get(0).equals(DEFAULT_CATALOG);
- final String schemaName = names.get(1);
- final String tableName = names.get(2);
- final CalciteSchema schema = rootSchema.getSubSchema(schemaName, true);
+ final List<String> schemaPath = Util.skipLast(names);
+ final String tableName = Util.last(names);
+ final CalciteSchema schema = SqlValidatorUtil.getSchema(rootSchema,
+ schemaPath, SqlNameMatchers.withCaseSensitive(true));
schema.add(tableName, table);
}
@@ -632,6 +648,11 @@ public class MockCatalogReader extends CalciteCatalogReader {
rootSchema.add(schema.name, new AbstractSchema());
}
+ private void registerNestedSchema(MockSchema parentSchema, MockSchema schema) {
+ rootSchema.getSubSchema(parentSchema.getName(), true)
+ .add(schema.name, new AbstractSchema());
+ }
+
public RelDataType getNamedType(SqlIdentifier typeName) {
if (typeName.equalsDeep(addressType.getSqlIdentifier(), Litmus.IGNORE)) {
return addressType;
@@ -829,6 +850,12 @@ public class MockCatalogReader extends CalciteCatalogReader {
}
public static MockTable create(MockCatalogReader catalogReader,
+ List<String> names, boolean stream, double rowCount) {
+ return new MockTable(catalogReader, names, stream, rowCount, null,
+ NullInitializerExpressionFactory.INSTANCE);
+ }
+
+ public static MockTable create(MockCatalogReader catalogReader,
MockSchema schema, String name, boolean stream, double rowCount,
ColumnResolver resolver) {
return create(catalogReader, schema, name, stream, rowCount, resolver,
http://git-wip-us.apache.org/repos/asf/calcite/blob/26b4712d/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index f62b0aa..c2d89a5 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -10405,6 +10405,9 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
sql("select (((^slackingmin^))) from emp_r")
.fails(error);
+
+ sql("select ^slackingmin^ from nest.emp_r")
+ .fails(error);
}
@Test public void testSelectAggregateOnRolledUpColumn() {
[4/4] calcite git commit: [CALCITE-2072] Enable spatial functions by
adding 'fun=spatial' to JDBC connect string
Posted by jh...@apache.org.
[CALCITE-2072] Enable spatial functions by adding 'fun=spatial' to JDBC connect string
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/c1749ade
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/c1749ade
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/c1749ade
Branch: refs/heads/master
Commit: c1749ade6638cd2e724f33a09f12f45d8d2a5503
Parents: 26b4712
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Dec 8 16:10:55 2017 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Dec 11 14:24:53 2017 -0800
----------------------------------------------------------------------
.../config/CalciteConnectionConfigImpl.java | 25 +++++---
.../config/CalciteConnectionProperty.java | 3 +-
.../calcite/prepare/CalciteCatalogReader.java | 63 +++++++++++++++++---
.../sql/validate/SqlUserDefinedAggFunction.java | 5 ++
.../java/org/apache/calcite/test/JdbcTest.java | 18 ++++++
site/_docs/adapter.md | 2 +-
site/_docs/howto.md | 15 +++++
site/_docs/spatial.md | 18 ++++++
8 files changed, 131 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1749ade/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
index c2a3239..794d1c8 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java
@@ -20,6 +20,8 @@ import org.apache.calcite.avatica.ConnectionConfigImpl;
import org.apache.calcite.avatica.util.Casing;
import org.apache.calcite.avatica.util.Quoting;
import org.apache.calcite.model.JsonSchema;
+import org.apache.calcite.prepare.CalciteCatalogReader;
+import org.apache.calcite.runtime.GeoFunctions;
import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.fun.OracleSqlOperatorTable;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -27,8 +29,8 @@ import org.apache.calcite.sql.util.ChainedSqlOperatorTable;
import org.apache.calcite.sql.validate.SqlConformance;
import org.apache.calcite.sql.validate.SqlConformanceEnum;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collection;
+import java.util.LinkedHashSet;
import java.util.Properties;
/** Implementation of {@link CalciteConnectionConfig}. */
@@ -86,22 +88,29 @@ public class CalciteConnectionConfigImpl extends ConnectionConfigImpl
if (fun == null || fun.equals("") || fun.equals("standard")) {
return defaultOperatorTable;
}
- final List<SqlOperatorTable> tables = new ArrayList<>();
+ final Collection<SqlOperatorTable> tables = new LinkedHashSet<>();
for (String s : fun.split(",")) {
- tables.add(operatorTable(s));
+ operatorTable(s, tables);
}
+ tables.add(SqlStdOperatorTable.instance());
return operatorTableClass.cast(
ChainedSqlOperatorTable.of(
tables.toArray(new SqlOperatorTable[tables.size()])));
}
- private static SqlOperatorTable operatorTable(String s) {
+ private static void operatorTable(String s,
+ Collection<SqlOperatorTable> tables) {
switch (s) {
case "standard":
- return SqlStdOperatorTable.instance();
+ tables.add(SqlStdOperatorTable.instance());
+ return;
case "oracle":
- return ChainedSqlOperatorTable.of(OracleSqlOperatorTable.instance(),
- SqlStdOperatorTable.instance());
+ tables.add(OracleSqlOperatorTable.instance());
+ return;
+ case "spatial":
+ tables.add(
+ CalciteCatalogReader.operatorTable(GeoFunctions.class.getName()));
+ return;
default:
throw new IllegalArgumentException("Unknown operator table: " + s);
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1749ade/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
index b576aac..67909da 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
@@ -74,7 +74,8 @@ public enum CalciteConnectionProperty implements ConnectionProperty {
LEX("lex", Type.ENUM, Lex.ORACLE, false),
/** Collection of built-in functions and operators. Valid values include
- * "standard" and "oracle". */
+ * "standard", "oracle" and "spatial", and also comma-separated lists, for
+ * example "oracle,spatial". */
FUN("fun", Type.STRING, "standard", true),
/** How identifiers are quoted.
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1749ade/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
index af0d3a6..4dc8be7 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
@@ -19,11 +19,13 @@ package org.apache.calcite.prepare;
import org.apache.calcite.config.CalciteConnectionConfig;
import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.model.ModelHandler;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelDataTypeSystem;
import org.apache.calcite.runtime.PredicateImpl;
import org.apache.calcite.schema.AggregateFunction;
import org.apache.calcite.schema.Function;
@@ -38,14 +40,18 @@ import org.apache.calcite.sql.SqlFunctionCategory;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlOperatorBinding;
+import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.SqlSyntax;
+import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.FamilyOperandTypeChecker;
import org.apache.calcite.sql.type.InferTypes;
import org.apache.calcite.sql.type.OperandTypes;
import org.apache.calcite.sql.type.ReturnTypes;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
+import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
import org.apache.calcite.sql.type.SqlTypeFamily;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.util.ListSqlOperatorTable;
import org.apache.calcite.sql.validate.SqlMoniker;
import org.apache.calcite.sql.validate.SqlMonikerImpl;
import org.apache.calcite.sql.validate.SqlMonikerType;
@@ -275,7 +281,43 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
}));
}
+ /** Creates an operator table that contains functions in the given class.
+ *
+ * @see ModelHandler#addFunctions */
+ public static SqlOperatorTable operatorTable(String className) {
+ // Dummy schema to collect the functions
+ final CalciteSchema schema =
+ CalciteSchema.createRootSchema(false, false);
+ ModelHandler.addFunctions(schema.plus(), null, ImmutableList.<String>of(),
+ className, "*", true);
+
+ // The following is technical debt; see [CALCITE-2082] Remove
+ // RelDataTypeFactory argument from SqlUserDefinedAggFunction constructor
+ final SqlTypeFactoryImpl typeFactory =
+ new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+
+ final ListSqlOperatorTable table = new ListSqlOperatorTable();
+ for (String name : schema.getFunctionNames()) {
+ for (Function function : schema.getFunctions(name, true)) {
+ final SqlIdentifier id = new SqlIdentifier(name, SqlParserPos.ZERO);
+ table.add(
+ toOp(typeFactory, id, function));
+ }
+ }
+ return table;
+ }
+
private SqlOperator toOp(SqlIdentifier name, final Function function) {
+ return toOp(typeFactory, name, function);
+ }
+
+ /** Converts a function to a {@link org.apache.calcite.sql.SqlOperator}.
+ *
+ * <p>The {@code typeFactory} argument is technical debt; see [CALCITE-2082]
+ * Remove RelDataTypeFactory argument from SqlUserDefinedAggFunction
+ * constructor. */
+ private static SqlOperator toOp(RelDataTypeFactory typeFactory,
+ SqlIdentifier name, final Function function) {
List<RelDataType> argTypes = new ArrayList<>();
List<SqlTypeFamily> typeFamilies = new ArrayList<>();
for (FunctionParameter o : function.getParameters()) {
@@ -292,7 +334,7 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
};
final FamilyOperandTypeChecker typeChecker =
OperandTypes.family(typeFamilies, optional);
- final List<RelDataType> paramTypes = toSql(argTypes);
+ final List<RelDataType> paramTypes = toSql(typeFactory, argTypes);
if (function instanceof ScalarFunction) {
return new SqlUserDefinedFunction(name, infer((ScalarFunction) function),
InferTypes.explicit(argTypes), typeChecker, paramTypes, function);
@@ -313,9 +355,10 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
}
}
- private SqlReturnTypeInference infer(final ScalarFunction function) {
+ private static SqlReturnTypeInference infer(final ScalarFunction function) {
return new SqlReturnTypeInference() {
public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
+ final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataType type;
if (function instanceof ScalarFunctionImpl) {
type = ((ScalarFunctionImpl) function).getReturnType(typeFactory,
@@ -323,30 +366,34 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
} else {
type = function.getReturnType(typeFactory);
}
- return toSql(type);
+ return toSql(typeFactory, type);
}
};
}
- private SqlReturnTypeInference infer(final AggregateFunction function) {
+ private static SqlReturnTypeInference infer(
+ final AggregateFunction function) {
return new SqlReturnTypeInference() {
public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
+ final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
final RelDataType type = function.getReturnType(typeFactory);
- return toSql(type);
+ return toSql(typeFactory, type);
}
};
}
- private List<RelDataType> toSql(List<RelDataType> types) {
+ private static List<RelDataType> toSql(
+ final RelDataTypeFactory typeFactory, List<RelDataType> types) {
return Lists.transform(types,
new com.google.common.base.Function<RelDataType, RelDataType>() {
public RelDataType apply(RelDataType type) {
- return toSql(type);
+ return toSql(typeFactory, type);
}
});
}
- private RelDataType toSql(RelDataType type) {
+ private static RelDataType toSql(RelDataTypeFactory typeFactory,
+ RelDataType type) {
if (type instanceof RelDataTypeFactoryImpl.JavaType
&& ((RelDataTypeFactoryImpl.JavaType) type).getJavaClass()
== Object.class) {
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1749ade/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
index a8be50b..68c954f 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedAggFunction.java
@@ -17,6 +17,7 @@
package org.apache.calcite.sql.validate;
import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.linq4j.function.Experimental;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
@@ -46,6 +47,10 @@ import java.util.List;
*/
public class SqlUserDefinedAggFunction extends SqlAggFunction {
public final AggregateFunction function;
+
+ /** This field is is technical debt; see [CALCITE-2082] Remove
+ * RelDataTypeFactory argument from SqlUserDefinedAggFunction constructor. */
+ @Experimental
public final RelDataTypeFactory typeFactory;
/** Creates a SqlUserDefinedAggFunction. */
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1749ade/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index cdebd47..2fd5d0a 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -6157,6 +6157,24 @@ public class JdbcTest {
.throws_("No match found for function signature NVL(<NUMERIC>, <NUMERIC>)");
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-2072">[CALCITE-2072]
+ * Enable spatial operator table by adding 'fun=spatial'to JDBC URL</a>. */
+ @Test public void testFunSpatial() {
+ final String sql = "select distinct\n"
+ + " ST_PointFromText('POINT(-71.0642.28)') as c\n"
+ + "from \"hr\".\"emps\"";
+ CalciteAssert.that(CalciteAssert.Config.REGULAR)
+ .with("fun", "spatial")
+ .query(sql)
+ .returnsUnordered("C={\"x\":-71.0642,\"y\":0.28}");
+
+ // NVL is present in the Oracle operator table, but not spatial or core
+ CalciteAssert.that(CalciteAssert.Config.REGULAR)
+ .query("select nvl(\"commission\", -99) as c from \"hr\".\"emps\"")
+ .throws_("No match found for function signature NVL(<NUMERIC>, <NUMERIC>)");
+ }
+
/** Tests that {@link Hook#PARSE_TREE} works. */
@Test public void testHook() {
final int[] callCount = {0};
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1749ade/site/_docs/adapter.md
----------------------------------------------------------------------
diff --git a/site/_docs/adapter.md b/site/_docs/adapter.md
index 5562c4c..35001ed 100644
--- a/site/_docs/adapter.md
+++ b/site/_docs/adapter.md
@@ -88,7 +88,7 @@ as implemented by Avatica's
| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#DEFAULT_NULL_COLLATION">defaultNullCollation</a> | How NULL values should be sorted if neither NULLS FIRST nor NULLS LAST are specified in a query. The default, HIGH, sorts NULL values the same as Oracle.
| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#DRUID_FETCH">druidFetch</a> | How many rows the Druid adapter should fetch at a time when executing SELECT queries.
| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#FORCE_DECORRELATE">forceDecorrelate</a> | Whether the planner should try de-correlating as much as possible. Default true.
-| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#FUN">fun</a> | Collection of built-in functions and operators. Valid values: "standard" (the default), "oracle".
+| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#FUN">fun</a> | Collection of built-in functions and operators. Valid values are "standard" (the default), "oracle", "spatial", and may be combined using commas, for example "oracle,spatial".
| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#LEX">lex</a> | Lexical policy. Values are ORACLE (default), MYSQL, MYSQL_ANSI, SQL_SERVER, JAVA.
| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#MATERIALIZATIONS_ENABLED">materializationsEnabled</a> | Whether Calcite should use materializations. Default false.
| <a href="{{ site.apiRoot }}/org/apache/calcite/config/CalciteConnectionProperty.html#MODEL">model</a> | URI of the JSON model file.
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1749ade/site/_docs/howto.md
----------------------------------------------------------------------
diff --git a/site/_docs/howto.md b/site/_docs/howto.md
index 742a83f..437f64d 100644
--- a/site/_docs/howto.md
+++ b/site/_docs/howto.md
@@ -464,6 +464,21 @@ Before you start:
a fix version assigned (most likely the version we are
just about to release)
+Smoke-test `sqlline` with Spatial and Oracle function tables:
+
+{% highlight sql %}
+$ ./sqlline
+> !connect jdbc:calcite:fun=spatial,oracle "sa" ""
+SELECT NVL(ST_Is3D(ST_PointFromText('POINT(-71.064544 42.28787)')), TRUE);
++--------+
+| EXPR$0 |
++--------+
+| false |
++--------+
+1 row selected (0.039 seconds)
+> !quit
+{% endhighlight %}
+
Create a release branch named after the release, e.g. `branch-1.1`, and push it to Apache.
{% highlight bash %}
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1749ade/site/_docs/spatial.md
----------------------------------------------------------------------
diff --git a/site/_docs/spatial.md b/site/_docs/spatial.md
index 3b98464..1521ce1 100644
--- a/site/_docs/spatial.md
+++ b/site/_docs/spatial.md
@@ -51,6 +51,24 @@ Calcite's support for spatial data includes:
and will at some point also include query rewrites to use spatial indexes.
+## Enabling spatial support
+
+Though the `GEOMETRY` data type is built-in, the functions are not enabled by
+default. You need to add `fun=spatial` to the JDBC connect string to enable
+the functions. For example, `sqlline`:
+
+{% highlight sql %}
+$ ./sqlline
+> !connect jdbc:calcite:fun=spatial "sa" ""
+SELECT ST_PointFromText('POINT(-71.064544 42.28787)');
++-------------------------------+
+| EXPR$0 |
++-------------------------------+
+| {"x":-71.064544,"y":42.28787} |
++-------------------------------+
+1 row selected (0.323 seconds)
+{% endhighlight %}
+
## Acknowledgements
Calcite's OpenGIS implementation uses the