Skip to content
Snippets Groups Projects
Commit e136017d authored by Grégory Mantelet's avatar Grégory Mantelet
Browse files

[ADQL] Fix the SQL translation of concatenations for MySQL and MS-SQLServer.

As @vforchi said:

> The ANSI standard `||` is supported only by Oracle and Postgres: MySQL uses
> `CONCAT` and SQLServer uses `+`.

_This commit resolves the issue #70 ._
parent 1a1c8a3a
No related branches found
No related tags found
No related merge requests found
...@@ -5,6 +5,8 @@ import adql.db.DBType.DBDatatype; ...@@ -5,6 +5,8 @@ import adql.db.DBType.DBDatatype;
import adql.db.STCS.Region; import adql.db.STCS.Region;
import adql.parser.ParseException; import adql.parser.ParseException;
import adql.query.IdentifierField; import adql.query.IdentifierField;
import adql.query.operand.ADQLOperand;
import adql.query.operand.Concatenation;
import adql.query.operand.function.geometry.AreaFunction; import adql.query.operand.function.geometry.AreaFunction;
import adql.query.operand.function.geometry.BoxFunction; import adql.query.operand.function.geometry.BoxFunction;
import adql.query.operand.function.geometry.CentroidFunction; import adql.query.operand.function.geometry.CentroidFunction;
...@@ -34,20 +36,23 @@ import adql.query.operand.function.geometry.RegionFunction; ...@@ -34,20 +36,23 @@ import adql.query.operand.function.geometry.RegionFunction;
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>. * along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>.
* *
* Copyright 2017 - Astronomisches Rechen Institut (ARI) * Copyright 2017-2019 - Astronomisches Rechen Institut (ARI),
* UDS/Centre de Données astronomiques de Strasbourg (CDS)
*/ */
/** /**
* <p>Translates all ADQL objects into an SQL interrogation query designed for MySQL.</p> * Translates all ADQL objects into an SQL interrogation query designed for
* MySQL.
* *
* <p><i><b>Important</b>: * <p><i><b>Important</b>:
* The geometrical functions are translated exactly as in ADQL. * The geometrical functions are translated exactly as in ADQL.
* You will probably need to extend this translator to correctly manage the geometrical functions. * You will probably need to extend this translator to correctly manage the
* geometrical functions.
* </i></p> * </i></p>
* *
* @author Gr&eacute;gory Mantelet (ARI) * @author Gr&eacute;gory Mantelet (ARI;CDS)
* @version 2.1 (08/2017) * @version 1.5 (03/2019)
* @since 2.1 * @since 1.4
*/ */
public class MySQLTranslator extends JDBCTranslator { public class MySQLTranslator extends JDBCTranslator {
...@@ -125,6 +130,28 @@ public class MySQLTranslator extends JDBCTranslator { ...@@ -125,6 +130,28 @@ public class MySQLTranslator extends JDBCTranslator {
return str.append(id); return str.append(id);
} }
/* ********************************************************************** */
/* * * */
/* * GENERAL TRANSLATIONS * */
/* * * */
/* ********************************************************************** */
@Override
public String translate(Concatenation concat) throws TranslationException{
StringBuffer translated = new StringBuffer();
for(ADQLOperand op : concat){
if (translated.length() == 0)
translated.append("CONCAT(");
else
translated.append(", ");
translated.append(translate(op));
}
translated.append(")");
return translated.toString();
}
/* ********************************************************************** */ /* ********************************************************************** */
/* * * */ /* * * */
/* * TYPE MANAGEMENT * */ /* * TYPE MANAGEMENT * */
...@@ -145,7 +172,8 @@ public class MySQLTranslator extends JDBCTranslator { ...@@ -145,7 +172,8 @@ public class MySQLTranslator extends JDBCTranslator {
if (params != null && params.length > 0){ if (params != null && params.length > 0){
try{ try{
lengthParam = Integer.parseInt(params[0]); lengthParam = Integer.parseInt(params[0]);
}catch(NumberFormatException nfe){} }catch(NumberFormatException nfe){
}
} }
// SMALLINT // SMALLINT
......
package adql.translator; package adql.translator;
/*
* This file is part of ADQLLibrary.
*
* ADQLLibrary is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ADQLLibrary is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* 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 2017-2019 - Astronomisches Rechen Institut (ARI),
* UDS/Centre de Données astronomiques de Strasbourg (CDS)
*/
import java.util.Iterator; import java.util.Iterator;
import adql.db.DBColumn; import adql.db.DBColumn;
...@@ -17,6 +37,8 @@ import adql.query.from.ADQLJoin; ...@@ -17,6 +37,8 @@ import adql.query.from.ADQLJoin;
import adql.query.from.ADQLTable; import adql.query.from.ADQLTable;
import adql.query.from.FromContent; import adql.query.from.FromContent;
import adql.query.operand.ADQLColumn; import adql.query.operand.ADQLColumn;
import adql.query.operand.ADQLOperand;
import adql.query.operand.Concatenation;
import adql.query.operand.function.MathFunction; import adql.query.operand.function.MathFunction;
import adql.query.operand.function.geometry.AreaFunction; import adql.query.operand.function.geometry.AreaFunction;
import adql.query.operand.function.geometry.BoxFunction; import adql.query.operand.function.geometry.BoxFunction;
...@@ -32,11 +54,12 @@ import adql.query.operand.function.geometry.PolygonFunction; ...@@ -32,11 +54,12 @@ import adql.query.operand.function.geometry.PolygonFunction;
import adql.query.operand.function.geometry.RegionFunction; import adql.query.operand.function.geometry.RegionFunction;
/** /**
* <p>MS SQL Server translator.</p> * MS SQL Server translator.
* *
* <p><b>Important:</b> * <p><b>Important:</b>
* This translator works correctly ONLY IF {@link SQLServer_ADQLQueryFactory} has been used * This translator works correctly ONLY IF {@link SQLServer_ADQLQueryFactory}
* to create any ADQL query this translator is asked to translate. * has been used to create any ADQL query this translator is asked to
* translate.
* </p> * </p>
* *
* TODO See how case sensitivity is supported by MS SQL Server and modify this translator accordingly. * TODO See how case sensitivity is supported by MS SQL Server and modify this translator accordingly.
...@@ -49,11 +72,12 @@ import adql.query.operand.function.geometry.RegionFunction; ...@@ -49,11 +72,12 @@ import adql.query.operand.function.geometry.RegionFunction;
* {@link #convertTypeToDB(DBType)}). * {@link #convertTypeToDB(DBType)}).
* *
* <p><i><b>Important note:</b> * <p><i><b>Important note:</b>
* Geometrical functions are not translated ; the translation returned for them is their ADQL expression. * Geometrical functions are not translated ; the translation returned for them
* is their ADQL expression.
* </i></p> * </i></p>
* *
* @author Gr&eacute;gory Mantelet (ARI) * @author Gr&eacute;gory Mantelet (ARI;CDS)
* @version 1.4 (09/2017) * @version 1.5 (03/2019)
* @since 1.4 * @since 1.4
* *
* @see SQLServer_ADQLQueryFactory * @see SQLServer_ADQLQueryFactory
...@@ -151,6 +175,19 @@ public class SQLServerTranslator extends JDBCTranslator { ...@@ -151,6 +175,19 @@ public class SQLServerTranslator extends JDBCTranslator {
return sql; return sql;
} }
@Override
public String translate(Concatenation concat) throws TranslationException{
StringBuffer translated = new StringBuffer();
for(ADQLOperand op : concat){
if (translated.length() > 0)
translated.append(" + ");
translated.append(translate(op));
}
return translated.toString();
}
@Override @Override
public String translate(final ADQLJoin join) throws TranslationException{ public String translate(final ADQLJoin join) throws TranslationException{
StringBuffer sql = new StringBuffer(translate(join.getLeftTable())); StringBuffer sql = new StringBuffer(translate(join.getLeftTable()));
...@@ -361,7 +398,8 @@ public class SQLServerTranslator extends JDBCTranslator { ...@@ -361,7 +398,8 @@ public class SQLServerTranslator extends JDBCTranslator {
if (params != null && params.length > 0){ if (params != null && params.length > 0){
try{ try{
lengthParam = Integer.parseInt(params[0]); lengthParam = Integer.parseInt(params[0]);
}catch(NumberFormatException nfe){} }catch(NumberFormatException nfe){
}
} }
// SMALLINT // SMALLINT
......
package adql.translator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
import adql.parser.ADQLParser;
import adql.parser.ParseException;
import adql.query.ADQLQuery;
public class TestMySQLTranslator {
@Test
public void testConcat(){
try{
MySQLTranslator translator = new MySQLTranslator();
// Test with an easy translation:
ADQLQuery query = (new ADQLParser()).parseQuery("SELECT 'abc' || ' ' || 'def' FROM aTable");
assertEquals("SELECT CONCAT('abc', ' ', 'def') AS `concat`", translator.translate(query.getSelect()));
// Test with an easy translation:
query = (new ADQLParser()).parseQuery("SELECT 'a||b||c' || ' ' || 'd+e|f' FROM aTable");
assertEquals("SELECT CONCAT('a||b||c', ' ', 'd+e|f') AS `concat`", 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)");
}catch(TranslationException te){
te.printStackTrace();
fail("No error was expected from this translation. (see the console for more details)");
}
}
}
...@@ -83,4 +83,26 @@ public class TestSQLServerTranslator { ...@@ -83,4 +83,26 @@ public class TestSQLServerTranslator {
} }
} }
@Test
public void testConcat(){
try{
SQLServerTranslator translator = new SQLServerTranslator();
// Test with an easy translation:
ADQLQuery query = (new ADQLParser(new SQLServer_ADQLQueryFactory())).parseQuery("SELECT 'abc' || ' ' || 'def' FROM aTable");
assertEquals("SELECT 'abc' + ' ' + 'def' AS \"concat\"", translator.translate(query.getSelect()));
// Test with an easy translation:
query = (new ADQLParser(new SQLServer_ADQLQueryFactory())).parseQuery("SELECT 'a||b||c' || ' ' || 'd+e|f' FROM aTable");
assertEquals("SELECT 'a||b||c' + ' ' + 'd+e|f' AS \"concat\"", 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)");
}catch(TranslationException te){
te.printStackTrace();
fail("No error was expected from this translation. (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