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());