You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/09/30 05:12:01 UTC
incubator-calcite git commit: [CALCITE-546] Allow table,
column and field called '*'
Repository: incubator-calcite
Updated Branches:
refs/heads/master c2950ebaf -> 1c292a9d5
[CALCITE-546] Allow table, column and field called '*'
Now a star in the SqlIdentifier's name list means a literal
star. If you want to create an identifier with a wild-card star
in it, either use the new SqlIdentifier.star method or replace
the star with an empty string.
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/1c292a9d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/1c292a9d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/1c292a9d
Branch: refs/heads/master
Commit: 1c292a9d5225f495d319aaa581185a18ae4502aa
Parents: c2950eb
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Sep 29 16:33:13 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Sep 29 20:11:23 2015 -0700
----------------------------------------------------------------------
core/src/main/codegen/templates/Parser.jj | 14 ++--
.../apache/calcite/adapter/jdbc/JdbcTable.java | 3 +-
.../org/apache/calcite/sql/SqlIdentifier.java | 60 ++++++++++++---
.../apache/calcite/sql/SqlSelectOperator.java | 5 +-
.../calcite/sql/validate/SqlValidatorImpl.java | 14 +++-
.../calcite/test/SqlToRelConverterTest.java | 4 +
.../apache/calcite/test/SqlValidatorTest.java | 14 +++-
.../calcite/test/SqlToRelConverterTest.xml | 11 +++
core/src/test/resources/sql/misc.oq | 77 ++++++++++++++++++++
9 files changed, 174 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/core/src/main/codegen/templates/Parser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj
index cb50599..756ed6a 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -1422,13 +1422,11 @@ SqlNode SelectItem() :
SqlNode SelectExpression() :
{
SqlNode e;
- SqlParserPos pos;
}
{
<STAR>
{
- pos = getPos();
- return new SqlIdentifier("*", pos);
+ return SqlIdentifier.star(getPos());
}
|
e = Expression(ExprContext.ACCEPT_SUBQUERY)
@@ -3520,6 +3518,7 @@ SqlIdentifier CompoundIdentifier() :
List<String> list = new ArrayList<String>();
List<SqlParserPos> posList = new ArrayList<SqlParserPos>();
String p;
+ boolean star = false;
}
{
p = Identifier()
@@ -3531,11 +3530,13 @@ SqlIdentifier CompoundIdentifier() :
<DOT>
(
p = Identifier() {
+ star = false;
list.add(p);
posList.add(getPos());
}
|
<STAR> {
+ star = true;
list.add("*");
posList.add(getPos());
}
@@ -3543,6 +3544,9 @@ SqlIdentifier CompoundIdentifier() :
) *
{
SqlParserPos pos = SqlParserPos.sum(posList);
+ if (star) {
+ return SqlIdentifier.star(list, pos, posList);
+ }
return new SqlIdentifier(list, null, pos, posList);
}
}
@@ -4140,7 +4144,7 @@ SqlNode NamedFunctionCall() :
(
LOOKAHEAD(2) <LPAREN> <STAR> { starPos = getPos(); } <RPAREN>
{
- args = startList(new SqlIdentifier("*", starPos));
+ args = startList(SqlIdentifier.star(starPos));
pos = pos.plus(getPos());
}
| LOOKAHEAD(2) <LPAREN> <RPAREN>
@@ -4394,7 +4398,7 @@ SqlNode JdbcFunctionCall() :
LOOKAHEAD(2) <LPAREN> <STAR> {starPos = getPos();} <RPAREN>
{
args = new SqlNodeList(starPos);
- args.add(new SqlIdentifier("*", starPos));
+ args.add(SqlIdentifier.star(starPos));
}
| LOOKAHEAD(2) <LPAREN> <RPAREN>
{ args = new SqlNodeList(pos); }
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
index f820c28..237a822 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
@@ -129,8 +129,7 @@ class JdbcTable extends AbstractQueryableTable
SqlString generateSql() {
final SqlNodeList selectList =
new SqlNodeList(
- Collections.singletonList(
- new SqlIdentifier("*", SqlParserPos.ZERO)),
+ Collections.singletonList(SqlIdentifier.star(SqlParserPos.ZERO)),
SqlParserPos.ZERO);
SqlSelect node =
new SqlSelect(SqlParserPos.ZERO, SqlNodeList.EMPTY, selectList,
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
index 854b18b..9d0d633 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
@@ -24,7 +24,9 @@ import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.util.Util;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import java.util.List;
@@ -32,11 +34,28 @@ import java.util.List;
* A <code>SqlIdentifier</code> is an identifier, possibly compound.
*/
public class SqlIdentifier extends SqlNode {
+ private static final Function<String, String> STAR_TO_EMPTY =
+ new Function<String, String>() {
+ public String apply(String s) {
+ return s.equals("*") ? "" : s;
+ }
+ };
+
+ private static final Function<String, String> EMPTY_TO_STAR =
+ new Function<String, String>() {
+ public String apply(String s) {
+ return s.equals("") ? "*" : s.equals("*") ? "\"*\"" : s;
+ }
+ };
+
//~ Instance fields --------------------------------------------------------
/**
* Array of the components of this compound identifier.
*
+ * <p>The empty string represents the wildcard "*",
+ * to distinguish it from a real "*" (presumably specified using quotes).
+ *
* <p>It's convenient to have this member public, and it's convenient to
* have this member not-final, but it's a shame it's public and not-final.
* If you assign to this member, please use
@@ -53,7 +72,7 @@ public class SqlIdentifier extends SqlNode {
/**
* A list of the positions of the components of compound identifiers.
*/
- private ImmutableList<SqlParserPos> componentPositions;
+ protected ImmutableList<SqlParserPos> componentPositions;
//~ Constructors -----------------------------------------------------------
@@ -101,6 +120,18 @@ public class SqlIdentifier extends SqlNode {
this(ImmutableList.of(name), null, pos, null);
}
+ /** Creates an identifier that is a singleton wildcard star. */
+ public static SqlIdentifier star(SqlParserPos pos) {
+ return star(ImmutableList.of(""), pos, ImmutableList.of(pos));
+ }
+
+ /** Creates an identifier that ends in a wildcard star. */
+ public static SqlIdentifier star(List<String> names, SqlParserPos pos,
+ List<SqlParserPos> componentPositions) {
+ return new SqlIdentifier(Lists.transform(names, STAR_TO_EMPTY), null, pos,
+ componentPositions);
+ }
+
//~ Methods ----------------------------------------------------------------
public SqlKind getKind() {
@@ -112,7 +143,7 @@ public class SqlIdentifier extends SqlNode {
}
public String toString() {
- return Util.sepList(names, ".");
+ return Util.sepList(Lists.transform(names, EMPTY_TO_STAR), ".");
}
/**
@@ -194,11 +225,18 @@ public class SqlIdentifier extends SqlNode {
public SqlIdentifier plus(String name, SqlParserPos pos) {
final ImmutableList<String> names =
ImmutableList.<String>builder().addAll(this.names).add(name).build();
- final ImmutableList.Builder<SqlParserPos> builder = ImmutableList.builder();
- final ImmutableList<SqlParserPos> componentPositions =
- builder.addAll(this.componentPositions).add(pos).build();
- final SqlParserPos pos2 =
- SqlParserPos.sum(builder.add(this.pos).build());
+ final ImmutableList<SqlParserPos> componentPositions;
+ final SqlParserPos pos2;
+ if (this.componentPositions != null) {
+ final ImmutableList.Builder<SqlParserPos> builder =
+ ImmutableList.builder();
+ componentPositions =
+ builder.addAll(this.componentPositions).add(pos).build();
+ pos2 = SqlParserPos.sum(builder.add(this.pos).build());
+ } else {
+ componentPositions = null;
+ pos2 = pos;
+ }
return new SqlIdentifier(names, collation, pos2, componentPositions);
}
@@ -216,8 +254,8 @@ public class SqlIdentifier extends SqlNode {
writer.startList(SqlWriter.FrameTypeEnum.IDENTIFIER);
for (String name : names) {
writer.sep(".");
- if (name.equals("*")) {
- writer.print(name);
+ if (name.equals("")) {
+ writer.print("*");
} else {
writer.identifier(name);
}
@@ -284,7 +322,7 @@ public class SqlIdentifier extends SqlNode {
* Returns whether this identifier is a star, such as "*" or "foo.bar.*".
*/
public boolean isStar() {
- return Util.last(names).equals("*");
+ return Util.last(names).equals("");
}
/**
@@ -292,7 +330,7 @@ public class SqlIdentifier extends SqlNode {
* "FOO.*" and "FOO.BAR" are not.
*/
public boolean isSimple() {
- return (names.size() == 1) && !names.get(0).equals("*");
+ return names.size() == 1 && !isStar();
}
public SqlMonotonicity getMonotonicity(SqlValidatorScope scope) {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
index 858e58f..888a070 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
@@ -144,10 +144,7 @@ public class SqlSelectOperator extends SqlOperator {
}
SqlNode selectClause = select.selectList;
if (selectClause == null) {
- selectClause =
- new SqlIdentifier(
- "*",
- SqlParserPos.ZERO);
+ selectClause = SqlIdentifier.star(SqlParserPos.ZERO);
}
final SqlWriter.Frame selectListFrame =
writer.startList(SqlWriter.FrameTypeEnum.SELECT_LIST);
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/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 3b3e62d..d234b6d 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
@@ -1054,7 +1054,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
}
}
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
- selectList.add(new SqlIdentifier("*", SqlParserPos.ZERO));
+ selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
final SqlNodeList orderList;
if (getInnerSelect(node) != null && isAggregate(getInnerSelect(node))) {
orderList =
@@ -1084,7 +1084,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
// (TABLE t) is equivalent to (SELECT * FROM t)
SqlCall call = (SqlCall) node;
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
- selectList.add(new SqlIdentifier("*", SqlParserPos.ZERO));
+ selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
return new SqlSelect(SqlParserPos.ZERO, null, selectList, call.operand(0),
null, null, null, null, null, null, null);
}
@@ -4269,7 +4269,15 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
// Resolve rest of identifier
for (; i < id.names.size(); i++) {
String name = id.names.get(i);
- final RelDataTypeField field = catalogReader.field(type, name);
+ final RelDataTypeField field;
+ if (name.equals("")) {
+ // The wildcard "*" is represented as an empty name. It never
+ // resolves to a field.
+ name = "*";
+ field = null;
+ } else {
+ field = catalogReader.field(type, name);
+ }
if (field == null) {
throw newValidationError(id.getComponent(i),
RESOURCE.unknownField(name));
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/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 dc5b051..1494a78 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -369,6 +369,10 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
+ "group by deptno").ok();
}
+ @Test public void testFakeStar() {
+ sql("SELECT * FROM (VALUES (0, 0)) AS T(A, \"*\")").ok();
+ }
+
@Test public void testSelectDistinct() {
sql("select distinct sal + 5 from emp").ok();
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/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 f1de2ff..a319f43 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -4550,6 +4550,16 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
"Unknown identifier 'EMPNO'");
}
+ /**
+ * Test case for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-546">[CALCITE-546]
+ * Allow table, column and field called '*'</a>.
+ */
+ @Test public void testStarIdentifier() {
+ sql("SELECT * FROM (VALUES (0, 0)) AS T(A, \"*\")")
+ .type("RecordType(INTEGER NOT NULL A, INTEGER NOT NULL *) NOT NULL");
+ }
+
@Test public void testStarAliasFails() {
sql("select emp.^*^ AS x from emp")
.fails("Unknown field '\\*'");
@@ -4566,9 +4576,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
* Parser allows "*" in FROM clause because "*" can occur in any identifier.
* But validator must not.
*
- * <p>See also
- * <a href="https://issues.apache.org/jira/browse/CALCITE-546">[CALCITE-546]
- * Allow table, column and field called '*'</a> (not yet fixed).
+ * @see #testStarIdentifier()
*/
@Test public void testStarInFromFails() {
sql("select emp.empno AS x from ^sales.*^")
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/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 751ecfa..5912ed6 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2520,4 +2520,15 @@ LogicalProject(EMPNO=[$0])
]]>
</Resource>
</TestCase>
+ <TestCase name="testFakeStar">
+ <Resource name="sql">
+ <![CDATA[SELECT * FROM (VALUES (0, 0)) AS T(A, "*")]]>
+ </Resource>
+ <Resource name="plan">
+ <![CDATA[
+LogicalProject(A=[$0], *=[$1])
+ LogicalValues(tuples=[[{ 0, 0 }]])
+]]>
+ </Resource>
+ </TestCase>
</Root>
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/1c292a9d/core/src/test/resources/sql/misc.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.oq b/core/src/test/resources/sql/misc.oq
index 2b9b3c9..2704812 100644
--- a/core/src/test/resources/sql/misc.oq
+++ b/core/src/test/resources/sql/misc.oq
@@ -965,4 +965,81 @@ select * from "scott".emp where '7369' between empno and '7876';
!ok
+# [CALCITE-546] Allow table, column and field called "*"
+# See [DRILL-3859], [DRILL-3860].
+SELECT * FROM (VALUES (0, 0)) AS T(A, "*");
++---+---+
+| A | * |
++---+---+
+| 0 | 0 |
++---+---+
+(1 row)
+
+!ok
+
+SELECT a FROM (VALUES (0, 0)) AS T(A, "*");
++---+
+| A |
++---+
+| 0 |
++---+
+(1 row)
+
+!ok
+
+SELECT b FROM (VALUES (0, 0)) AS T(A, "*");
+Column 'B' not found in any table
+!error
+
+# See [DRILL-3860].
+SELECT "a" FROM (VALUES (1, 2, 3, 4)) AS T("a", "A", ".", "*");
++---+
+| a |
++---+
+| 1 |
++---+
+(1 row)
+
+!ok
+
+SELECT "A" FROM (VALUES (1, 2, 3, 4)) AS T("a", "A", ".", "*");
++---+
+| A |
++---+
+| 2 |
++---+
+(1 row)
+
+!ok
+
+SELECT "." FROM (VALUES (1, 2, 3, 4)) AS T("a", "A", ".", "*");
++---+
+| . |
++---+
+| 3 |
++---+
+(1 row)
+
+!ok
+
+SELECT "*" FROM (VALUES (1, 2, 3, 4)) AS T("a", "A", ".", "*");
++---+
+| * |
++---+
+| 4 |
++---+
+(1 row)
+
+!ok
+
+SELECT * FROM (VALUES (1, 2, 3, 4)) AS T("a", "A", ".", "*");
++---+---+---+---+
+| a | A | . | * |
++---+---+---+---+
+| 1 | 2 | 3 | 4 |
++---+---+---+---+
+(1 row)
+
+!ok
+
# End misc.oq