diff --git a/src/adql/parser/feature/FeatureSet.java b/src/adql/parser/feature/FeatureSet.java index 04b7a61544de50c57fe929e6b692b1ead2477e85..9beafbc0b2abbb50b0182ca4a62919a21efd4c80 100644 --- a/src/adql/parser/feature/FeatureSet.java +++ b/src/adql/parser/feature/FeatureSet.java @@ -28,6 +28,7 @@ import java.util.NoSuchElementException; import java.util.Set; import adql.db.FunctionDef; +import adql.query.constraint.ComparisonOperator; import adql.query.operand.function.geometry.AreaFunction; import adql.query.operand.function.geometry.BoxFunction; import adql.query.operand.function.geometry.CentroidFunction; @@ -574,9 +575,7 @@ public class FeatureSet implements Iterable<LanguageFeature> { * * ********************************************************************** */ - /*public static final LanguageFeature ILIKE = new LanguageFeature(FeatureType.ADQL_STRING, "ILIKE"); // TODO ILIKE - - public static final LanguageFeature UNION = new LanguageFeature(FeatureType.ADQL_SETS, "UNION"); // TODO UNION + /*public static final LanguageFeature UNION = new LanguageFeature(FeatureType.ADQL_SETS, "UNION"); // TODO UNION public static final LanguageFeature EXCEPT = new LanguageFeature(FeatureType.ADQL_SETS, "EXCEPT"); // TODO EXCEPT public static final LanguageFeature INTERSECT = new LanguageFeature(FeatureType.ADQL_SETS, "INTERSECT"); // TODO INTERSECT @@ -603,7 +602,7 @@ public class FeatureSet implements Iterable<LanguageFeature> { * <p><i><b>Important note:</b> * All of them must be optional and must have a type. * </i></p> */ - static LanguageFeature[] availableFeatures = new LanguageFeature[]{ LowerFunction.FEATURE, AreaFunction.FEATURE, BoxFunction.FEATURE, CentroidFunction.FEATURE, CircleFunction.FEATURE, ContainsFunction.FEATURE, ExtractCoord.FEATURE_COORD1, ExtractCoord.FEATURE_COORD2, ExtractCoordSys.FEATURE, DistanceFunction.FEATURE, IntersectsFunction.FEATURE, PointFunction.FEATURE, PolygonFunction.FEATURE, RegionFunction.FEATURE }; + static LanguageFeature[] availableFeatures = new LanguageFeature[]{ ComparisonOperator.ILIKE.getFeatureDescription(), LowerFunction.FEATURE, AreaFunction.FEATURE, BoxFunction.FEATURE, CentroidFunction.FEATURE, CircleFunction.FEATURE, ContainsFunction.FEATURE, ExtractCoord.FEATURE_COORD1, ExtractCoord.FEATURE_COORD2, ExtractCoordSys.FEATURE, DistanceFunction.FEATURE, IntersectsFunction.FEATURE, PointFunction.FEATURE, PolygonFunction.FEATURE, RegionFunction.FEATURE }; /** * List all available language features. diff --git a/src/adql/parser/grammar/adqlGrammar201.jj b/src/adql/parser/grammar/adqlGrammar201.jj index 5276df35bc098592cb8aac977829611e4e9e0936..778e8a51ff45f402f1e082d13a61d4cafe203f2a 100644 --- a/src/adql/parser/grammar/adqlGrammar201.jj +++ b/src/adql/parser/grammar/adqlGrammar201.jj @@ -284,6 +284,7 @@ TOKEN : { | < NULL: "NULL" > { matchedToken.adqlReserved = true; } | < BETWEEN: "BETWEEN" > { matchedToken.adqlReserved = true; } | < LIKE: "LIKE" > { matchedToken.adqlReserved = true; } +| < ILIKE: "ILIKE" > { matchedToken.adqlReserved = true; } } TOKEN : { < IN: "IN" > { matchedToken.adqlReserved = matchedToken.isFunctionName = true; } @@ -1069,6 +1070,14 @@ ADQLConstraint Predicate(): {ADQLQuery q=null; ADQLColumn column=null; ADQLOpera return comp; } ) + // ilike_predicate + | LOOKAHEAD(StringExpression() [<NOT>] <ILIKE>) (strExpr1=StringExpression() [notToken=<NOT>] <ILIKE> strExpr2=StringExpression() + { + Comparison comp = queryFactory.createComparison(strExpr1, (notToken==null)?ComparisonOperator.ILIKE:ComparisonOperator.NOTILIKE, strExpr2); + comp.setPosition(new TextPosition(strExpr1.getPosition(), strExpr2.getPosition())); + return comp; + } + ) | (op=ValueExpression() (// comparison_predicate (constraint=ComparisonEnd(op)) diff --git a/src/adql/query/constraint/ComparisonOperator.java b/src/adql/query/constraint/ComparisonOperator.java index 4dc5c1776309b5dada1a1501fee8ad6782df04c7..02a28144bf8d6156ff680400ddb7490bc0eaa31b 100644 --- a/src/adql/query/constraint/ComparisonOperator.java +++ b/src/adql/query/constraint/ComparisonOperator.java @@ -26,12 +26,23 @@ import adql.query.operand.function.SQLFunction; * Gathers all comparison operators (numeric or not). * * @author Grégory Mantelet (CDS) - * @version 2.0 (07/2019) + * @version 2.0 (08/2019) * * @see Comparison */ public enum ComparisonOperator { - EQUAL, NOT_EQUAL, LESS_THAN, LESS_OR_EQUAL, GREATER_THAN, GREATER_OR_EQUAL, LIKE, NOTLIKE; + EQUAL, + NOT_EQUAL, + LESS_THAN, + LESS_OR_EQUAL, + GREATER_THAN, + GREATER_OR_EQUAL, + LIKE, + /** @since 2.0 */ + ILIKE, + NOTLIKE, + /** @since 2.0 */ + NOTILIKE; /** Description of the ADQL Feature based on this type. * @since 2.0 */ @@ -39,7 +50,10 @@ public enum ComparisonOperator { /** @since 2.0 */ private ComparisonOperator() { - FEATURE = new LanguageFeature(null, this.name(), false); + if (name().endsWith("ILIKE")) + FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_STRING, "ILIKE", true, "Perform a case-insensitive comparison between its string operands."); + else + FEATURE = new LanguageFeature(null, this.name(), false); } /** @@ -75,8 +89,12 @@ public enum ComparisonOperator { return GREATER_OR_EQUAL; else if (str.equalsIgnoreCase("LIKE")) return LIKE; + else if (str.equalsIgnoreCase("ILIKE")) + return ILIKE; else if (str.equalsIgnoreCase("NOT LIKE")) return NOTLIKE; + else if (str.equalsIgnoreCase("NOT ILIKE")) + return NOTILIKE; else throw new UnsupportedOperationException("Comparison operator unknown: \"" + str + "\" !"); } @@ -97,8 +115,12 @@ public enum ComparisonOperator { return ">="; case LIKE: return "LIKE"; + case ILIKE: + return "ILIKE"; case NOTLIKE: return "NOT LIKE"; + case NOTILIKE: + return "NOT ILIKE"; default: return "???"; } diff --git a/src/adql/translator/ADQLTranslator.java b/src/adql/translator/ADQLTranslator.java index 1174f08378a043cc8306ad4938c4972c4734c03d..66d22c6f641cde3d6d397d87e1ec07f6a8b369c7 100644 --- a/src/adql/translator/ADQLTranslator.java +++ b/src/adql/translator/ADQLTranslator.java @@ -2,21 +2,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 2012,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * + * Copyright 2012-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -65,13 +65,14 @@ import adql.query.operand.function.geometry.IntersectsFunction; import adql.query.operand.function.geometry.PointFunction; import adql.query.operand.function.geometry.PolygonFunction; import adql.query.operand.function.geometry.RegionFunction; +import adql.query.operand.function.string.LowerFunction; /** * Translates ADQL objects into any language (i.e. SQL). - * + * * @author Grégory Mantelet (CDS) - * @version 01/2012 - * + * @version 2.0 (08/2019) + * * @see PostgreSQLTranslator */ public interface ADQLTranslator { @@ -143,6 +144,9 @@ public interface ADQLTranslator { public String translate(UserDefinedFunction fct) throws TranslationException; + /** @since 2.0 */ + public String translate(LowerFunction fct) throws TranslationException; + /* ***** GEOMETRICAL FUNCTIONS ***** */ public String translate(GeometryFunction fct) throws TranslationException; diff --git a/src/adql/translator/JDBCTranslator.java b/src/adql/translator/JDBCTranslator.java index 0baa58cea6db57f703636f0015cf29b5a955f07e..7cf11859431b251d9ef332a885f1bd33d3aa6a79 100644 --- a/src/adql/translator/JDBCTranslator.java +++ b/src/adql/translator/JDBCTranslator.java @@ -77,6 +77,7 @@ import adql.query.operand.function.geometry.IntersectsFunction; import adql.query.operand.function.geometry.PointFunction; import adql.query.operand.function.geometry.PolygonFunction; import adql.query.operand.function.geometry.RegionFunction; +import adql.query.operand.function.string.LowerFunction; /** * Implementation of {@link ADQLTranslator} which translates ADQL queries in @@ -89,7 +90,7 @@ import adql.query.operand.function.geometry.RegionFunction; * {@link MySQLTranslator} and {@link SQLServerTranslator} are doing. * </p> * - * <p><i>Note: + * <p><i><b>Note:</b> * Its default implementation of the SQL syntax has been inspired by the * PostgreSQL one. However, it should work also with other DBMS, although some * translations might be needed (as it is has been done for PostgreSQL about @@ -147,8 +148,8 @@ import adql.query.operand.function.geometry.RegionFunction; * translating differently: LOG, LOG10, RAND and TRUNC. * </p> * - * <p><i>Note: - * Geometrical regions and types have not been managed here. They stay abstract + * <p><i><b>Note:</b> + * Geometric regions and types have not been managed here. They stay abstract * because it is obviously impossible to have a generic translation and * conversion ; it totally depends from the database system. * </i></p> @@ -162,7 +163,7 @@ import adql.query.operand.function.geometry.RegionFunction; * </p> * * @author Grégory Mantelet (ARI;CDS) - * @version 1.5 (03/2019) + * @version 2.0 (08/2019) * @since 1.4 * * @see PostgreSQLTranslator @@ -203,7 +204,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { * @return The qualified (with DB catalog name prefix if any, and with double quotes if needed) DB schema name, * or an empty string if there is no schema or no DB name. */ - public String getQualifiedSchemaName(final DBTable table){ + public String getQualifiedSchemaName(final DBTable table) { if (table == null || table.getDBSchemaName() == null) return ""; @@ -232,7 +233,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { * * @see #getTableName(DBTable, boolean) */ - public String getQualifiedTableName(final DBTable table){ + public String getQualifiedTableName(final DBTable table) { return getTableName(table, true); } @@ -253,12 +254,12 @@ public abstract class JDBCTranslator implements ADQLTranslator { * * @since 2.0 */ - public String getTableName(final DBTable table, final boolean withSchema){ + public String getTableName(final DBTable table, final boolean withSchema) { if (table == null) return ""; StringBuffer buf = new StringBuffer(); - if (withSchema){ + if (withSchema) { buf.append(getQualifiedSchemaName(table)); if (buf.length() > 0) buf.append('.'); @@ -286,7 +287,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { * @return The DB column name (with double quotes if needed), * or an empty string if the given column is NULL. */ - public String getColumnName(final DBColumn column){ + public String getColumnName(final DBColumn column) { return (column == null) ? "" : appendIdentifier(new StringBuffer(), column.getDBName(), IdentifierField.COLUMN).toString(); } @@ -312,7 +313,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { * * @see #appendIdentifier(StringBuffer, String, boolean) */ - public final StringBuffer appendIdentifier(final StringBuffer str, final String id, final IdentifierField field){ + public final StringBuffer appendIdentifier(final StringBuffer str, final String id, final IdentifierField field) { return appendIdentifier(str, id, isCaseSensitive(field)); } @@ -325,7 +326,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { * * @return The string buffer + identifier. */ - public StringBuffer appendIdentifier(final StringBuffer str, final String id, final boolean caseSensitive){ + public StringBuffer appendIdentifier(final StringBuffer str, final String id, final boolean caseSensitive) { if (caseSensitive && !id.matches("\"[^\"]*\"")) return str.append('"').append(id).append('"'); else @@ -334,7 +335,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { @Override @SuppressWarnings({ "unchecked", "rawtypes" }) - public String translate(ADQLObject obj) throws TranslationException{ + public String translate(ADQLObject obj) throws TranslationException { if (obj instanceof ADQLQuery) return translate((ADQLQuery)obj); else if (obj instanceof ADQLList) @@ -356,7 +357,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(ADQLQuery query) throws TranslationException{ + public String translate(ADQLQuery query) throws TranslationException { StringBuffer sql = new StringBuffer(translate(query.getSelect())); sql.append("\nFROM ").append(translate(query.getFrom())); @@ -383,7 +384,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { /* ****** LIST & CLAUSE ****** */ /* *************************** */ @Override - public String translate(ADQLList<? extends ADQLObject> list) throws TranslationException{ + public String translate(ADQLList<? extends ADQLObject> list) throws TranslationException { if (list instanceof ClauseSelect) return translate((ClauseSelect)list); else if (list instanceof ClauseConstraints) @@ -412,7 +413,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { * * @see #getDefaultADQLList(ADQLList, boolean) */ - protected final String getDefaultADQLList(ADQLList<? extends ADQLObject> list) throws TranslationException{ + protected final String getDefaultADQLList(ADQLList<? extends ADQLObject> list) throws TranslationException { return getDefaultADQLList(list, true); } @@ -429,7 +430,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { * * @since 1.4 */ - protected String getDefaultADQLList(ADQLList<? extends ADQLObject> list, final boolean withNamePrefix) throws TranslationException{ + protected String getDefaultADQLList(ADQLList<? extends ADQLObject> list, final boolean withNamePrefix) throws TranslationException { String sql = (list.getName() == null || !withNamePrefix) ? "" : (list.getName() + " "); for(int i = 0; i < list.size(); i++) @@ -439,13 +440,13 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(ClauseSelect clause) throws TranslationException{ + public String translate(ClauseSelect clause) throws TranslationException { String sql = null; - for(int i = 0; i < clause.size(); i++){ - if (i == 0){ + for(int i = 0; i < clause.size(); i++) { + if (i == 0) { sql = clause.getName() + (clause.distinctColumns() ? " DISTINCT" : ""); - }else + } else sql += " " + clause.getSeparator(i); sql += " " + translate(clause.get(i)); @@ -455,7 +456,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(ClauseConstraints clause) throws TranslationException{ + public String translate(ClauseConstraints clause) throws TranslationException { if (clause instanceof ConstraintsGroup) return "(" + getDefaultADQLList(clause) + ")"; else @@ -463,18 +464,18 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(SelectItem item) throws TranslationException{ + public String translate(SelectItem item) throws TranslationException { if (item instanceof SelectAllColumns) return translate((SelectAllColumns)item); StringBuffer translation = new StringBuffer(translate(item.getOperand())); - if (item.hasAlias()){ + if (item.hasAlias()) { translation.append(" AS "); if (item.isCaseSensitive()) appendIdentifier(translation, item.getAlias(), true); else appendIdentifier(translation, item.getAlias().toLowerCase(), true); - }else{ + } else { translation.append(" AS "); appendIdentifier(translation, item.getName(), true); } @@ -483,27 +484,27 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(SelectAllColumns item) throws TranslationException{ + public String translate(SelectAllColumns item) throws TranslationException { // Fetch the full list of columns to display: Iterable<DBColumn> dbCols = null; - if (item.getAdqlTable() != null && item.getAdqlTable().getDBLink() != null){ + if (item.getAdqlTable() != null && item.getAdqlTable().getDBLink() != null) { ADQLTable table = item.getAdqlTable(); dbCols = table.getDBLink(); - }else if (item.getQuery() != null){ - try{ + } else if (item.getQuery() != null) { + try { dbCols = item.getQuery().getFrom().getDBColumns(); - }catch(UnresolvedJoinException pe){ + } catch(UnresolvedJoinException pe) { throw new TranslationException("Due to a join problem, the ADQL to SQL translation can not be completed!", pe); } } // Write the DB name of all these columns: - if (dbCols != null){ + if (dbCols != null) { StringBuffer cols = new StringBuffer(); - for(DBColumn col : dbCols){ + for(DBColumn col : dbCols) { if (cols.length() > 0) cols.append(','); - if (col.getTable() != null){ + if (col.getTable() != null) { if (col.getTable() instanceof DBTableAlias) cols.append(getTableName(col.getTable(), false)).append('.'); else @@ -513,13 +514,13 @@ public abstract class JDBCTranslator implements ADQLTranslator { cols.append(" AS \"").append(col.getADQLName()).append('\"'); } return (cols.length() > 0) ? cols.toString() : item.toADQL(); - }else{ + } else { return item.toADQL(); } } @Override - public String translate(ColumnReference ref) throws TranslationException{ + public String translate(ColumnReference ref) throws TranslationException { if (ref instanceof ADQLOrder) return translate((ADQLOrder)ref); else @@ -535,17 +536,17 @@ public abstract class JDBCTranslator implements ADQLTranslator { * * @throws TranslationException If there is an error during the translation. */ - protected String getDefaultColumnReference(ColumnReference ref) throws TranslationException{ - if (ref.isIndex()){ + protected String getDefaultColumnReference(ColumnReference ref) throws TranslationException { + if (ref.isIndex()) { return "" + ref.getColumnIndex(); - }else{ - if (ref.getDBLink() == null){ + } else { + if (ref.getDBLink() == null) { return (ref.isCaseSensitive() ? ("\"" + ref.getColumnName() + "\"") : ref.getColumnName()); - }else{ + } else { DBColumn dbCol = ref.getDBLink(); StringBuffer colName = new StringBuffer(); // Use the table alias if any: - if (ref.getAdqlTable() != null && ref.getAdqlTable().hasAlias()){ + if (ref.getAdqlTable() != null && ref.getAdqlTable().hasAlias()) { if (ref.getAdqlTable().isCaseSensitive(IdentifierField.ALIAS)) appendIdentifier(colName, ref.getAdqlTable().getAlias(), true).append('.'); else @@ -563,7 +564,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(ADQLOrder order) throws TranslationException{ + public String translate(ADQLOrder order) throws TranslationException { return getDefaultColumnReference(order) + (order.isDescSorting() ? " DESC" : " ASC"); } @@ -571,7 +572,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { /* ****** TABLE & JOIN ****** */ /* ************************** */ @Override - public String translate(FromContent content) throws TranslationException{ + public String translate(FromContent content) throws TranslationException { if (content instanceof ADQLTable) return translate((ADQLTable)content); else if (content instanceof ADQLJoin) @@ -581,7 +582,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(ADQLTable table) throws TranslationException{ + public String translate(ADQLTable table) throws TranslationException { StringBuffer sql = new StringBuffer(); // CASE: SUB-QUERY: @@ -589,9 +590,9 @@ public abstract class JDBCTranslator implements ADQLTranslator { sql.append('(').append(translate(table.getSubQuery())).append(')'); // CASE: TABLE REFERENCE: - else{ + else { // Use the corresponding DB table, if known: - if (table.getDBLink() != null){ + if (table.getDBLink() != null) { /* Note: if the table is aliased, the aliased table is wrapped * inside a DBTableAlias. So, to get the real table name * we should get first the original table thanks to @@ -607,13 +608,13 @@ public abstract class JDBCTranslator implements ADQLTranslator { } // Add the table alias, if any: - if (table.hasAlias()){ + if (table.hasAlias()) { sql.append(" AS "); /* In case where metadata are known, the alias must always be * written case sensitively in order to ensure a translation * stability (i.e. all references clearly point toward this alias * whatever is their character case). */ - if (table.getDBLink() != null){ + if (table.getDBLink() != null) { if (table.isCaseSensitive(IdentifierField.ALIAS)) appendIdentifier(sql, table.getAlias(), true); else @@ -628,7 +629,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(ADQLJoin join) throws TranslationException{ + public String translate(ADQLJoin join) throws TranslationException { StringBuffer sql = new StringBuffer(translate(join.getLeftTable())); if (join.isNatural()) @@ -636,13 +637,13 @@ public abstract class JDBCTranslator implements ADQLTranslator { sql.append(' ').append(join.getJoinType()).append(' ').append(translate(join.getRightTable())).append(' '); - if (!join.isNatural()){ + if (!join.isNatural()) { if (join.getJoinCondition() != null) sql.append(translate(join.getJoinCondition())); - else if (join.hasJoinedColumns()){ + else if (join.hasJoinedColumns()) { StringBuffer cols = new StringBuffer(); Iterator<ADQLColumn> it = join.getJoinedColumns(); - while(it.hasNext()){ + while(it.hasNext()) { ADQLColumn item = it.next(); if (cols.length() > 0) cols.append(", "); @@ -662,7 +663,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { /* ****** OPERAND ****** */ /* ********************* */ @Override - public String translate(ADQLOperand op) throws TranslationException{ + public String translate(ADQLOperand op) throws TranslationException { if (op instanceof ADQLColumn) return translate((ADQLColumn)op); else if (op instanceof Concatenation) @@ -684,14 +685,14 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(ADQLColumn column) throws TranslationException{ + public String translate(ADQLColumn column) throws TranslationException { // Use its DB name if known: - if (column.getDBLink() != null){ + if (column.getDBLink() != null) { DBColumn dbCol = column.getDBLink(); StringBuffer colName = new StringBuffer(); // Use the DBTable if any: - if (dbCol.getTable() != null && dbCol.getTable().getDBName() != null){ + if (dbCol.getTable() != null && dbCol.getTable().getDBName() != null) { /* Note: if the table is aliased, ensure no schema is prefixing * this alias thanks to getTableName(..., false). */ if (dbCol.getTable() instanceof DBTableAlias) @@ -714,32 +715,32 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(Concatenation concat) throws TranslationException{ + public String translate(Concatenation concat) throws TranslationException { return translate((ADQLList<ADQLOperand>)concat); } @Override - public String translate(NegativeOperand negOp) throws TranslationException{ + public String translate(NegativeOperand negOp) throws TranslationException { return "-" + translate(negOp.getOperand()); } @Override - public String translate(NumericConstant numConst) throws TranslationException{ + public String translate(NumericConstant numConst) throws TranslationException { return numConst.getValue(); } @Override - public String translate(StringConstant strConst) throws TranslationException{ + public String translate(StringConstant strConst) throws TranslationException { return "'" + strConst.getValue().replaceAll("'", "''") + "'"; } @Override - public String translate(WrappedOperand op) throws TranslationException{ + public String translate(WrappedOperand op) throws TranslationException { return "(" + translate(op.getOperand()) + ")"; } @Override - public String translate(Operation op) throws TranslationException{ + public String translate(Operation op) throws TranslationException { return translate(op.getLeftOperand()) + op.getOperation().toADQL() + translate(op.getRightOperand()); } @@ -747,7 +748,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { /* ****** CONSTRAINT ****** */ /* ************************ */ @Override - public String translate(ADQLConstraint cons) throws TranslationException{ + public String translate(ADQLConstraint cons) throws TranslationException { if (cons instanceof Comparison) return translate((Comparison)cons); else if (cons instanceof Between) @@ -765,32 +766,32 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(Comparison comp) throws TranslationException{ + public String translate(Comparison comp) throws TranslationException { return translate(comp.getLeftOperand()) + " " + comp.getOperator().toADQL() + " " + translate(comp.getRightOperand()); } @Override - public String translate(Between comp) throws TranslationException{ + public String translate(Between comp) throws TranslationException { return translate(comp.getLeftOperand()) + " " + comp.getName() + " " + translate(comp.getMinOperand()) + " AND " + translate(comp.getMaxOperand()); } @Override - public String translate(Exists exists) throws TranslationException{ + public String translate(Exists exists) throws TranslationException { return "EXISTS(" + translate(exists.getSubQuery()) + ")"; } @Override - public String translate(In in) throws TranslationException{ + public String translate(In in) throws TranslationException { return translate(in.getOperand()) + " " + in.getName() + " (" + (in.hasSubQuery() ? translate(in.getSubQuery()) : translate(in.getValuesList())) + ")"; } @Override - public String translate(IsNull isNull) throws TranslationException{ + public String translate(IsNull isNull) throws TranslationException { return translate(isNull.getColumn()) + " " + isNull.getName(); } @Override - public String translate(NotConstraint notCons) throws TranslationException{ + public String translate(NotConstraint notCons) throws TranslationException { return "NOT " + translate(notCons.getConstraint()); } @@ -798,7 +799,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { /* ****** FUNCTIONS ****** */ /* *********************** */ @Override - public String translate(ADQLFunction fct) throws TranslationException{ + public String translate(ADQLFunction fct) throws TranslationException { if (fct instanceof GeometryFunction) return translate((GeometryFunction)fct); else if (fct instanceof MathFunction) @@ -807,6 +808,8 @@ public abstract class JDBCTranslator implements ADQLTranslator { return translate((SQLFunction)fct); else if (fct instanceof UserDefinedFunction) return translate((UserDefinedFunction)fct); + else if (fct instanceof LowerFunction) + return translate((LowerFunction)fct); else return getDefaultADQLFunction(fct); } @@ -820,7 +823,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { * * @throws TranslationException If there is an error during the translation. */ - protected final String getDefaultADQLFunction(ADQLFunction fct) throws TranslationException{ + protected final String getDefaultADQLFunction(ADQLFunction fct) throws TranslationException { String sql = fct.getName() + "("; for(int i = 0; i < fct.getNbParameters(); i++) @@ -830,7 +833,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(SQLFunction fct) throws TranslationException{ + public String translate(SQLFunction fct) throws TranslationException { if (fct.getType() == SQLFunctionType.COUNT_ALL) return "COUNT(" + (fct.isDistinct() ? "DISTINCT " : "") + "*)"; else @@ -838,20 +841,25 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(MathFunction fct) throws TranslationException{ + public String translate(MathFunction fct) throws TranslationException { return getDefaultADQLFunction(fct); } @Override - public String translate(UserDefinedFunction fct) throws TranslationException{ + public String translate(UserDefinedFunction fct) throws TranslationException { return fct.translate(this); } + @Override + public String translate(LowerFunction fct) throws TranslationException { + return getDefaultADQLFunction(fct); + } + /* *********************************** */ /* ****** GEOMETRICAL FUNCTIONS ****** */ /* *********************************** */ @Override - public String translate(GeometryFunction fct) throws TranslationException{ + public String translate(GeometryFunction fct) throws TranslationException { if (fct instanceof AreaFunction) return translate((AreaFunction)fct); else if (fct instanceof BoxFunction) @@ -881,7 +889,7 @@ public abstract class JDBCTranslator implements ADQLTranslator { } @Override - public String translate(GeometryValue<? extends GeometryFunction> geomValue) throws TranslationException{ + public String translate(GeometryValue<? extends GeometryFunction> geomValue) throws TranslationException { return translate(geomValue.getValue()); } diff --git a/src/adql/translator/MySQLTranslator.java b/src/adql/translator/MySQLTranslator.java index 6d2b3ce465f7e10b6b91633addbec4ce745d413f..28ae9229f4207c041291d16dae6cf689ad7120a9 100644 --- a/src/adql/translator/MySQLTranslator.java +++ b/src/adql/translator/MySQLTranslator.java @@ -1,25 +1,5 @@ package adql.translator; -import adql.db.DBType; -import adql.db.DBType.DBDatatype; -import adql.db.STCS.Region; -import adql.parser.grammar.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; -import adql.query.operand.function.geometry.CircleFunction; -import adql.query.operand.function.geometry.ContainsFunction; -import adql.query.operand.function.geometry.DistanceFunction; -import adql.query.operand.function.geometry.ExtractCoord; -import adql.query.operand.function.geometry.ExtractCoordSys; -import adql.query.operand.function.geometry.IntersectsFunction; -import adql.query.operand.function.geometry.PointFunction; -import adql.query.operand.function.geometry.PolygonFunction; -import adql.query.operand.function.geometry.RegionFunction; - /* * This file is part of ADQLLibrary. * @@ -40,6 +20,27 @@ import adql.query.operand.function.geometry.RegionFunction; * UDS/Centre de Données astronomiques de Strasbourg (CDS) */ +import adql.db.DBType; +import adql.db.DBType.DBDatatype; +import adql.db.STCS.Region; +import adql.parser.grammar.ParseException; +import adql.query.IdentifierField; +import adql.query.constraint.Comparison; +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; +import adql.query.operand.function.geometry.CircleFunction; +import adql.query.operand.function.geometry.ContainsFunction; +import adql.query.operand.function.geometry.DistanceFunction; +import adql.query.operand.function.geometry.ExtractCoord; +import adql.query.operand.function.geometry.ExtractCoordSys; +import adql.query.operand.function.geometry.IntersectsFunction; +import adql.query.operand.function.geometry.PointFunction; +import adql.query.operand.function.geometry.PolygonFunction; +import adql.query.operand.function.geometry.RegionFunction; + /** * Translates all ADQL objects into an SQL interrogation query designed for * MySQL. @@ -51,7 +52,7 @@ import adql.query.operand.function.geometry.RegionFunction; * </i></p> * * @author Grégory Mantelet (ARI;CDS) - * @version 1.5 (03/2019) + * @version 2.0 (08/2019) * @since 1.4 */ public class MySQLTranslator extends JDBCTranslator { @@ -77,7 +78,7 @@ public class MySQLTranslator extends JDBCTranslator { * schema, table and column names will be surrounded by back-quotes in the * SQL translation. */ - public MySQLTranslator(){ + public MySQLTranslator() { caseSensitivity = 0x0F; } @@ -92,7 +93,7 @@ public class MySQLTranslator extends JDBCTranslator { * (surrounded by back-quotes), * <i>false</i> for case insensitivity. */ - public MySQLTranslator(final boolean allCaseSensitive){ + public MySQLTranslator(final boolean allCaseSensitive) { caseSensitivity = allCaseSensitive ? (byte)0x0F : (byte)0x00; } @@ -109,7 +110,7 @@ public class MySQLTranslator extends JDBCTranslator { * @param column <i>true</i> to translate column names with back-quotes * (case sensitive in the DBMS), <i>false</i> otherwise. */ - public MySQLTranslator(final boolean catalog, final boolean schema, final boolean table, final boolean column){ + public MySQLTranslator(final boolean catalog, final boolean schema, final boolean table, final boolean column) { caseSensitivity = IdentifierField.CATALOG.setCaseSensitive(caseSensitivity, catalog); caseSensitivity = IdentifierField.SCHEMA.setCaseSensitive(caseSensitivity, schema); caseSensitivity = IdentifierField.TABLE.setCaseSensitive(caseSensitivity, table); @@ -117,12 +118,12 @@ public class MySQLTranslator extends JDBCTranslator { } @Override - public boolean isCaseSensitive(final IdentifierField field){ + public boolean isCaseSensitive(final IdentifierField field) { return field == null ? false : field.isCaseSensitive(caseSensitivity); } @Override - public StringBuffer appendIdentifier(final StringBuffer str, final String id, final boolean caseSensitive){ + public StringBuffer appendIdentifier(final StringBuffer str, final String id, final boolean caseSensitive) { /* Note: In MySQL the identifier quoting character is a back-quote. */ if (caseSensitive && !id.matches("\"[^\"]*\"")) return str.append('`').append(id).append('`'); @@ -137,10 +138,21 @@ public class MySQLTranslator extends JDBCTranslator { /* ********************************************************************** */ @Override - public String translate(Concatenation concat) throws TranslationException{ + public String translate(Comparison comp) throws TranslationException { + switch(comp.getOperator()) { + case ILIKE: + case NOTILIKE: + throw new TranslationException("Translation of ILIKE impossible! This is not supported in MySQL."); + default: + return translate(comp.getLeftOperand()) + " " + comp.getOperator().toADQL() + " " + translate(comp.getRightOperand()); + } + } + + @Override + public String translate(Concatenation concat) throws TranslationException { StringBuffer translated = new StringBuffer(); - for(ADQLOperand op : concat){ + for(ADQLOperand op : concat) { if (translated.length() == 0) translated.append("CONCAT("); else @@ -159,7 +171,7 @@ public class MySQLTranslator extends JDBCTranslator { /* ********************************************************************** */ @Override - public DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, String dbmsTypeName, final String[] params){ + public DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, String dbmsTypeName, final String[] params) { // If no type is provided return VARCHAR: if (dbmsTypeName == null || dbmsTypeName.trim().length() == 0) return null; @@ -169,10 +181,10 @@ public class MySQLTranslator extends JDBCTranslator { // Extract the length parameter (always the first one): int lengthParam = DBType.NO_LENGTH; - if (params != null && params.length > 0){ - try{ + if (params != null && params.length > 0) { + try { lengthParam = Integer.parseInt(params[0]); - }catch(NumberFormatException nfe){ + } catch(NumberFormatException nfe) { } } @@ -218,11 +230,11 @@ public class MySQLTranslator extends JDBCTranslator { } @Override - public String convertTypeToDB(final DBType type){ + public String convertTypeToDB(final DBType type) { if (type == null) return "VARCHAR(" + DEFAULT_VARIABLE_LENGTH + ")"; - switch(type.type){ + switch(type.type) { case SMALLINT: case INTEGER: @@ -254,12 +266,12 @@ public class MySQLTranslator extends JDBCTranslator { } @Override - public Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException{ + public Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException { throw new ParseException("Unsupported geometrical value! The value \"" + jdbcColValue + "\" can not be parsed as a region."); } @Override - public Object translateGeometryToDB(final Region region) throws ParseException{ + public Object translateGeometryToDB(final Region region) throws ParseException { throw new ParseException("Geometries can not be uploaded in the database in this implementation!"); } @@ -270,62 +282,62 @@ public class MySQLTranslator extends JDBCTranslator { /* ********************************************************************** */ @Override - public String translate(ExtractCoord extractCoord) throws TranslationException{ + public String translate(ExtractCoord extractCoord) throws TranslationException { return getDefaultADQLFunction(extractCoord); } @Override - public String translate(ExtractCoordSys extractCoordSys) throws TranslationException{ + public String translate(ExtractCoordSys extractCoordSys) throws TranslationException { return getDefaultADQLFunction(extractCoordSys); } @Override - public String translate(AreaFunction areaFunction) throws TranslationException{ + public String translate(AreaFunction areaFunction) throws TranslationException { return getDefaultADQLFunction(areaFunction); } @Override - public String translate(CentroidFunction centroidFunction) throws TranslationException{ + public String translate(CentroidFunction centroidFunction) throws TranslationException { return getDefaultADQLFunction(centroidFunction); } @Override - public String translate(DistanceFunction fct) throws TranslationException{ + public String translate(DistanceFunction fct) throws TranslationException { return getDefaultADQLFunction(fct); } @Override - public String translate(ContainsFunction fct) throws TranslationException{ + public String translate(ContainsFunction fct) throws TranslationException { return getDefaultADQLFunction(fct); } @Override - public String translate(IntersectsFunction fct) throws TranslationException{ + public String translate(IntersectsFunction fct) throws TranslationException { return getDefaultADQLFunction(fct); } @Override - public String translate(BoxFunction box) throws TranslationException{ + public String translate(BoxFunction box) throws TranslationException { return getDefaultADQLFunction(box); } @Override - public String translate(CircleFunction circle) throws TranslationException{ + public String translate(CircleFunction circle) throws TranslationException { return getDefaultADQLFunction(circle); } @Override - public String translate(PointFunction point) throws TranslationException{ + public String translate(PointFunction point) throws TranslationException { return getDefaultADQLFunction(point); } @Override - public String translate(PolygonFunction polygon) throws TranslationException{ + public String translate(PolygonFunction polygon) throws TranslationException { return getDefaultADQLFunction(polygon); } @Override - public String translate(RegionFunction region) throws TranslationException{ + public String translate(RegionFunction region) throws TranslationException { return getDefaultADQLFunction(region); } diff --git a/src/adql/translator/SQLServerTranslator.java b/src/adql/translator/SQLServerTranslator.java index 79990dd4eb6f78ccd55d1a7097ab30c0db80894d..3a045b0d41e96fc7caeb25773128dbf00f01fbac 100644 --- a/src/adql/translator/SQLServerTranslator.java +++ b/src/adql/translator/SQLServerTranslator.java @@ -33,6 +33,7 @@ import adql.parser.grammar.ParseException; import adql.query.ADQLQuery; import adql.query.ClauseSelect; import adql.query.IdentifierField; +import adql.query.constraint.Comparison; import adql.query.from.ADQLJoin; import adql.query.from.ADQLTable; import adql.query.from.FromContent; @@ -77,7 +78,7 @@ import adql.query.operand.function.geometry.RegionFunction; * </i></p> * * @author Grégory Mantelet (ARI;CDS) - * @version 1.5 (03/2019) + * @version 2.0 (08/2019) * @since 1.4 * * @see SQLServer_ADQLQueryFactory @@ -97,7 +98,7 @@ public class SQLServerTranslator extends JDBCTranslator { * Builds an SQLServerTranslator which always translates in SQL all identifiers (schema, table and column) in a case sensitive manner ; * in other words, schema, table and column names will be surrounded by double quotes in the SQL translation. */ - public SQLServerTranslator(){ + public SQLServerTranslator() { caseSensitivity = 0x0F; } @@ -107,7 +108,7 @@ public class SQLServerTranslator extends JDBCTranslator { * * @param allCaseSensitive <i>true</i> to translate all identifiers in a case sensitive manner (surrounded by double quotes), <i>false</i> for case insensitivity. */ - public SQLServerTranslator(final boolean allCaseSensitive){ + public SQLServerTranslator(final boolean allCaseSensitive) { caseSensitivity = allCaseSensitive ? (byte)0x0F : (byte)0x00; } @@ -119,7 +120,7 @@ public class SQLServerTranslator extends JDBCTranslator { * @param table <i>true</i> to translate table names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. * @param column <i>true</i> to translate column names with double quotes (case sensitive in the DBMS), <i>false</i> otherwise. */ - public SQLServerTranslator(final boolean catalog, final boolean schema, final boolean table, final boolean column){ + public SQLServerTranslator(final boolean catalog, final boolean schema, final boolean table, final boolean column) { caseSensitivity = IdentifierField.CATALOG.setCaseSensitive(caseSensitivity, catalog); caseSensitivity = IdentifierField.SCHEMA.setCaseSensitive(caseSensitivity, schema); caseSensitivity = IdentifierField.TABLE.setCaseSensitive(caseSensitivity, table); @@ -127,7 +128,7 @@ public class SQLServerTranslator extends JDBCTranslator { } @Override - public boolean isCaseSensitive(final IdentifierField field){ + public boolean isCaseSensitive(final IdentifierField field) { return field == null ? false : field.isCaseSensitive(caseSensitivity); } @@ -139,7 +140,7 @@ public class SQLServerTranslator extends JDBCTranslator { * @see #translate(ClauseSelect) */ @Override - public String translate(ADQLQuery query) throws TranslationException{ + public String translate(ADQLQuery query) throws TranslationException { StringBuffer sql = new StringBuffer(translate(query.getSelect())); sql.append("\nFROM ").append(translate(query.getFrom())); @@ -160,13 +161,13 @@ public class SQLServerTranslator extends JDBCTranslator { } @Override - public String translate(ClauseSelect clause) throws TranslationException{ + public String translate(ClauseSelect clause) throws TranslationException { String sql = null; - for(int i = 0; i < clause.size(); i++){ - if (i == 0){ + for(int i = 0; i < clause.size(); i++) { + if (i == 0) { sql = clause.getName() + (clause.distinctColumns() ? " DISTINCT" : "") + (clause.hasLimit() ? " TOP " + clause.getLimit() + " " : ""); - }else + } else sql += " " + clause.getSeparator(i); sql += " " + translate(clause.get(i)); @@ -176,10 +177,21 @@ public class SQLServerTranslator extends JDBCTranslator { } @Override - public String translate(Concatenation concat) throws TranslationException{ + public String translate(Comparison comp) throws TranslationException { + switch(comp.getOperator()) { + case ILIKE: + case NOTILIKE: + throw new TranslationException("Translation of ILIKE impossible! This is not supported in MS-SQL Server."); + default: + return translate(comp.getLeftOperand()) + " " + comp.getOperator().toADQL() + " " + translate(comp.getRightOperand()); + } + } + + @Override + public String translate(Concatenation concat) throws TranslationException { StringBuffer translated = new StringBuffer(); - for(ADQLOperand op : concat){ + for(ADQLOperand op : concat) { if (translated.length() > 0) translated.append(" + "); translated.append(translate(op)); @@ -189,26 +201,26 @@ public class SQLServerTranslator extends JDBCTranslator { } @Override - public String translate(final ADQLJoin join) throws TranslationException{ + public String translate(final ADQLJoin join) throws TranslationException { StringBuffer sql = new StringBuffer(translate(join.getLeftTable())); sql.append(' ').append(join.getJoinType()).append(' ').append(translate(join.getRightTable())).append(' '); // CASE: NATURAL - if (join.isNatural()){ - try{ + if (join.isNatural()) { + 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){ + 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){ + 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); @@ -222,13 +234,13 @@ public class SQLServerTranslator extends JDBCTranslator { } sql.append("ON ").append(buf.toString()); - }catch(UnresolvedJoinException uje){ + } catch(UnresolvedJoinException uje) { throw new TranslationException("Impossible to resolve the NATURAL JOIN between " + join.getLeftTable().toADQL() + " and " + join.getRightTable().toADQL() + "!", uje); } } // CASE: USING - else if (join.hasJoinedColumns()){ - try{ + else if (join.hasJoinedColumns()) { + try { StringBuffer buf = new StringBuffer(); // For each columns of usingList, check there is in each list exactly one matching column, and then, translate it as ON condition: @@ -237,7 +249,7 @@ public class SQLServerTranslator extends JDBCTranslator { SearchColumnList leftList = join.getLeftTable().getDBColumns(); SearchColumnList rightList = join.getRightTable().getDBColumns(); Iterator<ADQLColumn> itCols = join.getJoinedColumns(); - while(itCols.hasNext()){ + while(itCols.hasNext()) { usingCol = itCols.next(); // search for exactly one column with the same name in the LEFT list // and throw an exception if there is none, or if there are several matches: @@ -253,7 +265,7 @@ public class SQLServerTranslator extends JDBCTranslator { } sql.append("ON ").append(buf.toString()); - }catch(UnresolvedJoinException uje){ + } catch(UnresolvedJoinException uje) { throw new TranslationException("Impossible to resolve the JOIN USING between " + join.getLeftTable().toADQL() + " and " + join.getRightTable().toADQL() + "!", uje); } } @@ -278,9 +290,9 @@ public class SQLServerTranslator extends JDBCTranslator { * * @return The generated column. */ - protected ADQLColumn generateJoinColumn(final FromContent table, final DBColumn colMeta, final ADQLColumn joinedColumn){ + 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 != null) { if (table instanceof ADQLTable) newCol.setAdqlTable((ADQLTable)table); else @@ -291,68 +303,68 @@ public class SQLServerTranslator extends JDBCTranslator { } @Override - public String translate(final ExtractCoord extractCoord) throws TranslationException{ + public String translate(final ExtractCoord extractCoord) throws TranslationException { return getDefaultADQLFunction(extractCoord); } @Override - public String translate(final ExtractCoordSys extractCoordSys) throws TranslationException{ + public String translate(final ExtractCoordSys extractCoordSys) throws TranslationException { return getDefaultADQLFunction(extractCoordSys); } @Override - public String translate(final AreaFunction areaFunction) throws TranslationException{ + public String translate(final AreaFunction areaFunction) throws TranslationException { return getDefaultADQLFunction(areaFunction); } @Override - public String translate(final CentroidFunction centroidFunction) throws TranslationException{ + public String translate(final CentroidFunction centroidFunction) throws TranslationException { return getDefaultADQLFunction(centroidFunction); } @Override - public String translate(final DistanceFunction fct) throws TranslationException{ + public String translate(final DistanceFunction fct) throws TranslationException { return getDefaultADQLFunction(fct); } @Override - public String translate(final ContainsFunction fct) throws TranslationException{ + public String translate(final ContainsFunction fct) throws TranslationException { return getDefaultADQLFunction(fct); } @Override - public String translate(final IntersectsFunction fct) throws TranslationException{ + public String translate(final IntersectsFunction fct) throws TranslationException { return getDefaultADQLFunction(fct); } @Override - public String translate(final PointFunction point) throws TranslationException{ + public String translate(final PointFunction point) throws TranslationException { return getDefaultADQLFunction(point); } @Override - public String translate(final CircleFunction circle) throws TranslationException{ + public String translate(final CircleFunction circle) throws TranslationException { return getDefaultADQLFunction(circle); } @Override - public String translate(final BoxFunction box) throws TranslationException{ + public String translate(final BoxFunction box) throws TranslationException { return getDefaultADQLFunction(box); } @Override - public String translate(final PolygonFunction polygon) throws TranslationException{ + public String translate(final PolygonFunction polygon) throws TranslationException { return getDefaultADQLFunction(polygon); } @Override - public String translate(final RegionFunction region) throws TranslationException{ + public String translate(final RegionFunction region) throws TranslationException { return getDefaultADQLFunction(region); } @Override - public String translate(MathFunction fct) throws TranslationException{ - switch(fct.getType()){ + public String translate(MathFunction fct) throws TranslationException { + switch(fct.getType()) { case TRUNCATE: // third argument to round nonzero means do a truncate return "round(convert(float, " + ((fct.getNbParameters() >= 2) ? (translate(fct.getParameter(0)) + ", " + translate(fct.getParameter(1))) : "") + "),1)"; @@ -385,7 +397,7 @@ public class SQLServerTranslator extends JDBCTranslator { } @Override - public DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, String dbmsTypeName, final String[] params){ + public DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, String dbmsTypeName, final String[] params) { // If no type is provided return VARCHAR: if (dbmsTypeName == null || dbmsTypeName.trim().length() == 0) return null; @@ -395,10 +407,10 @@ public class SQLServerTranslator extends JDBCTranslator { // Extract the length parameter (always the first one): int lengthParam = DBType.NO_LENGTH; - if (params != null && params.length > 0){ - try{ + if (params != null && params.length > 0) { + try { lengthParam = Integer.parseInt(params[0]); - }catch(NumberFormatException nfe){ + } catch(NumberFormatException nfe) { } } @@ -444,11 +456,11 @@ public class SQLServerTranslator extends JDBCTranslator { } @Override - public String convertTypeToDB(final DBType type){ + public String convertTypeToDB(final DBType type) { if (type == null) return "varchar"; - switch(type.type){ + switch(type.type) { case SMALLINT: case REAL: @@ -483,12 +495,12 @@ public class SQLServerTranslator extends JDBCTranslator { } @Override - public Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException{ + public Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException { throw new ParseException("Unsupported geometrical value! The value \"" + jdbcColValue + "\" can not be parsed as a region."); } @Override - public Object translateGeometryToDB(final Region region) throws ParseException{ + public Object translateGeometryToDB(final Region region) throws ParseException { throw new ParseException("Geometries can not be uploaded in the database in this implementation!"); } diff --git a/test/adql/parser/feature/TestFeatureSet.java b/test/adql/parser/feature/TestFeatureSet.java index fa1d4c4db5ea2fa408b77a6a716a07672214985f..6177a33bc2021740ff0017de71694d91c8359281 100644 --- a/test/adql/parser/feature/TestFeatureSet.java +++ b/test/adql/parser/feature/TestFeatureSet.java @@ -14,9 +14,10 @@ import org.junit.Test; import adql.db.DBType; import adql.db.DBType.DBDatatype; -import adql.parser.grammar.ParseException; import adql.db.FunctionDef; +import adql.parser.grammar.ParseException; import adql.query.ColumnReference; +import adql.query.constraint.ComparisonOperator; import adql.query.operand.function.geometry.BoxFunction; import adql.query.operand.function.geometry.PolygonFunction; import adql.query.operand.function.string.LowerFunction; @@ -179,6 +180,8 @@ public class TestFeatureSet { /* CASE: ok (with a set containing just 1 item) * => un-supported + no more set for the feature type! */ + assertTrue(set.unsupport(ComparisonOperator.ILIKE.getFeatureDescription())); + assertEquals(1, set.supportedFeatures.get(LowerFunction.FEATURE.type).size()); assertTrue(set.supportedFeatures.containsKey(LowerFunction.FEATURE.type)); assertTrue(set.supportedFeatures.get(LowerFunction.FEATURE.type).contains(LowerFunction.FEATURE)); assertTrue(set.unsupport(LowerFunction.FEATURE));