Skip to content
Snippets Groups Projects
Commit 7a70c603 authored by gmantele's avatar gmantele
Browse files

[ADQL] Re-Fix GROUP BY's columns handling:

a qualified column name should be allowed, but still no column index should be.
parent 1e98ff3b
No related branches found
No related tags found
No related merge requests found
/* ADQLParser.java */
/* Generated By:JavaCC: Do not edit this line. ADQLParser.java
*
* Modified by Gregory Mantelet (ARI), March 2017
* Modification: line 5686, from:
*
* public ADQLParser(java.io.InputStream stream){
* this(stream, null);
* }
*
* to:
*
* public ADQLParser(java.io.InputStream stream){
* this(stream, (String)null);
* }
*/
/* Generated By:JavaCC: Do not edit this line. ADQLParser.java */
package adql.parser;
import java.io.FileReader;
......@@ -82,7 +68,7 @@ import adql.translator.TranslationException;
* @see ADQLQueryFactory
*
* @author Grégory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
* @version 1.4 (03/2017)
* @version 1.4 (04/2017)
*/
public class ADQLParser implements ADQLParserConstants {
......@@ -1110,12 +1096,12 @@ public class ADQLParser implements ADQLParserConstants {
final public ColumnReference ColumnRef() throws ParseException{
trace_call("ColumnRef");
try{
IdentifierItem identifier = null;
identifier = Identifier();
IdentifierItems identifiers = null;
identifiers = ColumnName();
try{
{
if ("" != null)
return queryFactory.createColRef(identifier);
return queryFactory.createColRef(identifiers);
}
}catch(Exception ex){
{
......
......@@ -16,7 +16,7 @@ package adql.parser;
* You should have received a copy of the GNU Lesser General Public License
* along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/
......@@ -83,7 +83,7 @@ import adql.query.operand.function.geometry.RegionFunction;
* <p>To customize the object representation you merely have to extends the appropriate functions of this class.</p>
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 1.4 (08/2015)
* @version 1.4 (04/2017)
*
* @see ADQLParser
*/
......@@ -430,10 +430,6 @@ public class ADQLQueryFactory {
return colRef;
}
/**
* @deprecated since 1.4 ; Former version's mistake: a GROUP BY item is either a regular/delimited column name or an integer, not a qualified column name ; Replaced by {@link #createColRef(adql.parser.IdentifierItems.IdentifierItem)} ; This function is no longer used by ADQLParser.
*/
@Deprecated
public ColumnReference createColRef(final IdentifierItems idItems) throws Exception{
ColumnReference colRef = new ColumnReference(idItems.join("."));
if (colRef != null){
......
......@@ -26,7 +26,7 @@
* If the syntax is not conform to the ADQL definition an error message is printed else it will be the message "Correct syntax".
*
* Author: Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
* Version: 1.4 (03/2017)
* Version: 1.4 (04/2017)
*/
/* ########### */
......@@ -89,7 +89,7 @@ import adql.translator.TranslationException;
* @see ADQLQueryFactory
*
* @author Gr&eacute;gory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
* @version 1.4 (03/2017)
* @version 1.4 (04/2017)
*/
public class ADQLParser {
......@@ -916,11 +916,11 @@ ADQLColumn Column(): {IdentifierItems identifiers;} {
}
}
ColumnReference ColumnRef(): {IdentifierItem identifier = null;}{
identifier=Identifier()
ColumnReference ColumnRef(): {IdentifierItems identifiers = null;}{
identifiers=ColumnName()
{
try{
return queryFactory.createColRef(identifier);
return queryFactory.createColRef(identifiers);
}catch(Exception ex){
throw generateParseException(ex);
}
......
......@@ -43,6 +43,7 @@ public class TestADQLParser {
parser.parseQuery("SELECT * FROM cat ORDER BY 1 DESC;");
// GROUP BY
parser.parseQuery("SELECT * FROM cat GROUP BY oid;");
parser.parseQuery("SELECT * FROM cat GROUP BY cat.oid;");
// JOIN ... USING(...)
parser.parseQuery("SELECT * FROM cat JOIN cat2 USING(oid);");
}catch(Exception e){
......@@ -68,15 +69,6 @@ public class TestADQLParser {
assertEquals(" Encountered \".\". Was expecting one of: <EOF> \",\" \";\" \"ASC\" \"DESC\" ", e.getMessage());
}
try{
// GROUP BY with a qualified column name
parser.parseQuery("SELECT * FROM cat GROUP BY cat.oid;");
fail("A qualified column name is forbidden in GROUP BY! This test should have failed.");
}catch(Exception e){
assertEquals(ParseException.class, e.getClass());
assertEquals(" Encountered \".\". Was expecting one of: <EOF> \",\" \";\" \"HAVING\" \"ORDER BY\" ", e.getMessage());
}
try{
// GROUP BY with a SELECT item index
parser.parseQuery("SELECT * FROM cat GROUP BY 1;");
......
package adql.translator;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
......@@ -9,20 +10,24 @@ import org.junit.Before;
import org.junit.Test;
import adql.db.DBChecker;
import adql.db.DBColumn;
import adql.db.DBTable;
import adql.db.DefaultDBColumn;
import adql.db.DefaultDBTable;
import adql.db.SearchColumnList;
import adql.parser.ADQLParser;
import adql.parser.ParseException;
import adql.parser.SQLServer_ADQLQueryFactory;
import adql.query.ADQLQuery;
import adql.query.from.ADQLJoin;
import adql.query.operand.ADQLColumn;
public class TestSQLServerTranslator {
private List<DBTable> tables = null;
@Before
public void setUp() throws Exception {
public void setUp() throws Exception{
tables = new ArrayList<DBTable>(2);
DefaultDBTable t = new DefaultDBTable("aTable");
t.addColumn(new DefaultDBColumn("id", t));
......@@ -37,19 +42,19 @@ public class TestSQLServerTranslator {
}
@Test
public void testNaturalJoin() {
public void testNaturalJoin(){
final String adqlquery = "SELECT id, name, aColumn, anotherColumn FROM aTable A NATURAL JOIN anotherTable B;";
try{
ADQLQuery query = (new ADQLParser(new DBChecker(tables), new SQLServer_ADQLQueryFactory())).parseQuery(adqlquery);
SQLServerTranslator translator = new SQLServerTranslator();
// Test the FROM part:
assertEquals("\"aTable\" AS A INNER JOIN \"anotherTable\" AS B ON \"aTable\".\"id\"=\"anotherTable\".\"id\" AND \"aTable\".\"name\"=\"anotherTable\".\"name\"", translator.translate(query.getFrom()));
// Test the SELECT part (in order to ensure the usual common columns (due to NATURAL) are actually translated as columns of the first joined table):
assertEquals("SELECT A.\"id\" AS \"id\" , A.\"name\" AS \"name\" , A.\"aColumn\" AS \"aColumn\" , B.\"anotherColumn\" AS \"anotherColumn\"", translator.translate(query.getSelect()));
}catch(ParseException pe){
pe.printStackTrace();
fail("The given ADQL query is completely correct. No error should have occurred while parsing it. (see the console for more details)");
......@@ -60,19 +65,71 @@ public class TestSQLServerTranslator {
}
@Test
public void testJoinWithUSING() {
public void testNaturalJoin2(){
final String adqlquery = "SELECT id, name, aColumn, anotherColumn FROM aTable \"A\" NATURAL JOIN anotherTable B;";
try{
ADQLQuery query = (new ADQLParser(new DBChecker(tables), new SQLServer_ADQLQueryFactory())).parseQuery(adqlquery);
SQLServerTranslator translator = new SQLServerTranslator();
ADQLJoin join = (ADQLJoin)query.getFrom();
try{
StringBuffer buf = new StringBuffer();
// Find duplicated items between the two lists and translate them as ON conditions:
DBColumn rightCol;
SearchColumnList leftList = join.getLeftTable().getDBColumns();
SearchColumnList rightList = join.getRightTable().getDBColumns();
for(DBColumn leftCol : leftList){
// search for at most one column with the same name in the RIGHT list
// and throw an exception is there are several matches:
rightCol = ADQLJoin.findAtMostOneColumn(leftCol.getADQLName(), (byte)0, rightList, false);
// if there is one...
if (rightCol != null){
// ...check there is only one column with this name in the LEFT list,
// and throw an exception if it is not the case:
ADQLJoin.findExactlyOneColumn(leftCol.getADQLName(), (byte)0, leftList, true);
// ...append the corresponding join condition:
if (buf.length() > 0)
buf.append(" AND ");
ADQLColumn col = new ADQLColumn(leftCol.getADQLName());
col.setDBLink(leftCol);
// TODO col.setAdqlTable(adqlTable);
buf.append(translator.translate(col));
buf.append("=");
col = new ADQLColumn(rightCol.getADQLName());
col.setDBLink(rightCol);
buf.append(translator.translate(col));
}
}
System.out.println("ON " + buf.toString());
}catch(Exception uje){
System.err.println("Impossible to resolve the NATURAL JOIN between " + join.getLeftTable().toADQL() + " and " + join.getRightTable().toADQL() + "!");
uje.printStackTrace();
}
}catch(ParseException pe){
pe.printStackTrace();
fail("The given ADQL query is completely correct. No error should have occurred while parsing it. (see the console for more details)");
}
}
@Test
public void testJoinWithUSING(){
final String adqlquery = "SELECT B.id, name, aColumn, anotherColumn FROM aTable A JOIN anotherTable B USING(name);";
try{
ADQLQuery query = (new ADQLParser(new DBChecker(tables), new SQLServer_ADQLQueryFactory())).parseQuery(adqlquery);
SQLServerTranslator translator = new SQLServerTranslator();
// Test the FROM part:
assertEquals("\"aTable\" AS A INNER JOIN \"anotherTable\" AS B ON \"aTable\".\"name\"=\"anotherTable\".\"name\"", translator.translate(query.getFrom()));
// Test the SELECT part (in order to ensure the usual common columns (due to USING) are actually translated as columns of the first joined table):
assertEquals("SELECT B.\"id\" AS \"id\" , A.\"name\" AS \"name\" , A.\"aColumn\" AS \"aColumn\" , B.\"anotherColumn\" AS \"anotherColumn\"", translator.translate(query.getSelect()));
}catch(ParseException pe){
pe.printStackTrace();
fail("The given ADQL query is completely correct. No error should have occurred while parsing it. (see the console for more details)");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment