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 2018/06/29 18:42:00 UTC
[4/8] calcite git commit: [CALCITE-531] LATERAL combined with window
function or table function
[CALCITE-531] LATERAL combined with window function or table function
Rewrite the mechanism for resolving correlating variables in LATERAL.
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/189b50d5
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/189b50d5
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/189b50d5
Branch: refs/heads/master
Commit: 189b50d5ec8ac3c5f61be5540bb186f811fbf633
Parents: aae56a5
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Feb 7 13:46:25 2018 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jun 29 01:23:21 2018 -0700
----------------------------------------------------------------------
.../apache/calcite/sql/validate/EmptyScope.java | 4 +-
.../apache/calcite/sql/validate/JoinScope.java | 8 ++
.../sql/validate/SqlUserDefinedTableMacro.java | 9 +-
.../calcite/sql/validate/SqlValidatorImpl.java | 103 ++++++++++++-------
.../calcite/sql/validate/SqlValidatorScope.java | 15 +++
.../apache/calcite/sql/validate/TableScope.java | 30 +++---
.../calcite/sql2rel/SqlToRelConverter.java | 5 +-
.../java/org/apache/calcite/test/JdbcTest.java | 29 ++++++
.../apache/calcite/test/SqlValidatorTest.java | 19 +++-
.../calcite/test/SqlValidatorTestCase.java | 3 +-
.../apache/calcite/test/TableFunctionTest.java | 23 ++++-
11 files changed, 180 insertions(+), 68 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java b/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java
index 77922c7..139fe50 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java
@@ -160,13 +160,13 @@ class EmptyScope implements SqlValidatorScope {
table2 = RelOptTableImpl.create(relOptSchema, rowType, entry, null);
}
namespace = new TableNamespace(validator, table2);
- resolved.found(namespace, false, this, path, remainingNames);
+ resolved.found(namespace, false, null, path, remainingNames);
return;
}
// neither sub-schema nor table
if (namespace != null
&& !remainingNames.equals(names)) {
- resolved.found(namespace, false, this, path, remainingNames);
+ resolved.found(namespace, false, null, path, remainingNames);
}
return;
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java b/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java
index bf40e7d..f1eca33 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java
@@ -92,6 +92,14 @@ public class JoinScope extends ListScope {
public SqlValidatorScope getUsingScope() {
return usingScope;
}
+
+ @Override public boolean isWithin(SqlValidatorScope scope2) {
+ if (this == scope2) {
+ return true;
+ }
+ // go from the JOIN to the enclosing SELECT
+ return usingScope.isWithin(scope2);
+ }
}
// End JoinScope.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedTableMacro.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedTableMacro.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedTableMacro.java
index 9ef6cc2..4f191ac 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedTableMacro.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedTableMacro.java
@@ -117,7 +117,14 @@ public class SqlUserDefinedTableMacro extends SqlFunction {
+ pair.left.getOrdinal() + " (" + pair.left.getName()
+ ") is not literal: " + pair.right);
}
- arguments.add(null);
+ final RelDataType type = pair.left.getType(typeFactory);
+ final Object value;
+ if (type.isNullable()) {
+ value = null;
+ } else {
+ value = 0L;
+ }
+ arguments.add(value);
}
}
return arguments;
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/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 27b7f8a..ad1d3af 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
@@ -1888,8 +1888,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
// parse input query
SqlNode expr = call.getTableRef();
- SqlNode newExpr = registerFrom(usingScope, matchRecognizeScope, expr,
- expr, null, null, forceNullable);
+ SqlNode newExpr = registerFrom(usingScope, matchRecognizeScope, true, expr,
+ expr, null, null, forceNullable, false);
if (expr != newExpr) {
call.setOperand(0, newExpr);
}
@@ -1940,6 +1940,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
* @param parentScope Parent scope which this scope turns to in order to
* resolve objects
* @param usingScope Scope whose child list this scope should add itself to
+ * @param register Whether to register this scope as a child of
+ * {@code usingScope}
* @param node Node which namespace is based on
* @param enclosingNode Outermost node for namespace, including decorations
* such as alias and sample clause
@@ -1947,16 +1949,21 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
* @param extendList Definitions of extended columns
* @param forceNullable Whether to force the type of namespace to be
* nullable because it is in an outer join
+ * @param lateral Whether LATERAL is specified, so that items to the
+ * left of this in the JOIN tree are visible in the
+ * scope
* @return registered node, usually the same as {@code node}
*/
private SqlNode registerFrom(
SqlValidatorScope parentScope,
SqlValidatorScope usingScope,
+ boolean register,
final SqlNode node,
SqlNode enclosingNode,
String alias,
SqlNodeList extendList,
- boolean forceNullable) {
+ boolean forceNullable,
+ final boolean lateral) {
final SqlKind kind = node.getKind();
SqlNode expr;
@@ -2001,6 +2008,21 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
}
}
+ if (lateral) {
+ SqlValidatorScope s = usingScope;
+ while (s instanceof JoinScope) {
+ s = ((JoinScope) s).getUsingScope();
+ }
+ final SqlNode node2 = s != null ? s.getNode() : node;
+ final TableScope tableScope = new TableScope(parentScope, node2);
+ if (usingScope instanceof ListScope) {
+ for (ScopeChild child : ((ListScope) usingScope).children) {
+ tableScope.addChild(child.namespace, child.name, child.nullable);
+ }
+ }
+ parentScope = tableScope;
+ }
+
SqlCall call;
SqlNode operand;
SqlNode newOperand;
@@ -2011,27 +2033,26 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
if (alias == null) {
alias = call.operand(1).toString();
}
- SqlValidatorScope usingScope2 = usingScope;
- if (call.operandCount() > 2) {
- usingScope2 = null;
- }
+ final boolean needAlias = call.operandCount() > 2;
expr = call.operand(0);
newExpr =
registerFrom(
parentScope,
- usingScope2,
+ usingScope,
+ !needAlias,
expr,
enclosingNode,
alias,
extendList,
- forceNullable);
+ forceNullable,
+ lateral);
if (newExpr != expr) {
call.setOperand(0, newExpr);
}
// If alias has a column list, introduce a namespace to translate
- // column names.
- if (call.operandCount() > 2) {
+ // column names. We skipped registering it just now.
+ if (needAlias) {
registerNamespace(
usingScope,
alias,
@@ -2050,11 +2071,13 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
registerFrom(
parentScope,
usingScope,
+ true,
expr,
enclosingNode,
alias,
extendList,
- forceNullable);
+ forceNullable,
+ lateral);
if (newExpr != expr) {
call.setOperand(0, newExpr);
}
@@ -2086,29 +2109,27 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
registerFrom(
parentScope,
joinScope,
+ true,
left,
left,
null,
null,
- forceLeftNullable);
+ forceLeftNullable,
+ lateral);
if (newLeft != left) {
join.setLeft(newLeft);
}
- final SqlValidatorScope rightParentScope;
- if (rightIsLateral) {
- rightParentScope = joinScope;
- } else {
- rightParentScope = parentScope;
- }
final SqlNode newRight =
registerFrom(
- rightParentScope,
+ parentScope,
joinScope,
+ true,
right,
right,
null,
null,
- forceRightNullable);
+ forceRightNullable,
+ lateral);
if (newRight != right) {
join.setRight(newRight);
}
@@ -2123,7 +2144,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
new IdentifierNamespace(
this, id, extendList, enclosingNode,
parentScope);
- registerNamespace(usingScope, alias, newNs, forceNullable);
+ registerNamespace(register ? usingScope : null, alias, newNs,
+ forceNullable);
if (tableScope == null) {
tableScope = new TableScope(parentScope, node);
}
@@ -2134,50 +2156,55 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
return newNode;
case LATERAL:
- if (tableScope != null) {
- tableScope.meetLateral();
- }
return registerFrom(
parentScope,
usingScope,
+ true,
((SqlCall) node).operand(0),
enclosingNode,
alias,
extendList,
- forceNullable);
+ forceNullable,
+ true);
case COLLECTION_TABLE:
call = (SqlCall) node;
operand = call.operand(0);
newOperand =
registerFrom(
- tableScope == null ? parentScope : tableScope,
+ parentScope,
usingScope,
+ register,
operand,
enclosingNode,
alias,
extendList,
- forceNullable);
+ forceNullable, lateral);
if (newOperand != operand) {
call.setOperand(0, newOperand);
}
scopes.put(node, parentScope);
return newNode;
+ case UNNEST:
+ if (!lateral) {
+ return registerFrom(parentScope, usingScope, register, node,
+ enclosingNode, alias, extendList, forceNullable, true);
+ }
+ // fall through
case SELECT:
case UNION:
case INTERSECT:
case EXCEPT:
case VALUES:
case WITH:
- case UNNEST:
case OTHER_FUNCTION:
if (alias == null) {
alias = deriveAlias(node, nextGeneratedId++);
}
registerQuery(
parentScope,
- usingScope,
+ register ? usingScope : null,
node,
enclosingNode,
alias,
@@ -2196,18 +2223,20 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
registerFrom(
parentScope,
overScope,
+ true,
operand,
enclosingNode,
alias,
extendList,
- forceNullable);
+ forceNullable,
+ lateral);
if (newOperand != operand) {
call.setOperand(0, newOperand);
}
for (ScopeChild child : overScope.children) {
- registerNamespace(usingScope, child.name, child.namespace,
- forceNullable);
+ registerNamespace(register ? usingScope : null, child.name,
+ child.namespace, forceNullable);
}
return newNode;
@@ -2216,11 +2245,13 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
final SqlCall extend = (SqlCall) node;
return registerFrom(parentScope,
usingScope,
+ true,
extend.getOperandList().get(0),
extend,
alias,
(SqlNodeList) extend.getOperandList().get(1),
- forceNullable);
+ forceNullable,
+ lateral);
default:
throw Util.unexpected(kind);
@@ -2355,10 +2386,12 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
registerFrom(
parentScope,
selectScope,
+ true,
from,
from,
null,
null,
+ false,
false);
if (newFrom != from) {
select.setFrom(newFrom);
@@ -3720,7 +3753,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
// We've found a table. But is it a sequence?
final SqlValidatorNamespace ns = resolved.only().namespace;
if (ns instanceof TableNamespace) {
- final Table table = ((RelOptTable) ns.getTable()).unwrap(Table.class);
+ final Table table = ns.getTable().unwrap(Table.class);
switch (table.getJdbcTableType()) {
case SEQUENCE:
case TEMPORARY_SEQUENCE:
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java
index c8eb6b0..b32ed36 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java
@@ -22,6 +22,7 @@ import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
+import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.SqlWindow;
import org.apache.calcite.util.Pair;
@@ -202,6 +203,12 @@ public interface SqlValidatorScope {
* warrants it. */
RelDataType nullifyType(SqlNode node, RelDataType type);
+ /** Returns whether this scope is enclosed within {@code scope2} in such
+ * a way that it can see the contents of {@code scope2}. */
+ default boolean isWithin(SqlValidatorScope scope2) {
+ return this == scope2;
+ }
+
/** Callback from {@link SqlValidatorScope#resolve}. */
interface Resolved {
void found(SqlValidatorNamespace namespace, boolean nullable,
@@ -244,6 +251,10 @@ public interface SqlValidatorScope {
protected void build(ImmutableList.Builder<Step> paths) {
}
+
+ @Override public String toString() {
+ return stepNames().toString();
+ }
}
/** A path that has no steps. */
@@ -284,6 +295,9 @@ public interface SqlValidatorScope {
public void found(SqlValidatorNamespace namespace, boolean nullable,
SqlValidatorScope scope, Path path, List<String> remainingNames) {
+ if (scope instanceof TableScope) {
+ scope = scope.getValidator().getSelectScope((SqlSelect) scope.getNode());
+ }
resolves.add(
new Resolve(namespace, nullable, scope, path, remainingNames));
}
@@ -317,6 +331,7 @@ public interface SqlValidatorScope {
this.namespace = Preconditions.checkNotNull(namespace);
this.nullable = nullable;
this.scope = scope;
+ assert !(scope instanceof TableScope);
this.path = Preconditions.checkNotNull(path);
this.remainingNames = remainingNames == null ? ImmutableList.<String>of()
: ImmutableList.copyOf(remainingNames);
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/core/src/main/java/org/apache/calcite/sql/validate/TableScope.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/TableScope.java b/core/src/main/java/org/apache/calcite/sql/validate/TableScope.java
index aa81d41..89171c2 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/TableScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/TableScope.java
@@ -17,6 +17,9 @@
package org.apache.calcite.sql.validate;
import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlSelect;
+
+import com.google.common.base.Preconditions;
/**
* The name-resolution scope of a LATERAL TABLE clause.
@@ -29,39 +32,30 @@ class TableScope extends ListScope {
private final SqlNode node;
- // The expression inside the LATERAL can only see tables before it in the FROM clause.
- // We use this flag to indicate whether current table is before LATERAL.
- private boolean beforeLateral;
-
//~ Constructors -----------------------------------------------------------
/**
* Creates a scope corresponding to a LATERAL TABLE clause.
*
- * @param parent Parent scope, or null
+ * @param parent Parent scope
*/
TableScope(SqlValidatorScope parent, SqlNode node) {
- super(parent);
- this.node = node;
- this.beforeLateral = true;
+ super(Preconditions.checkNotNull(parent));
+ this.node = Preconditions.checkNotNull(node);
}
//~ Methods ----------------------------------------------------------------
-
- @Override public void addChild(SqlValidatorNamespace ns, String alias,
- boolean nullable) {
- if (beforeLateral) {
- super.addChild(ns, alias, nullable);
- }
- }
-
public SqlNode getNode() {
return node;
}
- public void meetLateral() {
- this.beforeLateral = false;
+ @Override public boolean isWithin(SqlValidatorScope scope2) {
+ if (this == scope2) {
+ return true;
+ }
+ SqlValidatorScope s = getValidator().getSelectScope((SqlSelect) node);
+ return s.isWithin(scope2);
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/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 71edcee..3767e30 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -2439,7 +2439,7 @@ public class SqlToRelConverter {
String originalFieldName = fieldAccess.getField().getName();
final SqlNameMatcher nameMatcher =
- lookup.bb.scope.getValidator().getCatalogReader().nameMatcher();
+ bb.getValidator().getCatalogReader().nameMatcher();
final SqlValidatorScope.ResolvedImpl resolved =
new SqlValidatorScope.ResolvedImpl();
lookup.bb.scope.resolve(ImmutableList.of(originalRelName),
@@ -2450,7 +2450,7 @@ public class SqlToRelConverter {
final RelDataType rowType = resolve.rowType();
final int childNamespaceIndex = resolve.path.steps().get(0).i;
final SqlValidatorScope ancestorScope = resolve.scope;
- boolean correlInCurrentScope = ancestorScope == bb.scope;
+ boolean correlInCurrentScope = bb.scope.isWithin(ancestorScope);
if (!correlInCurrentScope) {
continue;
@@ -5404,6 +5404,7 @@ public class SqlToRelConverter {
private static class CorrelationUse {
private final CorrelationId id;
private final ImmutableBitSet requiredColumns;
+ /** The relational expression that uses the variable. */
private final RelNode r;
CorrelationUse(CorrelationId id, ImmutableBitSet requiredColumns,
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/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 b68f2a8..40d2f37 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -2111,6 +2111,35 @@ public class JdbcTest {
"empid=150; deptno=10; name=Sebastian; salary=7000.0; commission=null; deptno0=10; name0=Sales; employees=[{100, 10, Bill, 10000.0, 1000}, {150, 10, Sebastian, 7000.0, null}]; location={-122, 38}");
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-531">[CALCITE-531]
+ * Window function does not work in LATERAL</a>. */
+ @Test public void testLateralWithOver() {
+ final String sql = "select \"emps\".\"name\", d.\"deptno\", d.m\n"
+ + "from \"hr\".\"emps\",\n"
+ + " LATERAL (\n"
+ + " select \"depts\".\"deptno\",\n"
+ + " max(\"deptno\" + \"emps\".\"empid\") over (\n"
+ + " partition by \"emps\".\"deptno\") as m\n"
+ + " from \"hr\".\"depts\"\n"
+ + " where \"emps\".\"deptno\" = \"depts\".\"deptno\") as d";
+ CalciteAssert.that()
+ .with(CalciteAssert.Config.REGULAR)
+ .query(sql)
+ .returnsUnordered("name=Bill; deptno=10; M=190",
+ "name=Bill; deptno=30; M=190",
+ "name=Bill; deptno=40; M=190",
+ "name=Eric; deptno=10; M=240",
+ "name=Eric; deptno=30; M=240",
+ "name=Eric; deptno=40; M=240",
+ "name=Sebastian; deptno=10; M=190",
+ "name=Sebastian; deptno=30; M=190",
+ "name=Sebastian; deptno=40; M=190",
+ "name=Theodore; deptno=10; M=190",
+ "name=Theodore; deptno=30; M=190",
+ "name=Theodore; deptno=40; M=190");
+ }
+
/** Per SQL std, UNNEST is implicitly LATERAL. */
@Test public void testUnnestArrayColumn() {
CalciteAssert.hr()
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/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 743b7c4..d710661 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -4812,8 +4812,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
"RecordType(CHAR(2) NOT NULL A, INTEGER NOT NULL B) NOT NULL");
}
- // todo: implement IN
- public void _testAmbiguousColumnInIn() {
+ @Test public void testAmbiguousColumnInIn() {
// ok: cyclic reference
check("select * from emp as e\n"
+ "where e.deptno in (\n"
@@ -7506,7 +7505,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
}
@Test public void testUnnestArrayColumn() {
- final String sql = "select d.deptno, e.*\n"
+ final String sql1 = "select d.deptno, e.*\n"
+ "from dept_nested as d,\n"
+ " UNNEST(d.employees) as e";
final String type = "RecordType(INTEGER NOT NULL DEPTNO,"
@@ -7515,7 +7514,13 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
+ " RecordType(RecordType(VARCHAR(10) NOT NULL TYPE, VARCHAR(20) NOT NULL DESC,"
+ " RecordType(VARCHAR(10) NOT NULL A, VARCHAR(10) NOT NULL B) NOT NULL OTHERS)"
+ " NOT NULL ARRAY NOT NULL SKILLS) NOT NULL DETAIL) NOT NULL";
- sql(sql).type(type);
+ sql(sql1).type(type);
+
+ // equivalent query without table alias
+ final String sql1b = "select d.deptno, e.*\n"
+ + "from dept_nested as d,\n"
+ + " UNNEST(employees) as e";
+ sql(sql1b).type(type);
// equivalent query using CROSS JOIN
final String sql2 = "select d.deptno, e.*\n"
@@ -7523,6 +7528,12 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
+ " UNNEST(d.employees) as e";
sql(sql2).type(type);
+ // equivalent query using CROSS JOIN, without table alias
+ final String sql2b = "select d.deptno, e.*\n"
+ + "from dept_nested as d CROSS JOIN\n"
+ + " UNNEST(employees) as e";
+ sql(sql2b).type(type);
+
// LATERAL works left-to-right
final String sql3 = "select d.deptno, e.*\n"
+ "from UNNEST(^d^.employees) as e, dept_nested as d";
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
index 77e8753..b78df79 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
@@ -335,7 +335,8 @@ public class SqlValidatorTestCase {
actualLine = Integer.parseInt(matcher.group(1));
actualColumn = Integer.parseInt(matcher.group(2));
} else {
- if (actualMessage.toString().matches(expectedMsgPattern)) {
+ if (expectedMsgPattern != null
+ && actualMessage.matches(expectedMsgPattern)) {
return;
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/189b50d5/core/src/test/java/org/apache/calcite/test/TableFunctionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/TableFunctionTest.java b/core/src/test/java/org/apache/calcite/test/TableFunctionTest.java
index 336fb54..b0ed547 100644
--- a/core/src/test/java/org/apache/calcite/test/TableFunctionTest.java
+++ b/core/src/test/java/org/apache/calcite/test/TableFunctionTest.java
@@ -413,13 +413,26 @@ public class TableFunctionTest {
}
@Test public void testCrossApply() {
- final String q = "select *\n"
+ final String q1 = "select *\n"
+ "from (values 2, 5) as t (c)\n"
+ "cross apply table(\"s\".\"fibonacci2\"(c))";
- with()
- .with(CalciteConnectionProperty.CONFORMANCE, SqlConformanceEnum.LENIENT)
- .query(q)
- .returnsUnordered("C=7");
+ final String q2 = "select *\n"
+ + "from (values 2, 5) as t (c)\n"
+ + "cross apply table(\"s\".\"fibonacci2\"(t.c))";
+ for (String q : new String[] {q1, q2}) {
+ with()
+ .with(CalciteConnectionProperty.CONFORMANCE,
+ SqlConformanceEnum.LENIENT)
+ .query(q)
+ .returnsUnordered("C=2; N=1",
+ "C=2; N=1",
+ "C=2; N=2",
+ "C=5; N=1",
+ "C=5; N=1",
+ "C=5; N=2",
+ "C=5; N=3",
+ "C=5; N=5");
+ }
}
}