diff --git a/src/adql/translator/SQLServerTranslator.java b/src/adql/translator/SQLServerTranslator.java index 89d6629d1e88648af600e81d64ea9555738807cb..bae30066b5033da392ce514dbb05453595f28a01 100644 --- a/src/adql/translator/SQLServerTranslator.java +++ b/src/adql/translator/SQLServerTranslator.java @@ -1,44 +1,21 @@ 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 2016-2017 - Astronomisches Rechen Institut (ARI) - */ - -import java.util.ArrayList; import java.util.Iterator; -import adql.db.DBChecker; import adql.db.DBColumn; -import adql.db.DBTable; import adql.db.DBType; import adql.db.DBType.DBDatatype; -import adql.db.DefaultDBColumn; -import adql.db.DefaultDBTable; import adql.db.STCS.Region; import adql.db.SearchColumnList; import adql.db.exception.UnresolvedJoinException; -import adql.parser.ADQLParser; import adql.parser.ParseException; import adql.parser.SQLServer_ADQLQueryFactory; import adql.query.ADQLQuery; import adql.query.ClauseSelect; import adql.query.IdentifierField; import adql.query.from.ADQLJoin; +import adql.query.from.ADQLTable; +import adql.query.from.FromContent; import adql.query.operand.ADQLColumn; import adql.query.operand.function.MathFunction; import adql.query.operand.function.geometry.AreaFunction; @@ -83,30 +60,6 @@ import adql.query.operand.function.geometry.RegionFunction; */ public class SQLServerTranslator extends JDBCTranslator { - /* TODO Temporary MAIN function. - * TO REMOVE for the release. */ - public final static void main(final String[] args) throws Exception{ - final String adqlquery = "SELECT id, name, aColumn, anotherColumn FROM aTable A NATURAL JOIN anotherTable B;"; - System.out.println("ADQL Query:\n" + adqlquery); - - ArrayList<DBTable> tables = new ArrayList<DBTable>(2); - DefaultDBTable t = new DefaultDBTable("aTable"); - t.addColumn(new DefaultDBColumn("id", t)); - t.addColumn(new DefaultDBColumn("name", t)); - t.addColumn(new DefaultDBColumn("aColumn", t)); - tables.add(t); - t = new DefaultDBTable("anotherTable"); - t.addColumn(new DefaultDBColumn("id", t)); - t.addColumn(new DefaultDBColumn("name", t)); - t.addColumn(new DefaultDBColumn("anotherColumn", t)); - tables.add(t); - - ADQLQuery query = (new ADQLParser(new DBChecker(tables), new SQLServer_ADQLQueryFactory())).parseQuery(adqlquery); - - SQLServerTranslator translator = new SQLServerTranslator(); - System.out.println("\nIn MS SQL Server:\n" + translator.translate(query)); - } - /** <p>Indicate the case sensitivity to apply to each SQL identifier (only SCHEMA, TABLE and COLUMN).</p> * * <p><i>Note: @@ -225,9 +178,9 @@ public class SQLServerTranslator extends JDBCTranslator { // ...append the corresponding join condition: if (buf.length() > 0) buf.append(" AND "); - buf.append(getQualifiedTableName(leftCol.getTable())).append('.').append(getColumnName(leftCol)); + buf.append(translate(generateJoinColumn(join.getLeftTable(), leftCol, new ADQLColumn(leftCol.getADQLName())))); buf.append("="); - buf.append(getQualifiedTableName(rightCol.getTable())).append('.').append(getColumnName(rightCol)); + buf.append(translate(generateJoinColumn(join.getRightTable(), rightCol, new ADQLColumn(rightCol.getADQLName())))); } } @@ -257,9 +210,9 @@ public class SQLServerTranslator extends JDBCTranslator { // append the corresponding join condition: if (buf.length() > 0) buf.append(" AND "); - buf.append(getQualifiedTableName(leftCol.getTable())).append('.').append(getColumnName(leftCol)); + buf.append(translate(generateJoinColumn(join.getLeftTable(), leftCol, usingCol))); buf.append("="); - buf.append(getQualifiedTableName(rightCol.getTable())).append('.').append(getColumnName(rightCol)); + buf.append(translate(generateJoinColumn(join.getRightTable(), rightCol, usingCol))); } sql.append("ON ").append(buf.toString()); @@ -274,6 +227,32 @@ public class SQLServerTranslator extends JDBCTranslator { return sql.toString(); } + /** + * Generate an ADQL column of the given table and with the given metadata. + * + * @param table Parent table of the column to generate. + * @param colMeta DB metadata of the column to generate. + * @param joinedColumn The joined column (i.e. the ADQL column listed in a + * USING) from which the generated column should + * derive. + * <i>If NULL, an {@link ADQLColumn} instance will be + * created from scratch using the ADQL name of the + * given DB metadata.</i> + * + * @return The generated column. + */ + protected ADQLColumn generateJoinColumn(final FromContent table, final DBColumn colMeta, final ADQLColumn joinedColumn){ + ADQLColumn newCol = (joinedColumn == null ? new ADQLColumn(colMeta.getADQLName()) : new ADQLColumn(joinedColumn)); + if (table != null){ + if (table instanceof ADQLTable) + newCol.setAdqlTable((ADQLTable)table); + else + newCol.setAdqlTable(new ADQLTable(table.getName())); + } + newCol.setDBLink(colMeta); + return newCol; + } + @Override public String translate(final ExtractCoord extractCoord) throws TranslationException{ return getDefaultADQLFunction(extractCoord); diff --git a/test/adql/translator/TestSQLServerTranslator.java b/test/adql/translator/TestSQLServerTranslator.java index 4ddd1bddbd033abd8c6818d97554de5e737f52b3..49685a7d10562c671d638b31c1561d30ed7754e8 100644 --- a/test/adql/translator/TestSQLServerTranslator.java +++ b/test/adql/translator/TestSQLServerTranslator.java @@ -10,17 +10,13 @@ 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 { @@ -50,7 +46,7 @@ public class TestSQLServerTranslator { 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())); + assertEquals("\"aTable\" AS A INNER JOIN \"anotherTable\" AS B ON A.\"id\"=B.\"id\" AND A.\"name\"=B.\"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())); @@ -64,58 +60,6 @@ public class TestSQLServerTranslator { } } - @Test - 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);"; @@ -125,7 +69,7 @@ public class TestSQLServerTranslator { 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())); + assertEquals("\"aTable\" AS A INNER JOIN \"anotherTable\" AS B ON A.\"name\"=B.\"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()));