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
Loading
Loading
Loading
Loading
+35 −7
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@ import adql.db.DBType.DBDatatype;
import adql.db.STCS.Region;
import adql.parser.ParseException;
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.BoxFunction;
import adql.query.operand.function.geometry.CentroidFunction;
@@ -34,20 +36,23 @@ import adql.query.operand.function.geometry.RegionFunction;
 * 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 - 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>:
 * 	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>
 *
 * @author Gr&eacute;gory Mantelet (ARI)
 * @version 2.1 (08/2017)
 * @since 2.1
 * @author Gr&eacute;gory Mantelet (ARI;CDS)
 * @version 1.5 (03/2019)
 * @since 1.4
 */
public class MySQLTranslator extends JDBCTranslator {

@@ -125,6 +130,28 @@ public class MySQLTranslator extends JDBCTranslator {
			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                                                    * */
@@ -145,7 +172,8 @@ public class MySQLTranslator extends JDBCTranslator {
		if (params != null && params.length > 0){
			try{
				lengthParam = Integer.parseInt(params[0]);
			}catch(NumberFormatException nfe){}
			}catch(NumberFormatException nfe){
			}
		}

		// SMALLINT
+58 −20
Original line number Diff line number Diff line
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 adql.db.DBColumn;
@@ -17,6 +37,8 @@ import adql.query.from.ADQLJoin;
import adql.query.from.ADQLTable;
import adql.query.from.FromContent;
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.geometry.AreaFunction;
import adql.query.operand.function.geometry.BoxFunction;
@@ -32,11 +54,12 @@ import adql.query.operand.function.geometry.PolygonFunction;
import adql.query.operand.function.geometry.RegionFunction;

/**
 * <p>MS SQL Server translator.</p>
 * MS SQL Server translator.
 *
 * <p><b>Important:</b>
 * 	This translator works correctly ONLY IF {@link SQLServer_ADQLQueryFactory} has been used
 * 	to create any ADQL query this translator is asked to translate.
 * 	This translator works correctly ONLY IF {@link SQLServer_ADQLQueryFactory}
 * 	has been used to create any ADQL query this translator is asked to
 * 	translate.
 * </p>
 *
 * 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;
 *      {@link #convertTypeToDB(DBType)}).
 *
 * <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>
 *
 * @author Gr&eacute;gory Mantelet (ARI)
 * @version 1.4 (09/2017)
 * @author Gr&eacute;gory Mantelet (ARI;CDS)
 * @version 1.5 (03/2019)
 * @since 1.4
 *
 * @see SQLServer_ADQLQueryFactory
@@ -151,6 +175,19 @@ public class SQLServerTranslator extends JDBCTranslator {
		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
	public String translate(final ADQLJoin join) throws TranslationException{
		StringBuffer sql = new StringBuffer(translate(join.getLeftTable()));
@@ -361,7 +398,8 @@ public class SQLServerTranslator extends JDBCTranslator {
		if (params != null && params.length > 0){
			try{
				lengthParam = Integer.parseInt(params[0]);
			}catch(NumberFormatException nfe){}
			}catch(NumberFormatException nfe){
			}
		}

		// SMALLINT
+36 −0
Original line number Diff line number Diff line
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)");
		}
	}

}
+22 −0
Original line number Diff line number Diff line
@@ -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)");
		}
	}

}