From d5dd0e0d75ae1b543de2d23202245201c9d5af33 Mon Sep 17 00:00:00 2001 From: Hosur Narahari Date: Mon, 4 May 2015 22:13:40 +0530 Subject: [PATCH 1/4] METAMODEL-133 defect fix --- .../org/apache/metamodel/query/FromItem.java | 5 ++ .../query/parser/FromItemParser.java | 64 +++++++++++++++---- .../apache/metamodel/query/FromItemTest.java | 38 +++++++++++ 3 files changed, 95 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/org/apache/metamodel/query/FromItem.java b/core/src/main/java/org/apache/metamodel/query/FromItem.java index 8ee07fa41..392c0bfe3 100644 --- a/core/src/main/java/org/apache/metamodel/query/FromItem.java +++ b/core/src/main/java/org/apache/metamodel/query/FromItem.java @@ -267,6 +267,11 @@ private void appendJoinOnItem(StringBuilder sb, String sideAlias, SelectItem onI sb.append(superQueryAlias); return; } + + if(_join != null && _leftSide.getJoin() != null) { + sb.append(onItem.toSql()); + return; + } if (sideAlias != null) { sb.append(sideAlias); 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 76ff4f2a9..8b5c389dd 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 @@ -18,6 +18,11 @@ */ package org.apache.metamodel.query.parser; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import org.apache.metamodel.DataContext; import org.apache.metamodel.query.FromItem; import org.apache.metamodel.query.JoinType; @@ -66,7 +71,11 @@ public void parse(String delim, String itemToken) { fromItem.setAlias(alias); } } else if (itemToken.toUpperCase().indexOf(" JOIN ") != -1) { - fromItem = parseJoinItem(itemToken); + if(itemToken.split("(?i) JOIN ").length == 2) { + fromItem = parseJoinItem(null,itemToken,new HashSet()); + } else { + fromItem = parseAllJoinItems(itemToken); + } } else { fromItem = parseTableItem(itemToken); } @@ -95,10 +104,32 @@ private FromItem parseTableItem(String itemToken) { result.setQuery(_query); return result; } + + private FromItem parseAllJoinItems(final String itemToken) { + String[] joinSplit = itemToken.split("(?i) JOIN "); + List joinsList = new ArrayList(); + for(int i = 0 ; i < joinSplit.length -1 ; i++) { + joinSplit[i] = joinSplit[i].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(" ")); + joinsList.add((leftPart + " " + joinType + " JOIN " + rightPart).replaceAll(" +", " ")); + String rightTable = rightPart.substring(0, rightPart.lastIndexOf(" ON ")); + String nextJoinType = joinSplit[i+1].substring(joinSplit[i+1].lastIndexOf(" ")); + joinSplit[i+1] = rightTable + " " + nextJoinType; + } + Set fromItems = new HashSet(); + FromItem leftFromItem = null; + for(String token : joinsList) { + leftFromItem = parseJoinItem(leftFromItem, token, fromItems); + } + return leftFromItem; + } // this method will be documented based on this example itemToken: FOO f // INNER JOIN BAR b ON f.id = b.id - private FromItem parseJoinItem(final String itemToken) { + private FromItem parseJoinItem(final FromItem leftFromItem,final String itemToken,Set fromItems) { final int indexOfJoin = itemToken.toUpperCase().indexOf(" JOIN "); // firstPart = "FOO f INNER" @@ -123,6 +154,8 @@ private FromItem parseJoinItem(final String itemToken) { final FromItem leftSide = parseTableItem(firstTableToken); final FromItem rightSide = parseTableItem(secondTableToken); + + fromItems.add(leftSide); // onClausess = ["f.id = b.id"] final String[] onClauses = secondPart.substring(indexOfOn + " ON ".length()).split(" AND "); @@ -136,16 +169,17 @@ private FromItem parseJoinItem(final String itemToken) { // rightPart = "b.id" final String rightPart = onClause.substring(indexOfEquals + 1).trim(); - leftOn[i] = findSelectItem(leftPart, leftSide, rightSide); - rightOn[i] = findSelectItem(rightPart, leftSide, rightSide); + leftOn[i] = findSelectItem(leftPart, fromItems.toArray(new FromItem[fromItems.size()]), rightSide); + rightOn[i] = findSelectItem(rightPart, fromItems.toArray(new FromItem[fromItems.size()]), rightSide); } - - final FromItem result = new FromItem(joinType, leftSide, rightSide, leftOn, rightOn); + + final FromItem leftItem = (leftFromItem != null) ? leftFromItem : leftSide; + final FromItem result = new FromItem(joinType, leftItem, rightSide, leftOn, rightOn); result.setQuery(_query); return result; } - private SelectItem findSelectItem(String token, FromItem leftSide, FromItem rightSide) { + private SelectItem findSelectItem(String token, FromItem[] leftSides, FromItem rightSide) { // first look in the original query SelectItemParser selectItemParser = new SelectItemParser(_query, false); SelectItem result = selectItemParser.findSelectItem(token); @@ -153,17 +187,23 @@ private SelectItem findSelectItem(String token, FromItem leftSide, FromItem righ if (result == null) { // fail over and try with the from items available in the join that // is being built. - final Query temporaryQuery = new Query().from(leftSide, rightSide); - selectItemParser = new SelectItemParser(temporaryQuery, false); - result = selectItemParser.findSelectItem(token); - + FromItem leftFromItem = null; + for(FromItem leftSide : leftSides) { + final Query temporaryQuery = new Query().from(leftSide, rightSide); + selectItemParser = new SelectItemParser(temporaryQuery, false); + result = selectItemParser.findSelectItem(token); + if(result != null) { + leftFromItem = leftSide; + break; + } + } if (result == null) { throw new QueryParserException("Not capable of parsing ON token: " + token); } // set the query on the involved query parts (since they have been // temporarily moved to the searched query). - leftSide.setQuery(_query); + leftFromItem.setQuery(_query); rightSide.setQuery(_query); result.setQuery(_query); } diff --git a/core/src/test/java/org/apache/metamodel/query/FromItemTest.java b/core/src/test/java/org/apache/metamodel/query/FromItemTest.java index 49678411a..5868ac2c7 100644 --- a/core/src/test/java/org/apache/metamodel/query/FromItemTest.java +++ b/core/src/test/java/org/apache/metamodel/query/FromItemTest.java @@ -18,7 +18,14 @@ */ package org.apache.metamodel.query; +import org.apache.metamodel.MetaModelException; import org.apache.metamodel.MetaModelTestCase; +import org.apache.metamodel.QueryPostprocessDataContext; +import org.apache.metamodel.data.DataSet; +import org.apache.metamodel.data.DataSetHeader; +import org.apache.metamodel.data.DefaultRow; +import org.apache.metamodel.data.InMemoryDataSet; +import org.apache.metamodel.data.SimpleDataSetHeader; import org.apache.metamodel.schema.Column; import org.apache.metamodel.schema.Relationship; import org.apache.metamodel.schema.Schema; @@ -98,4 +105,35 @@ public void testSubQueryJoinToString() throws Exception { "MetaModelSchema.project a LEFT JOIN (SELECT c.contributor_id, c.project_id AS foobar, c.name FROM MetaModelSchema.role c) b ON a.project_id = b.foobar", from.toString()); } + + public void testCompoundJoin() { + final Schema schema = getExampleSchema(); + + final QueryPostprocessDataContext dc = new QueryPostprocessDataContext() { + @Override + protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) { + Object[] values = new Object[columns.length]; + for (int i = 0; i < columns.length; i++) { + values[i] = columns[i].getColumnNumber(); + } + DataSetHeader header = new SimpleDataSetHeader(columns); + DefaultRow row = new DefaultRow(header, values); + return new InMemoryDataSet(row); + } + + @Override + protected String getMainSchemaName() throws MetaModelException { + return "MetaModelSchema"; + } + + @Override + protected Schema getMainSchema() throws MetaModelException { + return schema; + } + }; + + Query query = dc.parseQuery("SELECT c.contributor_id,p.project_id from contributor c INNER JOIN role r ON c.contributor_id=r.contributor_id INNER JOIN project p ON p.project_id=r.project_id"); + System.out.println(query); + assertEquals("SELECT c.contributor_id, p.project_id FROM MetaModelSchema.contributor c INNER JOIN MetaModelSchema.role r ON c.contributor_id = r.contributor_id INNER JOIN MetaModelSchema.project p ON p.project_id = r.project_id", query.toSql()); + } } \ No newline at end of file From 8f6eae7245c38c74b1d24df10e9132299e5a4e31 Mon Sep 17 00:00:00 2001 From: Hosur Narahari Date: Mon, 4 May 2015 22:55:42 +0530 Subject: [PATCH 2/4] METAMODEL-133 defect fix --- .../org/apache/metamodel/query/FromItemTest.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/core/src/test/java/org/apache/metamodel/query/FromItemTest.java b/core/src/test/java/org/apache/metamodel/query/FromItemTest.java index 5868ac2c7..b026f8d5b 100644 --- a/core/src/test/java/org/apache/metamodel/query/FromItemTest.java +++ b/core/src/test/java/org/apache/metamodel/query/FromItemTest.java @@ -22,10 +22,6 @@ import org.apache.metamodel.MetaModelTestCase; import org.apache.metamodel.QueryPostprocessDataContext; import org.apache.metamodel.data.DataSet; -import org.apache.metamodel.data.DataSetHeader; -import org.apache.metamodel.data.DefaultRow; -import org.apache.metamodel.data.InMemoryDataSet; -import org.apache.metamodel.data.SimpleDataSetHeader; import org.apache.metamodel.schema.Column; import org.apache.metamodel.schema.Relationship; import org.apache.metamodel.schema.Schema; @@ -112,13 +108,7 @@ public void testCompoundJoin() { final QueryPostprocessDataContext dc = new QueryPostprocessDataContext() { @Override protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) { - Object[] values = new Object[columns.length]; - for (int i = 0; i < columns.length; i++) { - values[i] = columns[i].getColumnNumber(); - } - DataSetHeader header = new SimpleDataSetHeader(columns); - DefaultRow row = new DefaultRow(header, values); - return new InMemoryDataSet(row); + throw new UnsupportedOperationException("This method is not used"); } @Override @@ -133,7 +123,6 @@ protected Schema getMainSchema() throws MetaModelException { }; Query query = dc.parseQuery("SELECT c.contributor_id,p.project_id from contributor c INNER JOIN role r ON c.contributor_id=r.contributor_id INNER JOIN project p ON p.project_id=r.project_id"); - System.out.println(query); assertEquals("SELECT c.contributor_id, p.project_id FROM MetaModelSchema.contributor c INNER JOIN MetaModelSchema.role r ON c.contributor_id = r.contributor_id INNER JOIN MetaModelSchema.project p ON p.project_id = r.project_id", query.toSql()); } } \ No newline at end of file From 9e78d5e564d1fcdd77db5f103ea19387b2b4dbfc Mon Sep 17 00:00:00 2001 From: Hosur Narahari Date: Mon, 4 May 2015 23:31:52 +0530 Subject: [PATCH 3/4] METAMODEL-133 defect fix --- .../apache/metamodel/query/parser/FromItemParser.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) 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 8b5c389dd..e3951b862 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 @@ -71,11 +71,7 @@ public void parse(String delim, String itemToken) { fromItem.setAlias(alias); } } else if (itemToken.toUpperCase().indexOf(" JOIN ") != -1) { - if(itemToken.split("(?i) JOIN ").length == 2) { - fromItem = parseJoinItem(null,itemToken,new HashSet()); - } else { - fromItem = parseAllJoinItems(itemToken); - } + fromItem = parseAllJoinItems(itemToken); } else { fromItem = parseTableItem(itemToken); } @@ -115,7 +111,7 @@ private FromItem parseAllJoinItems(final String itemToken) { 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(" ")); joinsList.add((leftPart + " " + joinType + " JOIN " + rightPart).replaceAll(" +", " ")); - String rightTable = rightPart.substring(0, rightPart.lastIndexOf(" ON ")); + String rightTable = rightPart.substring(0, rightPart.toUpperCase().lastIndexOf(" ON ")); String nextJoinType = joinSplit[i+1].substring(joinSplit[i+1].lastIndexOf(" ")); joinSplit[i+1] = rightTable + " " + nextJoinType; } @@ -129,7 +125,7 @@ private FromItem parseAllJoinItems(final String itemToken) { // this method will be documented based on this example itemToken: FOO f // INNER JOIN BAR b ON f.id = b.id - private FromItem parseJoinItem(final FromItem leftFromItem,final String itemToken,Set fromItems) { + private FromItem parseJoinItem(final FromItem leftFromItem, final String itemToken, Set fromItems) { final int indexOfJoin = itemToken.toUpperCase().indexOf(" JOIN "); // firstPart = "FOO f INNER" From 58992037f279e42974df71727c9b395663a669aa Mon Sep 17 00:00:00 2001 From: Hosur Narahari Date: Tue, 5 May 2015 21:24:51 +0530 Subject: [PATCH 4/4] METAMODEL-133 fix --- .../query/parser/FromItemParser.java | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) 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 e3951b862..cc8916aca 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 @@ -152,6 +152,7 @@ private FromItem parseJoinItem(final FromItem leftFromItem, final String itemTok final FromItem rightSide = parseTableItem(secondTableToken); fromItems.add(leftSide); + fromItems.add(rightSide); // onClausess = ["f.id = b.id"] final String[] onClauses = secondPart.substring(indexOfOn + " ON ".length()).split(" AND "); @@ -165,8 +166,8 @@ private FromItem parseJoinItem(final FromItem leftFromItem, final String itemTok // rightPart = "b.id" final String rightPart = onClause.substring(indexOfEquals + 1).trim(); - leftOn[i] = findSelectItem(leftPart, fromItems.toArray(new FromItem[fromItems.size()]), rightSide); - rightOn[i] = findSelectItem(rightPart, fromItems.toArray(new FromItem[fromItems.size()]), rightSide); + 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; @@ -175,7 +176,7 @@ private FromItem parseJoinItem(final FromItem leftFromItem, final String itemTok return result; } - private SelectItem findSelectItem(String token, FromItem[] leftSides, FromItem rightSide) { + private SelectItem findSelectItem(String token, FromItem[] joinTables) { // first look in the original query SelectItemParser selectItemParser = new SelectItemParser(_query, false); SelectItem result = selectItemParser.findSelectItem(token); @@ -183,24 +184,15 @@ private SelectItem findSelectItem(String token, FromItem[] leftSides, FromItem r if (result == null) { // fail over and try with the from items available in the join that // is being built. - FromItem leftFromItem = null; - for(FromItem leftSide : leftSides) { - final Query temporaryQuery = new Query().from(leftSide, rightSide); - selectItemParser = new SelectItemParser(temporaryQuery, false); - result = selectItemParser.findSelectItem(token); - if(result != null) { - leftFromItem = leftSide; - break; - } - } + final Query temporaryQuery = new Query().from(joinTables); + selectItemParser = new SelectItemParser(temporaryQuery, false); + result = selectItemParser.findSelectItem(token); if (result == null) { throw new QueryParserException("Not capable of parsing ON token: " + token); } // set the query on the involved query parts (since they have been // temporarily moved to the searched query). - leftFromItem.setQuery(_query); - rightSide.setQuery(_query); result.setQuery(_query); } return result;