You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metamodel.apache.org by ka...@apache.org on 2015/11/27 08:27:53 UTC
metamodel git commit: METAMODEL-15: Fixed query parsing for table
names
Repository: metamodel
Updated Branches:
refs/heads/master 19564d0d8 -> f7989b85f
METAMODEL-15: Fixed query parsing for table names
Fixes #72
Project: http://git-wip-us.apache.org/repos/asf/metamodel/repo
Commit: http://git-wip-us.apache.org/repos/asf/metamodel/commit/f7989b85
Tree: http://git-wip-us.apache.org/repos/asf/metamodel/tree/f7989b85
Diff: http://git-wip-us.apache.org/repos/asf/metamodel/diff/f7989b85
Branch: refs/heads/master
Commit: f7989b85f2212a65881bfa5cbabb4577fd92e533
Parents: 19564d0
Author: Ashwin Rayaprolu <as...@gmail.com>
Authored: Fri Nov 27 08:27:49 2015 +0100
Committer: Kasper Sørensen <i....@gmail.com>
Committed: Fri Nov 27 08:27:49 2015 +0100
----------------------------------------------------------------------
CHANGES.md | 1 +
.../metamodel/query/parser/FromItemParser.java | 81 +++++++++++++++-----
.../metamodel/query/parser/QueryParserTest.java | 55 ++++++++++---
3 files changed, 109 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/metamodel/blob/f7989b85/CHANGES.md
----------------------------------------------------------------------
diff --git a/CHANGES.md b/CHANGES.md
index bdf3696..cdf244a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,7 @@
* [METAMODEL-207] - Ensured the serializability of the SingleLineCsvRow class.
* [METAMODEL-211] - Fixed a bug related to lookup by primary key (_id) on MongoDB.
+ * [METAMODEL-15] - Query parser support for table names with space. Delimitters can be double quote or square brackets.
### Apache MetaModel 4.4.1
http://git-wip-us.apache.org/repos/asf/metamodel/blob/f7989b85/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java b/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java
index cc8916a..f24f83d 100644
--- a/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java
+++ b/core/src/main/java/org/apache/metamodel/query/parser/FromItemParser.java
@@ -19,8 +19,10 @@
package org.apache.metamodel.query.parser;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.apache.metamodel.DataContext;
@@ -33,7 +35,17 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final class FromItemParser implements QueryPartProcessor {
-
+
+ /**
+ * This field will hold start and end character for delimiter that can be
+ * used
+ */
+ private static final Map<Character, Character> delimiterMap = new HashMap<Character, Character>();
+ static {
+ delimiterMap.put('\"', '\"');
+ delimiterMap.put('[', ']');
+ }
+
private static final Logger logger = LoggerFactory.getLogger(FromItemParser.class);
private final Query _query;
@@ -80,44 +92,75 @@ final class FromItemParser implements QueryPartProcessor {
}
private FromItem parseTableItem(String itemToken) {
- final String[] tokens = itemToken.split(" ");
- final String alias;
- if (tokens.length == 2) {
- alias = tokens[1];
- } else if (tokens.length == 1) {
- alias = null;
+ // From token can be starting with [
+ final String tableNameToken;
+ final String aliasToken;
+
+ char startDelimiter = itemToken.trim().charAt(0);
+ if (delimiterMap.containsKey(startDelimiter)) {
+ char endDelimiter = delimiterMap.get(startDelimiter);
+ int endIndex = itemToken.trim().lastIndexOf(endDelimiter, itemToken.trim().length());
+ if (endIndex <= 0) {
+ throw new QueryParserException("Not capable of parsing FROM token: " + itemToken + ". Expected end "
+ + endDelimiter);
+ }
+ tableNameToken = itemToken.trim().substring(1, endIndex).trim();
+
+ if (itemToken.trim().substring(1 + endIndex).trim().equalsIgnoreCase("")) {
+ /*
+ * As per code in FromClause Method: getItemByReference(FromItem
+ * item, String reference) if (alias == null && table != null &&
+ * reference.equals(table.getName())) { Either we have to change
+ * the code to add alias.equals("") there or return null here.
+ */
+ aliasToken = null;
+ } else {
+ aliasToken = itemToken.trim().substring(1 + endIndex).trim();
+ }
+
} else {
- throw new QueryParserException("Not capable of parsing FROM token: " + itemToken);
+ // Default assumption is space being delimiter for tablename and
+ // alias.. If otherwise use DoubleQuotes or [] around tableName
+ final String[] tokens = itemToken.split(" ");
+ tableNameToken = tokens[0];
+ if (tokens.length == 2) {
+ aliasToken = tokens[1];
+ } else if (tokens.length == 1) {
+ aliasToken = null;
+ } else {
+ throw new QueryParserException("Not capable of parsing FROM token: " + itemToken);
+ }
}
- final Table table = _dataContext.getTableByQualifiedLabel(tokens[0]);
+ final Table table = _dataContext.getTableByQualifiedLabel(tableNameToken);
if (table == null) {
throw new QueryParserException("Not capable of parsing FROM token: " + itemToken);
}
final FromItem result = new FromItem(table);
- result.setAlias(alias);
+ result.setAlias(aliasToken);
result.setQuery(_query);
return result;
}
-
+
private FromItem parseAllJoinItems(final String itemToken) {
String[] joinSplit = itemToken.split("(?i) JOIN ");
List<String> joinsList = new ArrayList<String>();
- for(int i = 0 ; i < joinSplit.length -1 ; i++) {
+ for (int i = 0; i < joinSplit.length - 1; i++) {
joinSplit[i] = joinSplit[i].trim();
- joinSplit[i+1] = joinSplit[i+1].trim();
+ joinSplit[i + 1] = joinSplit[i + 1].trim();
String leftPart = joinSplit[i].substring(0, joinSplit[i].lastIndexOf(" "));
String joinType = joinSplit[i].substring(joinSplit[i].lastIndexOf(" "));
- String rightPart = (i+1 == joinSplit.length-1) ? joinSplit[i+1] : joinSplit[i+1].substring(0, joinSplit[i+1].lastIndexOf(" "));
+ String rightPart = (i + 1 == joinSplit.length - 1) ? joinSplit[i + 1] : joinSplit[i + 1].substring(0,
+ joinSplit[i + 1].lastIndexOf(" "));
joinsList.add((leftPart + " " + joinType + " JOIN " + rightPart).replaceAll(" +", " "));
String rightTable = rightPart.substring(0, rightPart.toUpperCase().lastIndexOf(" ON "));
- String nextJoinType = joinSplit[i+1].substring(joinSplit[i+1].lastIndexOf(" "));
- joinSplit[i+1] = rightTable + " " + nextJoinType;
+ String nextJoinType = joinSplit[i + 1].substring(joinSplit[i + 1].lastIndexOf(" "));
+ joinSplit[i + 1] = rightTable + " " + nextJoinType;
}
Set<FromItem> fromItems = new HashSet<FromItem>();
FromItem leftFromItem = null;
- for(String token : joinsList) {
+ for (String token : joinsList) {
leftFromItem = parseJoinItem(leftFromItem, token, fromItems);
}
return leftFromItem;
@@ -150,7 +193,7 @@ final class FromItemParser implements QueryPartProcessor {
final FromItem leftSide = parseTableItem(firstTableToken);
final FromItem rightSide = parseTableItem(secondTableToken);
-
+
fromItems.add(leftSide);
fromItems.add(rightSide);
@@ -169,7 +212,7 @@ final class FromItemParser implements QueryPartProcessor {
leftOn[i] = findSelectItem(leftPart, fromItems.toArray(new FromItem[fromItems.size()]));
rightOn[i] = findSelectItem(rightPart, fromItems.toArray(new FromItem[fromItems.size()]));
}
-
+
final FromItem leftItem = (leftFromItem != null) ? leftFromItem : leftSide;
final FromItem result = new FromItem(joinType, leftItem, rightSide, leftOn, rightOn);
result.setQuery(_query);
http://git-wip-us.apache.org/repos/asf/metamodel/blob/f7989b85/core/src/test/java/org/apache/metamodel/query/parser/QueryParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/query/parser/QueryParserTest.java b/core/src/test/java/org/apache/metamodel/query/parser/QueryParserTest.java
index 92befe2..1059f9a 100644
--- a/core/src/test/java/org/apache/metamodel/query/parser/QueryParserTest.java
+++ b/core/src/test/java/org/apache/metamodel/query/parser/QueryParserTest.java
@@ -51,11 +51,9 @@ public class QueryParserTest extends TestCase {
col.setType(ColumnType.INTEGER);
};
- public void testQueryWithParenthesisAnd() throws Exception {
- Query q = MetaModelHelper.parseQuery(dc,
- "select foo from sch.tbl where (foo= 1) and (foo=2)");
- assertEquals("SELECT tbl.foo FROM sch.tbl WHERE tbl.foo = '1' AND tbl.foo = '2'",
- q.toSql());
+ public void testQueryWithParenthesisAnd() throws Exception {
+ Query q = MetaModelHelper.parseQuery(dc, "select foo from sch.tbl where (foo= 1) and (foo=2)");
+ assertEquals("SELECT tbl.foo FROM sch.tbl WHERE tbl.foo = '1' AND tbl.foo = '2'", q.toSql());
}
public void testQueryInLowerCase() throws Exception {
@@ -64,10 +62,9 @@ public class QueryParserTest extends TestCase {
assertEquals("SELECT a.foo AS f FROM sch.tbl a INNER JOIN sch.tbl b ON a.foo = b.foo ORDER BY a.foo ASC",
q.toSql());
}
-
+
public void testParseScalarFunctions() throws Exception {
- Query q = MetaModelHelper.parseQuery(dc,
- "select TO_NUM(a.foo) from sch.tbl a WHERE BOOLEAN(a.bar) = false");
+ Query q = MetaModelHelper.parseQuery(dc, "select TO_NUM(a.foo) from sch.tbl a WHERE BOOLEAN(a.bar) = false");
assertEquals("SELECT TO_NUMBER(a.foo) FROM sch.tbl a WHERE TO_BOOLEAN(a.bar) = FALSE", q.toSql());
}
@@ -94,7 +91,7 @@ public class QueryParserTest extends TestCase {
Query q = MetaModelHelper.parseQuery(dc, "SELECT fo.o AS f FROM sch.tbl");
assertEquals("SELECT tbl.fo.o AS f FROM sch.tbl", q.toSql());
}
-
+
public void testApproximateCountQuery() throws Exception {
Query q = MetaModelHelper.parseQuery(dc, "SELECT APPROXIMATE COUNT(*) FROM sch.tbl");
assertEquals("SELECT APPROXIMATE COUNT(*) FROM sch.tbl", q.toSql());
@@ -136,6 +133,46 @@ public class QueryParserTest extends TestCase {
assertEquals("SELECT tbl.foo AS alias FROM sch.tbl", q.toSql());
}
+ /**
+ * This will test differences cases for tablename
+ *
+ * @throws Exception
+ */
+ public void testTableName() throws Exception {
+ Query q = MetaModelHelper.parseQuery(dc, "SELECT tbl.foo AS alias FROM sch.tbl");
+ assertEquals("SELECT tbl.foo AS alias FROM sch.tbl", q.toSql());
+
+ // Missing ] Bracket
+ try {
+ MetaModelHelper.parseQuery(dc, "SELECT tbl.foo AS alias FROM [sch.tbl");
+ fail("Exception expected");
+ } catch (MetaModelException e) {
+ assertEquals("Not capable of parsing FROM token: [sch.tbl. Expected end ]", e.getMessage());
+ }
+
+ try {
+ MetaModelHelper.parseQuery(dc, "SELECT tbl.foo AS alias FROM \"sch.tbl");
+ fail("Exception expected");
+ } catch (MetaModelException e) {
+ assertEquals("Not capable of parsing FROM token: \"sch.tbl. Expected end \"", e.getMessage());
+ }
+ // Test Delimiter in tablename
+ try {
+ MetaModelHelper.parseQuery(dc, "SELECT tbl.foo AS alias FROM \"sch.tbl");
+ fail("Exception expected");
+ } catch (MetaModelException e) {
+ assertEquals("Not capable of parsing FROM token: \"sch.tbl. Expected end \"", e.getMessage());
+ }
+
+ // Positive test case
+ q = MetaModelHelper.parseQuery(dc, "SELECT tbl.foo AS alias FROM [sch.tbl]");
+ assertEquals("SELECT tbl.foo AS alias FROM sch.tbl", q.toSql());
+
+ q = MetaModelHelper.parseQuery(dc, "SELECT tbl.foo AS alias FROM \"sch.tbl\"");
+ assertEquals("SELECT tbl.foo AS alias FROM sch.tbl", q.toSql());
+
+ }
+
public void testSelectAvgInLowerCase() throws Exception {
Query q = MetaModelHelper.parseQuery(dc, "SELECT avg(tbl.foo) FROM sch.tbl");
assertEquals("SELECT AVG(tbl.foo) FROM sch.tbl", q.toSql());