Skip to content
Snippets Groups Projects
Commit 13a2dc54 authored by gmantele's avatar gmantele
Browse files

[ADQL] Fix a Big Bug reported by M.Taylor and M.Demleitner: in ORDER BY, GROUP...

[ADQL] Fix a Big Bug reported by M.Taylor and M.Demleitner: in ORDER BY, GROUP BY and USING only regular and delimited identifiers are accepted, not qualified column names.
For instance: "SELECT table.column_name FROM table ORDER BY table.column_name" is wrong. We should instead write:
"SELECT table.column_name FROM table ORDER BY column_name".
"SELECT table.column_name AS mycol FROM table ORDER BY mycol" is also correct.
Of course, for ORDER BY and GROUP BY, it is still possible to reference a column using its index in the SELECT clause.
For instance: "SELECT table.column_name FROM table ORDER BY 1".
parent 84ede4bf
No related branches found
No related tags found
No related merge requests found
......@@ -67,7 +67,7 @@ import adql.translator.TranslationException;
* @see ADQLQueryFactory
*
* @author Grégory Mantelet (CDS;ARI) - gmantele@ari.uni-heidelberg.de
* @version 1.4 (06/2015)
* @version 1.4 (08/2015)
*/
public class ADQLParser implements ADQLParserConstants {
......@@ -1074,12 +1074,12 @@ public class ADQLParser implements ADQLParserConstants {
final public ColumnReference ColumnRef() throws ParseException{
trace_call("ColumnRef");
try{
IdentifierItems identifiers = null;
IdentifierItem identifier = null;
Token ind = null;
switch((jj_ntk == -1) ? jj_ntk() : jj_ntk){
case DELIMITED_IDENTIFIER:
case REGULAR_IDENTIFIER:
identifiers = ColumnName();
identifier = Identifier();
break;
case UNSIGNED_INTEGER:
ind = jj_consume_token(UNSIGNED_INTEGER);
......@@ -1091,8 +1091,8 @@ public class ADQLParser implements ADQLParserConstants {
}
try{
ColumnReference colRef = null;
if (identifiers != null)
colRef = queryFactory.createColRef(identifiers);
if (identifier != null)
colRef = queryFactory.createColRef(identifier);
else
colRef = queryFactory.createColRef(Integer.parseInt(ind.image), new TextPosition(ind));
{
......@@ -1114,12 +1114,12 @@ public class ADQLParser implements ADQLParserConstants {
final public ADQLOrder OrderItem() throws ParseException{
trace_call("OrderItem");
try{
IdentifierItems identifiers = null;
IdentifierItem identifier = null;
Token ind = null, desc = null;
switch((jj_ntk == -1) ? jj_ntk() : jj_ntk){
case DELIMITED_IDENTIFIER:
case REGULAR_IDENTIFIER:
identifiers = ColumnName();
identifier = Identifier();
break;
case UNSIGNED_INTEGER:
ind = jj_consume_token(UNSIGNED_INTEGER);
......@@ -1151,9 +1151,9 @@ public class ADQLParser implements ADQLParserConstants {
}
try{
ADQLOrder order = null;
if (identifiers != null){
order = queryFactory.createOrder(identifiers, desc != null);
order.setPosition(identifiers.getPosition());
if (identifier != null){
order = queryFactory.createOrder(identifier, desc != null);
order.setPosition(identifier.position);
}else{
order = queryFactory.createOrder(Integer.parseInt(ind.image), desc != null);
order.setPosition(new TextPosition(ind));
......
......@@ -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 (06/2015)
* @version 1.4 (08/2015)
*
* @see ADQLParser
*/
......@@ -403,6 +403,17 @@ public class ADQLQueryFactory {
return order;
}
public ADQLOrder createOrder(final IdentifierItem colName, final boolean desc) throws Exception{
ADQLOrder order = new ADQLOrder(colName.identifier, desc);
if (order != null)
order.setCaseSensitive(colName.caseSensitivity);
return order;
}
/**
* @deprecated since 1.4 ; Former version's mistake: an ORDER BY item is either a regular/delimited column name or an integer, not a qualified column name ; Replaced by {@link #createOrder(Identifier, boolean)} ; This function is no longer used by ADQLParser.
*/
@Deprecated
public ADQLOrder createOrder(final IdentifierItems idItems, final boolean desc) throws Exception{
ADQLOrder order = new ADQLOrder(idItems.join("."), desc);
if (order != null)
......@@ -410,6 +421,19 @@ public class ADQLQueryFactory {
return order;
}
public ColumnReference createColRef(final IdentifierItem idItem) throws Exception{
ColumnReference colRef = new ColumnReference(idItem.identifier);
if (colRef != null){
colRef.setPosition(idItem.position);
colRef.setCaseSensitive(idItem.caseSensitivity);
}
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(Identifier)} ; 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 (06/2015)
* Version: 1.4 (08/2015)
*/
/* ########### */
......@@ -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 (06/2015)
* @version 1.4 (08/2015)
*/
public class ADQLParser {
......@@ -918,13 +918,13 @@ ADQLColumn Column(): {IdentifierItems identifiers;} {
}
}
ColumnReference ColumnRef(): {IdentifierItems identifiers = null; Token ind = null;}{
( identifiers=ColumnName() | ind=<UNSIGNED_INTEGER> )
ColumnReference ColumnRef(): {IdentifierItem identifier = null; Token ind = null;}{
( identifier=Identifier() | ind=<UNSIGNED_INTEGER> )
{
try{
ColumnReference colRef = null;
if (identifiers != null)
colRef = queryFactory.createColRef(identifiers);
if (identifier != null)
colRef = queryFactory.createColRef(identifier);
else
colRef = queryFactory.createColRef(Integer.parseInt(ind.image), new TextPosition(ind));
return colRef;
......@@ -934,14 +934,14 @@ ColumnReference ColumnRef(): {IdentifierItems identifiers = null; Token ind = nu
}
}
ADQLOrder OrderItem(): {IdentifierItems identifiers = null; Token ind = null, desc = null;}{
(identifiers=ColumnName() | ind=<UNSIGNED_INTEGER>) (<ASC> | desc=<DESC>)?
ADQLOrder OrderItem(): {IdentifierItem identifier = null; Token ind = null, desc = null;}{
(identifier=Identifier() | ind=<UNSIGNED_INTEGER>) (<ASC> | desc=<DESC>)?
{
try{
ADQLOrder order = null;
if (identifiers != null){
order = queryFactory.createOrder(identifiers, desc!=null);
order.setPosition(identifiers.getPosition());
if (identifier != null){
order = queryFactory.createOrder(identifier, desc!=null);
order.setPosition(identifier.position);
}else{
order = queryFactory.createOrder(Integer.parseInt(ind.image), desc!=null);
order.setPosition(new TextPosition(ind));
......
......@@ -27,6 +27,73 @@ public class TestADQLParser {
@After
public void tearDown() throws Exception{}
@Test
public void testColumnReference(){
ADQLParser parser = new ADQLParser();
try{
// ORDER BY
parser.parseQuery("SELECT * FROM cat ORDER BY oid;");
parser.parseQuery("SELECT * FROM cat ORDER BY oid ASC;");
parser.parseQuery("SELECT * FROM cat ORDER BY oid DESC;");
parser.parseQuery("SELECT * FROM cat ORDER BY 1;");
parser.parseQuery("SELECT * FROM cat ORDER BY 1 ASC;");
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 1;");
// JOIN ... USING(...)
parser.parseQuery("SELECT * FROM cat JOIN cat2 USING(oid);");
}catch(Exception e){
e.printStackTrace(System.err);
fail("These ADQL queries are strictly correct! No error should have occured. (see stdout for more details)");
}
try{
// ORDER BY
parser.parseQuery("SELECT * FROM cat ORDER BY cat.oid;");
fail("A qualified column name is forbidden in ORDER BY! This test should have failed.");
}catch(Exception e){
assertEquals(ParseException.class, e.getClass());
assertEquals(" Encountered \".\". Was expecting one of: <EOF> \",\" \";\" \"ASC\" \"DESC\" ", e.getMessage());
}
// Query reported as in error before the bug correction:
try{
parser.parseQuery("SELECT TOP 10 browndwarfs.cat.jmag FROM browndwarfs.cat ORDER BY browndwarfs.cat.jmag");
fail("A qualified column name is forbidden in ORDER BY! This test should have failed.");
}catch(Exception e){
assertEquals(ParseException.class, e.getClass());
assertEquals(" Encountered \".\". Was expecting one of: <EOF> \",\" \";\" \"ASC\" \"DESC\" ", e.getMessage());
}
try{
// GROUP BY
parser.parseQuery("SELECT * FROM cat GROUP BY cat.oid;");
fail("A qualified column name is forbidden in ORDER 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{
// JOIN ... USING(...)
parser.parseQuery("SELECT * FROM cat JOIN cat2 USING(cat.oid);");
fail("A qualified column name is forbidden in USING(...)! This test should have failed.");
}catch(Exception e){
assertEquals(ParseException.class, e.getClass());
assertEquals(" Encountered \".\". Was expecting one of: \")\" \",\" ", e.getMessage());
}
try{
// JOIN ... USING(...)
parser.parseQuery("SELECT * FROM cat JOIN cat2 USING(1);");
fail("A column index is forbidden in USING(...)! This test should have failed.");
}catch(Exception e){
assertEquals(ParseException.class, e.getClass());
assertEquals(" Encountered \"1\". Was expecting one of: \"\\\"\" <REGULAR_IDENTIFIER> ", e.getMessage());
}
}
@Test
public void testDelimitedIdentifiersWithDot(){
ADQLParser parser = new ADQLParser();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment