diff --git a/src/adql/parser/ADQLQueryFactory.java b/src/adql/parser/ADQLQueryFactory.java index 5829f327e5741c0f0da6590d48a2bfcecd3f890b..d291ef4e297a1191c51e32bad90d4037f03ce605 100644 --- a/src/adql/parser/ADQLQueryFactory.java +++ b/src/adql/parser/ADQLQueryFactory.java @@ -372,10 +372,20 @@ public class ADQLQueryFactory { return new BoxFunction(coordinateSystem, firstCoord, secondCoord, boxWidth, boxHeight); } + /** @since 2.0 */ + public BoxFunction createBox(ADQLOperand coordinateSystem, GeometryValue<GeometryFunction> center, ADQLOperand boxWidth, ADQLOperand boxHeight) throws Exception { + return new BoxFunction(coordinateSystem, center, boxWidth, boxHeight); + } + public CircleFunction createCircle(ADQLOperand coordSys, ADQLOperand coord1, ADQLOperand coord2, ADQLOperand radius) throws Exception { return new CircleFunction(coordSys, coord1, coord2, radius); } + /** @since 2.0 */ + public CircleFunction createCircle(ADQLOperand coordSys, GeometryValue<GeometryFunction> center, ADQLOperand radius) throws Exception { + return new CircleFunction(coordSys, center, radius); + } + public CentroidFunction createCentroid(GeometryFunction param) throws Exception { return new CentroidFunction(new GeometryValue<GeometryFunction>(param)); } diff --git a/src/adql/parser/grammar/adqlGrammar201.jj b/src/adql/parser/grammar/adqlGrammar201.jj index 9626e427fd06e43ad48356b1dbe2da4d84d62dc1..24fef4ebb2b4fa0e575cbddc8e1b39aa1c3a152b 100644 --- a/src/adql/parser/grammar/adqlGrammar201.jj +++ b/src/adql/parser/grammar/adqlGrammar201.jj @@ -1305,34 +1305,30 @@ DistanceFunction DistanceFunction(): { Token fct=null, end=null; DistanceFunctio } } +GeometryValue<GeometryFunction> PointValue(): { GeometryFunction p=null; ADQLColumn col=null; UserDefinedFunction udf=null; } { + ( p=Point() + | p=Centroid() + | LOOKAHEAD(2) udf=UserDefinedFunction() + | col=Column() ) + { + if (p != null) + return new GeometryValue<GeometryFunction>(p); + else if (udf != null){ + udf.setExpectedType('G'); + return new GeometryValue<GeometryFunction>(udf); + }else{ + col.setExpectedType('G'); + return new GeometryValue<GeometryFunction>(col); + } + } +} + DistanceFunction DistanceFunction2(): { Token fct=null, end=null; DistanceFunction gf; GeometryValue<GeometryFunction> gvp1, gvp2; GeometryFunction p1=null, p2=null; ADQLColumn col1=null, col2=null; UserDefinedFunction udf1=null, udf2=null; } { try { fct=<DISTANCE> <LEFT_PAR> - (p1=Point()|p1=Centroid()|LOOKAHEAD(2) udf1=UserDefinedFunction()|col1=Column()) - { - if (p1 != null) - gvp1 = new GeometryValue<GeometryFunction>(p1); - else if (udf1 != null){ - udf1.setExpectedType('G'); - gvp1 = new GeometryValue<GeometryFunction>(udf1); - }else{ - col1.setExpectedType('G'); - gvp1 = new GeometryValue<GeometryFunction>(col1); - } - } + gvp1=PointValue() <COMMA> - (p2=Point()|p2=Centroid()|LOOKAHEAD(2) udf2=UserDefinedFunction()|col2=Column()) - { - if (p2 != null) - gvp2 = new GeometryValue<GeometryFunction>(p2); - else if (udf2 != null){ - udf2.setExpectedType('G'); - gvp2 = new GeometryValue<GeometryFunction>(udf2); - }else{ - col2.setExpectedType('G'); - gvp2 = new GeometryValue<GeometryFunction>(col2); - } - } + gvp2=PointValue() end=<RIGHT_PAR> { gf = queryFactory.createDistance(gvp1, gvp2); @@ -1349,45 +1345,23 @@ ADQLOperand CoordinateSystem(): { ADQLOperand coordSys=null;}{ { return coordSys; } } -GeometryFunction GeometryValueFunction(): {Token fct=null, end=null; ADQLOperand width, height; ADQLOperand[] coords, tmp; Vector<ADQLOperand> vCoords; ADQLOperand op=null; GeometryValue<GeometryFunction> gvf = null; GeometryFunction gf = null;} { +GeometryFunction GeometryValueFunction(): {Token fct=null, end=null; ADQLOperand coordSys, width, height; ADQLOperand[] coords = null, tmp; Vector<ADQLOperand> vCoords; ADQLOperand op=null; GeometryValue<GeometryFunction> gvf = null, gvp = null; GeometryFunction gf = null;} { try{ // BOX (deprecated since ADQL-2.1) - (LOOKAHEAD(BoxWithCooSys()) gf=BoxWithCooSys() - - // BOX: - | (fct=<BOX> <LEFT_PAR> // coord_sys - coords=Coordinates() // coordinates - <COMMA> width=NumericExpression() <COMMA> height=NumericExpression() end=<RIGHT_PAR>) - {gf = queryFactory.createBox(null, coords[0], coords[1], width, height);} + (gf=Box() // CENTROID: | gf=Centroid() - // CIRCLE (deprecated since ADQL-2.1) - | LOOKAHEAD(CircleWithCooSys()) gf=CircleWithCooSys() - // CIRCLE: - | (fct=<CIRCLE> <LEFT_PAR> - coords=Coordinates() // coordinates - <COMMA> width=NumericExpression() end=<RIGHT_PAR>) // radius - {gf = queryFactory.createCircle(null, coords[0], coords[1], width);} + | gf=Circle() // POINT: | gf=Point() // POLYGON (deprecated since ADQL-2.1) - | LOOKAHEAD(PolygonWithCooSys()) gf=PolygonWithCooSys() - - // POLYGON: - | (fct=<POLYGON> <LEFT_PAR> - { vCoords = new Vector<ADQLOperand>(); } // coordinates - tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} - <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} - <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} - (<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);})* - end=<RIGHT_PAR>) - { gf = queryFactory.createPolygon(null, vCoords); } + | gf=Polygon() /* // REGION (REMOVED SINCE 2.1): | (fct=<REGION> <LEFT_PAR> op=StringExpression() end=<RIGHT_PAR>) {gf = queryFactory.createRegion(op);}*/ @@ -1403,10 +1377,41 @@ GeometryFunction GeometryValueFunction(): {Token fct=null, end=null; ADQLOperand } } -GeometryFunction BoxWithCooSys(): { Token fct=null, end=null; ADQLOperand coordSys; ADQLOperand width, height; ADQLOperand[] coords; } { - fct=<BOX> <LEFT_PAR> coordSys=CoordinateSystem() // coord_sys - <COMMA> coords=Coordinates() // coordinates - <COMMA> width=NumericExpression() <COMMA> height=NumericExpression() end=<RIGHT_PAR> +GeometryFunction Box(): { GeometryFunction gf; } { + ( + LOOKAHEAD(BoxWithPoint()) + gf=BoxWithPoint() + | + gf=BoxWithCoords() + ) + { return gf; } +} + +GeometryFunction BoxWithPoint(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand width, height; GeometryValue<GeometryFunction> center = null; } { + fct=<BOX> <LEFT_PAR> + [ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1) + center=PointValue() // center point + <COMMA> width=NumericExpression() // width + <COMMA> height=NumericExpression() // height + end=<RIGHT_PAR> + { + try { + GeometryFunction gf = queryFactory.createBox(coordSys, center, width, height); + gf.setPosition(new TextPosition(fct, end)); + return gf; + }catch(Exception ex){ + throw generateParseException(ex); + } + } +} + +GeometryFunction BoxWithCoords(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand width, height; ADQLOperand[] coords = null; } { + fct=<BOX> <LEFT_PAR> + [ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1) + coords=Coordinates() // center coordinates + <COMMA> width=NumericExpression() // width + <COMMA> height=NumericExpression() // height + end=<RIGHT_PAR> { try { GeometryFunction gf = queryFactory.createBox(coordSys, coords[0], coords[1], width, height); @@ -1418,10 +1423,38 @@ GeometryFunction BoxWithCooSys(): { Token fct=null, end=null; ADQLOperand coordS } } -GeometryFunction CircleWithCooSys(): { Token fct=null, end=null; ADQLOperand coordSys; ADQLOperand width; ADQLOperand[] coords; } { - fct=<CIRCLE> <LEFT_PAR> coordSys=CoordinateSystem() <COMMA> // coord_sys - coords=Coordinates() // coordinates - <COMMA> width=NumericExpression() end=<RIGHT_PAR> // radius +GeometryFunction Circle(): { GeometryFunction gf; } { + ( LOOKAHEAD(CircleWithPoint()) + gf=CircleWithPoint() + | + gf=CircleWithCoords() + ) + { return gf; } +} + +GeometryFunction CircleWithPoint(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand width; GeometryValue<GeometryFunction> center = null; } { + fct=<CIRCLE> <LEFT_PAR> + [ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1) + center=PointValue() // center coordinates + <COMMA> width=NumericExpression() // radius + end=<RIGHT_PAR> + { + try { + GeometryFunction gf = queryFactory.createCircle(coordSys, center, width); + gf.setPosition(new TextPosition(fct, end)); + return gf; + }catch(Exception ex){ + throw generateParseException(ex); + } + } +} + +GeometryFunction CircleWithCoords(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand width; ADQLOperand[] coords = null; } { + fct=<CIRCLE> <LEFT_PAR> + [ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1) + coords=Coordinates() // center coordinates + <COMMA> width=NumericExpression() // radius + end=<RIGHT_PAR> { try { GeometryFunction gf = queryFactory.createCircle(coordSys, coords[0], coords[1], width); @@ -1444,33 +1477,14 @@ CentroidFunction Centroid(): {Token fct=null, end=null; GeometryValue<GeometryFu } } -PointFunction Point(): {Token start, end; ADQLOperand[] coords; PointFunction pf;} { - // POINT (depecrated since ADQL-2.1) - (LOOKAHEAD(PointWithCooSys()) - pf=PointWithCooSys() - { return pf; } - - // POINT (last version - >= ADQL-2.1) - | - start=<POINT> <LEFT_PAR> coords=Coordinates() end=<RIGHT_PAR> // coordinates - { - try{ - pf = queryFactory.createPoint(null, coords[0], coords[1]); - pf.setPosition(new TextPosition(start, end)); - return pf; - }catch(Exception ex){ - throw generateParseException(ex); - } - } - ) -} - -PointFunction PointWithCooSys(): {Token start, end; ADQLOperand coordSys; ADQLOperand[] coords;} { - start=<POINT> <LEFT_PAR> coordSys=CoordinateSystem() <COMMA> // coord_sys - coords=Coordinates() end=<RIGHT_PAR> // coordinates +PointFunction Point(): {Token start, end; ADQLOperand coordSys=null; ADQLOperand[] coords; PointFunction pf;} { + start=<POINT> <LEFT_PAR> + [ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1) + coords=Coordinates() // coordinates + end=<RIGHT_PAR> { try{ - PointFunction pf = queryFactory.createPoint(coordSys, coords[0], coords[1]); + pf = queryFactory.createPoint(coordSys, coords[0], coords[1]); pf.setPosition(new TextPosition(start, end)); return pf; }catch(Exception ex){ @@ -1479,14 +1493,45 @@ PointFunction PointWithCooSys(): {Token start, end; ADQLOperand coordSys; ADQLOp } } -GeometryFunction PolygonWithCooSys(): { Token fct=null, end=null; ADQLOperand coordSys; ADQLOperand[] coords, tmp; Vector<ADQLOperand> vCoords; } { - fct=<POLYGON> <LEFT_PAR> coordSys=CoordinateSystem() // coord_sys - { vCoords = new Vector<ADQLOperand>(); } // coordinates - <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} - <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} - <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} - (<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);})* - end=<RIGHT_PAR> +GeometryFunction Polygon(): { GeometryFunction gf; } { + ( + LOOKAHEAD(PolygonWithPoints()) + gf=PolygonWithPoints() + | + gf=PolygonWithCoords() + ) + { return gf; } +} + +GeometryFunction PolygonWithPoints(): { Token fct=null, end=null; ADQLOperand coordSys=null; GeometryValue<GeometryFunction> tmp; Vector<ADQLOperand> vCoords; } { + fct=<POLYGON> <LEFT_PAR> + [ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1) + { vCoords = new Vector<ADQLOperand>(); } // points (min. 3) + tmp=PointValue() {vCoords.add(tmp);} + <COMMA> tmp=PointValue() {vCoords.add(tmp);} + <COMMA> tmp=PointValue() {vCoords.add(tmp);} + (<COMMA> tmp=PointValue() {vCoords.add(tmp);})* + end=<RIGHT_PAR> + { + try { + GeometryFunction gf = queryFactory.createPolygon(coordSys, vCoords); + gf.setPosition(new TextPosition(fct, end)); + return gf; + }catch(Exception ex){ + throw generateParseException(ex); + } + } +} + +GeometryFunction PolygonWithCoords(): { Token fct=null, end=null; ADQLOperand coordSys=null; ADQLOperand[] coords, tmp; Vector<ADQLOperand> vCoords; } { + fct=<POLYGON> <LEFT_PAR> + [ coordSys=CoordinateSystem() <COMMA> ] // coord_sys (deprecated since ADQL-2.1) + { vCoords = new Vector<ADQLOperand>(); } // coordinates (min. 3 pairs) + tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} + <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} + <COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);} + (<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);})* + end=<RIGHT_PAR> { try { GeometryFunction gf = queryFactory.createPolygon(coordSys, vCoords); diff --git a/src/adql/query/operand/function/geometry/BoxFunction.java b/src/adql/query/operand/function/geometry/BoxFunction.java index e4b429bfdc5ec5697336f94796a621f914160219..3e84e26efeedebdbadb89bbdcc60dd6e3adafae1 100644 --- a/src/adql/query/operand/function/geometry/BoxFunction.java +++ b/src/adql/query/operand/function/geometry/BoxFunction.java @@ -16,13 +16,15 @@ package adql.query.operand.function.geometry; * 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-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ import adql.parser.feature.LanguageFeature; import adql.query.ADQLObject; +import adql.query.operand.ADQLColumn; import adql.query.operand.ADQLOperand; +import adql.query.operand.function.UserDefinedFunction; /** * It represents the box function of the ADQL language. @@ -66,8 +68,7 @@ import adql.query.operand.ADQLOperand; * * <p> * The function arguments may be literal values, as above, or they may be - * column references, functions or expressions that returns the appropriate - * datatypes. + * column references, functions or expressions that returns a POINT value. * </p> * * <i> @@ -87,7 +88,7 @@ import adql.query.operand.ADQLOperand; * </p> * * @author Grégory Mantelet (CDS;ARI) - * @version 2.0 (07/2019) + * @version 2.0 (06/2020) */ public class BoxFunction extends GeometryFunction { @@ -95,10 +96,23 @@ public class BoxFunction extends GeometryFunction { * @since 2.0 */ public static final LanguageFeature FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_GEO, "BOX", true, "Express a box on the sky."); - /** The first coordinate of the center of this box. */ + /** Center position. + * <p><i><b>Note:</b> + * NULL, if both {@link #coord1} and {@link #coord2} are provided. + * </i></p> + * @since 2.0 */ + private GeometryValue<GeometryFunction> centerPoint; + + /** The first coordinate of the center of this box. + * <p><i><b>Note:</b> + * NULL, if {@link #centerPoint} is provided. + * </i></p> */ private ADQLOperand coord1; - /** The second coordinate of the center of this box. */ + /** The second coordinate of the center of this box. + * <p><i><b>Note:</b> + * NULL, if {@link #centerPoint} is provided. + * </i></p> */ private ADQLOperand coord2; /** The width of this box (in degrees). */ @@ -118,9 +132,11 @@ public class BoxFunction extends GeometryFunction { * box. * @param boxWidth The width of this box (in degrees). * @param boxHeight The height of this box (in degrees). + * * @throws NullPointerException If one parameter is NULL. * @throws Exception If there is another error. */ + @SuppressWarnings("deprecation") public BoxFunction(ADQLOperand coordinateSystem, ADQLOperand firstCoord, ADQLOperand secondCoord, ADQLOperand boxWidth, ADQLOperand boxHeight) throws NullPointerException, Exception { super(coordinateSystem); @@ -131,6 +147,35 @@ public class BoxFunction extends GeometryFunction { coord2 = secondCoord; width = boxWidth; height = boxHeight; + centerPoint = null; + } + + /** + * Builds a BOX function. + * + * @param coordinateSystem The coordinate system of the center + * position. + * @param center The center position. + * @param boxWidth The width of this box (in degrees). + * @param boxHeight The height of this box (in degrees). + * + * @throws NullPointerException If one parameter is NULL. + * @throws Exception If there is another error. + * + * @since 2.0 + */ + @SuppressWarnings("deprecation") + public BoxFunction(ADQLOperand coordinateSystem, GeometryValue<GeometryFunction> center, ADQLOperand boxWidth, ADQLOperand boxHeight) throws NullPointerException, Exception { + super(coordinateSystem); + + if (center == null || boxWidth == null || boxHeight == null) + throw new NullPointerException("All the parameters of the BOX function must be different from NULL!"); + + coord1 = null; + coord2 = null; + width = boxWidth; + height = boxHeight; + centerPoint = center; } /** @@ -139,12 +184,14 @@ public class BoxFunction extends GeometryFunction { * @param toCopy The BOX function to copy. * @throws Exception If there is an error during the copy. */ + @SuppressWarnings("unchecked") public BoxFunction(BoxFunction toCopy) throws Exception { super(toCopy); coord1 = (ADQLOperand)(toCopy.coord1.getCopy()); coord2 = (ADQLOperand)(toCopy.coord2.getCopy()); width = (ADQLOperand)(toCopy.width.getCopy()); height = (ADQLOperand)(toCopy.height.getCopy()); + centerPoint = (GeometryValue<GeometryFunction>)(toCopy.centerPoint.getCopy()); } @Override @@ -177,6 +224,42 @@ public class BoxFunction extends GeometryFunction { return true; } + /** + * Gets the center point, exactly as provided. + * + * <p><b>IMPORTANT NOTE:</b> + * If this {@link BoxFunction} has been initialized with a pair of + * coordinates, this function will return NULL. + * </p> + * + * @return The center point of the represented box, + * or NULL if created with a pair of coordinates. + * + * @since 2.0 + */ + public final GeometryValue<GeometryFunction> getCenter() { + return centerPoint; + } + + /** + * Sets the center point. + * + * <p><b>WARNING:</b> + * Calling this function will erase the single coordinates already set: + * {@link #getCoord1()} and {@link #getCoord2()} will both return NULL. + * </p> + * + * @param newCenter The new center point of the represented box. + * + * @since 2.0 + */ + public final void setCenter(final GeometryValue<GeometryFunction> newCenter) { + centerPoint = newCenter; + coord1 = null; + coord2 = null; + setPosition(null); + } + /** * Gets the first coordinate (i.e. right ascension). * @@ -254,34 +337,55 @@ public class BoxFunction extends GeometryFunction { } @Override + @SuppressWarnings("deprecation") public ADQLOperand[] getParameters() { - return new ADQLOperand[]{ coordSys, coord1, coord2, width, height }; + if (centerPoint == null) + return new ADQLOperand[]{ coordSys, coord1, coord2, width, height }; + else + return new ADQLOperand[]{ coordSys, centerPoint.getValue(), width, height }; } @Override public int getNbParameters() { - return 5; + return (centerPoint == null ? 5 : 4); } @Override + @SuppressWarnings("deprecation") public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException { - switch(index) { - case 0: - return coordSys; - case 1: - return coord1; - case 2: - return coord2; - case 3: - return width; - case 4: - return height; - default: - throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + if (centerPoint == null) { + switch(index) { + case 0: + return coordSys; + case 1: + return coord1; + case 2: + return coord2; + case 3: + return width; + case 4: + return height; + default: + throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + } + } else { + switch(index) { + case 0: + return coordSys; + case 1: + return centerPoint.getValue(); + case 2: + return width; + case 3: + return height; + default: + throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + } } } @Override + @SuppressWarnings({ "unchecked", "deprecation" }) public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception { if (replacer == null) throw new NullPointerException("Impossible to remove one parameter from a " + getName() + " function!"); @@ -289,31 +393,62 @@ public class BoxFunction extends GeometryFunction { throw new Exception("Impossible to replace an ADQLOperand by a " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!"); ADQLOperand replaced = null; - switch(index) { - case 0: - replaced = coordSys; - setCoordinateSystem(replacer); - break; - case 1: - replaced = coord1; - coord1 = replacer; - break; - case 2: - replaced = coord2; - coord2 = replacer; - break; - case 3: - replaced = width; - width = replacer; - break; - case 4: - replaced = height; - height = replacer; - break; - default: - throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + if (centerPoint == null) { + switch(index) { + case 0: + replaced = coordSys; + setCoordinateSystem(replacer); + break; + case 1: + replaced = coord1; + setCoord1(replacer); + break; + case 2: + replaced = coord2; + setCoord2(replacer); + break; + case 3: + replaced = width; + setWidth(replacer); + break; + case 4: + replaced = height; + setHeight(replacer); + break; + default: + throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + } + } else { + switch(index) { + case 0: + replaced = coordSys; + setCoordinateSystem(replacer); + break; + case 1: + replaced = centerPoint; + if (replacer instanceof GeometryValue) + setCenter((GeometryValue<GeometryFunction>)replacer); + else if (replaced instanceof ADQLColumn) + centerPoint.setColumn((ADQLColumn)replaced); + else if (replaced instanceof GeometryFunction) + centerPoint.setGeometry((GeometryFunction)replaced); + else if (replaced instanceof UserDefinedFunction) + centerPoint.setUDF((UserDefinedFunction)replaced); + else + throw new Exception("Impossible to replace a GeometryValue/Column/GeometryFunction/UDF by " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!"); + break; + case 2: + replaced = width; + setWidth(replacer); + break; + case 3: + replaced = height; + setHeight(replacer); + break; + default: + throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + } } - setPosition(null); return replaced; } diff --git a/src/adql/query/operand/function/geometry/CircleFunction.java b/src/adql/query/operand/function/geometry/CircleFunction.java index a03bb34bfd6d0f1a6b37c9630f56a9e943b4ce49..1f243dc375f9cbd9edd22fc8234d0b4dcc75d01d 100644 --- a/src/adql/query/operand/function/geometry/CircleFunction.java +++ b/src/adql/query/operand/function/geometry/CircleFunction.java @@ -16,13 +16,15 @@ package adql.query.operand.function.geometry; * 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-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ import adql.parser.feature.LanguageFeature; import adql.query.ADQLObject; +import adql.query.operand.ADQLColumn; import adql.query.operand.ADQLOperand; +import adql.query.operand.function.UserDefinedFunction; /** * It represents the CIRCLE function of the ADQL language. @@ -57,7 +59,7 @@ import adql.query.operand.ADQLOperand; * * <p> * The position argument may be a literal value, as above, or it may be a - * column reference, function or expression that returns a geometric type. + * column reference, function or expression that returns a POINT value. * </p> * * <i> @@ -77,7 +79,7 @@ import adql.query.operand.ADQLOperand; * </p> * * @author Grégory Mantelet (CDS;ARI) - * @version 2.0 (07/2019) + * @version 2.0 (06/2020) */ public class CircleFunction extends GeometryFunction { @@ -85,10 +87,23 @@ public class CircleFunction extends GeometryFunction { * @since 2.0 */ public static final LanguageFeature FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_GEO, "CIRCLE", true, "Express a circular region on the sky (i.e. a cone in space)."); - /** The first coordinate of the center position. */ + /** Center position. + * <p><i><b>Note:</b> + * NULL, if both {@link #coord1} and {@link #coord2} are provided. + * </i></p> + * @since 2.0 */ + private GeometryValue<GeometryFunction> centerPoint; + + /** The first coordinate of the center position. + * <p><i><b>Note:</b> + * NULL, if {@link #centerPoint} is provided. + * </i></p> */ private ADQLOperand coord1; - /** The second coordinate of the center position. */ + /** The second coordinate of the center position. + * <p><i><b>Note:</b> + * NULL, if {@link #centerPoint} is provided. + * </i></p> */ private ADQLOperand coord2; /** The radius of the circle (in degrees). */ @@ -107,6 +122,7 @@ public class CircleFunction extends GeometryFunction { * or if the coordinate system is unknown. * @throws Exception If there is another error. */ + @SuppressWarnings("deprecation") public CircleFunction(ADQLOperand coordinateSystem, ADQLOperand firstCoord, ADQLOperand secondCoord, ADQLOperand radius) throws NullPointerException, Exception { super(coordinateSystem); @@ -115,6 +131,33 @@ public class CircleFunction extends GeometryFunction { coord1 = firstCoord; coord2 = secondCoord; + centerPoint = null; + this.radius = radius; + } + + /** + * Builds a CIRCLE function. + * + * @param coordinateSystem The coordinate system in which the center + * position is expressed. + * @param center The center position. + * @param radius The radius of the circle (in degrees). + * @throws NullPointerException If at least one parameter is incorrect + * or if the coordinate system is unknown. + * @throws Exception If there is another error. + * + * @since 2.0 + */ + @SuppressWarnings("deprecation") + public CircleFunction(ADQLOperand coordinateSystem, GeometryValue<GeometryFunction> center, ADQLOperand radius) throws NullPointerException, Exception { + super(coordinateSystem); + + if (center == null || radius == null) + throw new NullPointerException("All parameters of a CIRCLE function must be different from NULL!"); + + coord1 = null; + coord2 = null; + centerPoint = center; this.radius = radius; } @@ -124,10 +167,12 @@ public class CircleFunction extends GeometryFunction { * @param toCopy The CIRCLE function to copy. * @throws Exception If there is an error during the copy. */ + @SuppressWarnings("unchecked") public CircleFunction(CircleFunction toCopy) throws Exception { super(toCopy); coord1 = (ADQLOperand)(toCopy.coord1.getCopy()); coord2 = (ADQLOperand)(toCopy.coord2.getCopy()); + centerPoint = (GeometryValue<GeometryFunction>)(toCopy.centerPoint.getCopy()); radius = (ADQLOperand)(toCopy.radius.getCopy()); } @@ -161,6 +206,42 @@ public class CircleFunction extends GeometryFunction { return true; } + /** + * Gets the center point, exactly as provided. + * + * <p><b>IMPORTANT NOTE:</b> + * If this {@link CircleFunction} has been initialized with a pair of + * coordinates, this function will return NULL. + * </p> + * + * @return The center point of the represented circle, + * or NULL if created with a pair of coordinates. + * + * @since 2.0 + */ + public final GeometryValue<GeometryFunction> getCenter() { + return centerPoint; + } + + /** + * Sets the center point. + * + * <p><b>WARNING:</b> + * Calling this function will erase the single coordinates already set: + * {@link #getCoord1()} and {@link #getCoord2()} will both return NULL. + * </p> + * + * @param newCenter The new center point of the represented circle. + * + * @since 2.0 + */ + public final void setCenter(final GeometryValue<GeometryFunction> newCenter) { + centerPoint = newCenter; + coord1 = null; + coord2 = null; + setPosition(null); + } + /** * Gets the first coordinate of the center (i.e. right ascension). * @@ -173,10 +254,16 @@ public class CircleFunction extends GeometryFunction { /** * Sets the first coordinate of the center (i.e. right ascension). * + * <p><b>WARNING:</b> + * Calling this function will erase the center point already set: + * {@link #getCenter()} will return NULL. + * </p> + * * @param coord1 The first coordinate. */ public final void setCoord1(ADQLOperand coord1) { this.coord1 = coord1; + centerPoint = null; setPosition(null); } @@ -196,6 +283,7 @@ public class CircleFunction extends GeometryFunction { */ public final void setCoord2(ADQLOperand coord2) { this.coord2 = coord2; + centerPoint = null; setPosition(null); } @@ -219,58 +307,104 @@ public class CircleFunction extends GeometryFunction { } @Override + @SuppressWarnings("deprecation") public ADQLOperand[] getParameters() { - return new ADQLOperand[]{ coordSys, coord1, coord2, radius }; + if (centerPoint == null) + return new ADQLOperand[]{ coordSys, coord1, coord2, radius }; + else + return new ADQLOperand[]{ coordSys, centerPoint.getValue(), radius }; } @Override public int getNbParameters() { - return 4; + return (centerPoint == null ? 4 : 3); } @Override + @SuppressWarnings("deprecation") public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException { - switch(index) { - case 0: - return coordSys; - case 1: - return coord1; - case 2: - return coord2; - case 3: - return radius; - default: - throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + if (centerPoint == null) { + switch(index) { + case 0: + return coordSys; + case 1: + return coord1; + case 2: + return coord2; + case 3: + return radius; + default: + throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + } + } else { + switch(index) { + case 0: + return coordSys; + case 1: + return centerPoint.getValue(); + case 2: + return radius; + default: + throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + } } } @Override + @SuppressWarnings({ "unchecked", "deprecation" }) public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception { if (replacer == null) throw new NullPointerException("Impossible to remove one parameter of a " + getName() + " function!"); ADQLOperand replaced = null; - switch(index) { - case 0: - replaced = coordSys; - setCoordinateSystem(replacer); - break; - case 1: - replaced = coord1; - coord1 = replacer; - break; - case 2: - replaced = coord2; - coord2 = replacer; - break; - case 3: - replaced = radius; - radius = replacer; - break; - default: - throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + if (centerPoint == null) { + switch(index) { + case 0: + replaced = coordSys; + setCoordinateSystem(replacer); + break; + case 1: + replaced = coord1; + setCoord1(replacer); + break; + case 2: + replaced = coord2; + setCoord2(replacer); + break; + case 3: + replaced = radius; + setRadius(replacer); + break; + default: + throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + } + } else { + switch(index) { + case 0: + replaced = coordSys; + setCoordinateSystem(replacer); + break; + case 1: + replaced = centerPoint.getValue(); + if (replacer instanceof GeometryValue) + setCenter((GeometryValue<GeometryFunction>)replacer); + else if (replaced instanceof ADQLColumn) + centerPoint.setColumn((ADQLColumn)replaced); + else if (replaced instanceof GeometryFunction) + centerPoint.setGeometry((GeometryFunction)replaced); + else if (replaced instanceof UserDefinedFunction) + centerPoint.setUDF((UserDefinedFunction)replaced); + else + throw new Exception("Impossible to replace a GeometryValue/Column/GeometryFunction/UDF by " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!"); + break; + case 2: + replaced = radius; + setRadius(replacer); + break; + default: + throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); + } } - setPosition(null); return replaced; } diff --git a/src/adql/query/operand/function/geometry/DistanceFunction.java b/src/adql/query/operand/function/geometry/DistanceFunction.java index 1065340831284fb9894d24b0c76d60bc875027cd..e1cc8e0e1ed83c84d80be011cd8a5a57447ee517 100644 --- a/src/adql/query/operand/function/geometry/DistanceFunction.java +++ b/src/adql/query/operand/function/geometry/DistanceFunction.java @@ -24,6 +24,7 @@ import adql.parser.feature.LanguageFeature; import adql.query.ADQLObject; import adql.query.operand.ADQLColumn; import adql.query.operand.ADQLOperand; +import adql.query.operand.function.UserDefinedFunction; /** * It represents the DISTANCE function of the ADQL language. @@ -231,9 +232,9 @@ public class DistanceFunction extends GeometryFunction { public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException { switch(index) { case 0: - return p1.getValue(); + return p1; case 1: - return p2.getValue(); + return p2; default: throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + getName() + "\"!"); } @@ -244,8 +245,8 @@ public class DistanceFunction extends GeometryFunction { public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception { if (replacer == null) throw new NullPointerException("Impossible to remove a parameter from the function " + getName() + "!"); - else if (!(replacer instanceof GeometryValue || replacer instanceof ADQLColumn || replacer instanceof GeometryFunction)) - throw new Exception("Impossible to replace a GeometryValue/Column/GeometryFunction by " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!"); + else if (!(replacer instanceof GeometryValue || replacer instanceof ADQLColumn || replacer instanceof GeometryFunction || replacer instanceof UserDefinedFunction)) + throw new Exception("Impossible to replace a GeometryValue/Column/GeometryFunction/UDF by " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!"); ADQLOperand replaced = null; GeometryValue<GeometryFunction> toUpdate = null; @@ -273,6 +274,8 @@ public class DistanceFunction extends GeometryFunction { toUpdate.setColumn((ADQLColumn)replacer); else if (replacer instanceof GeometryFunction) toUpdate.setGeometry((GeometryFunction)replacer); + else if (replacer instanceof UserDefinedFunction) + toUpdate.setUDF((UserDefinedFunction)replacer); } setPosition(null); diff --git a/src/adql/query/operand/function/geometry/GeometryFunction.java b/src/adql/query/operand/function/geometry/GeometryFunction.java index 629cf85ae2af0313c89f53d24a7d836afa0bc98d..88ca95f2e2b479b98b20fa1ba73e63689b74b6b1 100644 --- a/src/adql/query/operand/function/geometry/GeometryFunction.java +++ b/src/adql/query/operand/function/geometry/GeometryFunction.java @@ -34,12 +34,21 @@ import adql.query.operand.function.UserDefinedFunction; /** * It represents any geometric function of ADQL. * + * <p> + * For historical reasons, the geometry regions accept an optional string value + * as the first argument. As of this version of the specification (2.1) this + * parameter has been marked as deprecated. Future versions of this + * specification (>2.1) may remove this parameter. + * </p> + * * @author Grégory Mantelet (CDS;ARI) - * @version 1.4 (06/2015) + * @version 2.0 (06/2020) */ public abstract class GeometryFunction extends ADQLFunction { - /** The coordinate system used to express the coordinates. */ + /** The coordinate system used to express the coordinates. + * @deprecated Since ADQL-2.1. */ + @Deprecated protected ADQLOperand coordSys = null; /** @@ -61,7 +70,10 @@ public abstract class GeometryFunction extends ADQLFunction { * @throws NullPointerException If the given operand is NULL. * @throws Exception If the given operand is not a * string. + * + * @deprecated Since ADQL-2.1, the coordinate system argument is deprecated. */ + @Deprecated protected GeometryFunction(ADQLOperand coordSys) throws UnsupportedOperationException, NullPointerException, Exception { setCoordinateSystem(coordSys); } @@ -81,7 +93,10 @@ public abstract class GeometryFunction extends ADQLFunction { * Gets the used coordinate system. * * @return Its coordinate system. + * + * @deprecated Since ADQL-2.1. */ + @Deprecated public ADQLOperand getCoordinateSystem() { return coordSys; } @@ -96,7 +111,10 @@ public abstract class GeometryFunction extends ADQLFunction { * @throws NullPointerException If the given operand is NULL. * @throws ParseException If the given operand is not a * string. + * + * @deprecated Since ADQL-2.1. */ + @Deprecated public void setCoordinateSystem(ADQLOperand coordSys) throws UnsupportedOperationException, NullPointerException, ParseException { if (coordSys == null) this.coordSys = new StringConstant(""); diff --git a/src/adql/query/operand/function/geometry/PointFunction.java b/src/adql/query/operand/function/geometry/PointFunction.java index 7ea1a70167f76d9f9842177739ed4c4b3b14b6da..1a06a79326a588229ae09f20c4071237be59ccdc 100644 --- a/src/adql/query/operand/function/geometry/PointFunction.java +++ b/src/adql/query/operand/function/geometry/PointFunction.java @@ -71,7 +71,7 @@ import adql.query.operand.ADQLOperand; * </p> * * @author Grégory Mantelet (CDS;ARI) - * @version 2.0 (07/2019) + * @version 2.0 (06/2020) */ public class PointFunction extends GeometryFunction { @@ -98,6 +98,7 @@ public class PointFunction extends GeometryFunction { * @throws ParseException If at least one of the given * parameters is incorrect. */ + @SuppressWarnings("deprecation") public PointFunction(ADQLOperand coordinateSystem, ADQLOperand firstCoord, ADQLOperand secondCoord) throws UnsupportedOperationException, NullPointerException, Exception { super(coordinateSystem); @@ -204,6 +205,7 @@ public class PointFunction extends GeometryFunction { return true; } + @SuppressWarnings("deprecation") @Override public ADQLOperand[] getParameters() { return new ADQLOperand[]{ coordSys, coord1, coord2 }; @@ -215,6 +217,7 @@ public class PointFunction extends GeometryFunction { } @Override + @SuppressWarnings("deprecation") public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException { switch(index) { case 0: @@ -229,6 +232,7 @@ public class PointFunction extends GeometryFunction { } @Override + @SuppressWarnings("deprecation") public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception { if (replacer == null) throw new NullPointerException("Impossible to remove a parameter from the function " + getName() + "!"); diff --git a/src/adql/query/operand/function/geometry/PolygonFunction.java b/src/adql/query/operand/function/geometry/PolygonFunction.java index 61fac169830526faf04a16347d110897ca8abc81..b9bc8eeb93cf85712a509147fd43eb55ce300a4d 100644 --- a/src/adql/query/operand/function/geometry/PolygonFunction.java +++ b/src/adql/query/operand/function/geometry/PolygonFunction.java @@ -16,11 +16,12 @@ package adql.query.operand.function.geometry; * 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-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ import java.util.Collection; +import java.util.Iterator; import java.util.Vector; import adql.parser.feature.LanguageFeature; @@ -32,7 +33,7 @@ import adql.query.operand.ADQLOperand; * * <p> * This function expresses a region on the sky with boundaries denoted by great - * circles passing through specified coordinates. It corresponds semantically + * circles passing through specified vertices. It corresponds semantically * to the STC Polygon. * </p> * @@ -58,6 +59,8 @@ import adql.query.operand.ADQLOperand; * </p> * <pre>POLYGON(10.0, -10.5, 20.0, 20.5, 30.0, 30.5)</pre> * <p>, where all numeric values are in degrees.</p> + * <p>or alternatively as follows:</p> + * <pre>POLYGON(POINT(10.0, -10.5), POINT(20.0, 20.5), POINT(30.0, 30.5))</pre> * </i> * * <p> @@ -103,7 +106,7 @@ import adql.query.operand.ADQLOperand; * </p> * * @author Grégory Mantelet (CDS;ARI) - * @version 2.0 (07/2019) + * @version 2.0 (06/2020) */ public class PolygonFunction extends GeometryFunction { @@ -111,7 +114,7 @@ public class PolygonFunction extends GeometryFunction { * @since 2.0 */ public static final LanguageFeature FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_GEO, "POLYGON", true, "Express a region on the sky with boundaries denoted by great circles passing through specified coordinates."); - /** The coordinates of vertices. */ + /** The vertices. */ protected Vector<ADQLOperand> coordinates; /** @@ -131,6 +134,7 @@ public class PolygonFunction extends GeometryFunction { * NULL. * @throws Exception If there is another error. */ + @SuppressWarnings("deprecation") public PolygonFunction(ADQLOperand coordSystem, ADQLOperand[] coords) throws UnsupportedOperationException, NullPointerException, Exception { super(coordSystem); if (coords == null || coords.length < 6) @@ -143,14 +147,18 @@ public class PolygonFunction extends GeometryFunction { } /** - * Builds a polygon function with at least 3 2-D coordinates (that is to - * say, the vector must contain at least 6 operands). + * Builds a polygon function with at least: + * + * <ul> + * <li>3 pairs of coordinates (that is to say, the vector must contain at + * least 6 items),</li> + * <li>OR 3 point values (so, a vector containing at least 3 items).</li> + * </ul> * * @param coordSystem A string operand which * corresponds to a valid * coordinate system. - * @param coords A vector of at least 3 2-D - * coordinates (size()>=6). + * @param coords A vector of at least 3 vertices. * * @throws UnsupportedOperationException If this function is not * associated with a coordinate @@ -159,10 +167,16 @@ public class PolygonFunction extends GeometryFunction { * NULL. * @throws Exception If there is another error. */ + @SuppressWarnings("deprecation") public PolygonFunction(ADQLOperand coordSystem, Collection<? extends ADQLOperand> coords) throws UnsupportedOperationException, NullPointerException, Exception { super(coordSystem); - if (coords == null || coords.size() < 6) - throw new NullPointerException("A POLYGON function must have at least 3 2-D coordinates!"); + if (coords == null) + throw new NullPointerException("A POLYGON function must have vertices!"); + + Iterator<?> itCoords = coords.iterator(); + Object firstItem = (itCoords.hasNext() ? itCoords.next() : null); + if (firstItem == null || (firstItem instanceof GeometryValue<?> && coords.size() < 3) || (!(firstItem instanceof GeometryValue<?>) && coords.size() < 6)) + throw new NullPointerException("A POLYGON function must have at least 3 vertices (i.e. 3 points or 3 pairs of coordinates)!"); else { coordinates = new Vector<ADQLOperand>(coords.size()); coordinates.addAll(coords); @@ -213,6 +227,7 @@ public class PolygonFunction extends GeometryFunction { } @Override + @SuppressWarnings("deprecation") public ADQLOperand[] getParameters() { ADQLOperand[] params = new ADQLOperand[coordinates.size() + 1]; @@ -229,6 +244,7 @@ public class PolygonFunction extends GeometryFunction { } @Override + @SuppressWarnings("deprecation") public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException { if (index == 0) return coordSys; @@ -239,6 +255,7 @@ public class PolygonFunction extends GeometryFunction { } @Override + @SuppressWarnings("deprecation") public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception { if (replacer == null) throw new NullPointerException("Impossible to remove only one parameter from the function POLYGON!"); diff --git a/src/adql/translator/PgSphereTranslator.java b/src/adql/translator/PgSphereTranslator.java index 360b57c2fa67c9547d08c2399a45406839e3bf0c..ea09378fccccd2c9b4092db54e52f9c83b12b3b5 100644 --- a/src/adql/translator/PgSphereTranslator.java +++ b/src/adql/translator/PgSphereTranslator.java @@ -16,7 +16,7 @@ package adql.translator; * 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-2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2020 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -62,7 +62,7 @@ import adql.query.operand.function.geometry.PolygonFunction; * </i></p> * * @author Grégory Mantelet (CDS;ARI) - * @version 2.0 (08/2019) + * @version 2.0 (06/2020) */ public class PgSphereTranslator extends PostgreSQLTranslator { @@ -243,17 +243,17 @@ public class PgSphereTranslator extends PostgreSQLTranslator { } try { // build the CIRCLE to use in the artificial CONTAINS: - CircleFunction circleFct = new CircleFunction(new StringConstant(""), ((PointFunction)distFct.getParameter(1)).getCoord1(), ((PointFunction)distFct.getParameter(1)).getCoord2(), numericOperand); + CircleFunction circleFct = new CircleFunction(new StringConstant(""), ((PointFunction)distFct.getP2().getValue()).getCoord1(), ((PointFunction)distFct.getP2().getValue()).getCoord2(), numericOperand); // adapt the translation in function of the comp. operator: switch(comp.getOperator()) { case LESS_THAN: - return "((" + translate(distFct.getParameter(0)) + " @ " + translate(circleFct) + ") = '1' AND " + super.translate(comp) + ")"; + return "((" + translate(distFct.getP1()) + " @ " + translate(circleFct) + ") = '1' AND " + super.translate(comp) + ")"; case LESS_OR_EQUAL: - return "((" + translate(distFct.getParameter(0)) + " @ " + translate(circleFct) + ") = '1'" + ")"; + return "((" + translate(distFct.getP1()) + " @ " + translate(circleFct) + ") = '1'" + ")"; case GREATER_THAN: - return "((" + translate(distFct.getParameter(0)) + " @ " + translate(circleFct) + ") = '0' AND " + super.translate(comp) + ")"; + return "((" + translate(distFct.getP1()) + " @ " + translate(circleFct) + ") = '0' AND " + super.translate(comp) + ")"; case GREATER_OR_EQUAL: - return "((" + translate(distFct.getParameter(0)) + " @ " + translate(circleFct) + ") = '0'" + ")"; + return "((" + translate(distFct.getP1()) + " @ " + translate(circleFct) + ") = '0'" + ")"; default: // theoretically, this case never happens! return super.translate(comp); } diff --git a/test/adql/parser/TestADQLParser.java b/test/adql/parser/TestADQLParser.java index 2a449963c626b14649029aaf1ae497ea4daa5d58..b6883386b203d8681111d0bb07338f415c38519e 100644 --- a/test/adql/parser/TestADQLParser.java +++ b/test/adql/parser/TestADQLParser.java @@ -870,10 +870,12 @@ public class TestADQLParser { } @Test - public void testGeometryWithNoCooSys() { + public void testGeometryWithOptionalArgs() { /* * NOTE: * Since ADQL-2.1, the coordinate system argument becomes optional. + * Besides, BOX, CIRCLE and POLYGON can now accept POINTs instead of + * pairs of coordinates. */ ADQLParser parser = new ADQLParser(ADQLVersion.V2_1); @@ -881,21 +883,32 @@ public class TestADQLParser { // CASE: with no coordinate system => equivalent to coosys = '' try { assertEquals("POINT('', 1, 2)", parser.parseSelect("SELECT POINT(1, 2)").get(0).toADQL()); + assertEquals("CIRCLE('', 1, 2, 3)", parser.parseSelect("SELECT CIRCLE(1, 2, 3)").get(0).toADQL()); + assertEquals("CIRCLE('', POINT('', 1, 2), 3)", parser.parseSelect("SELECT CIRCLE(POINT(1,2), 3)").get(0).toADQL()); + assertEquals("CIRCLE('', colCenter, 3)", parser.parseSelect("SELECT CIRCLE(colCenter, 3)").get(0).toADQL()); + assertEquals("BOX('', 1, 2, 3, 4)", parser.parseSelect("SELECT BOX(1, 2, 3, 4)").get(0).toADQL()); + assertEquals("BOX('', POINT('', 1, 2), 3, 4)", parser.parseSelect("SELECT BOX(POINT(1, 2), 3, 4)").get(0).toADQL()); + assertEquals("BOX('', colCenter, 3, 4)", parser.parseSelect("SELECT BOX(colCenter, 3, 4)").get(0).toADQL()); + assertEquals("POLYGON('', 1, 2, 3, 4, 5, 6)", parser.parseSelect("SELECT POLYGON(1, 2, 3, 4, 5, 6)").get(0).toADQL()); + assertEquals("POLYGON('', POINT('', 1, 2), POINT('', 3, 4), POINT('', 5, 6))", parser.parseSelect("SELECT POLYGON(POINT(1, 2), POINT(3, 4), POINT(5, 6))").get(0).toADQL()); + assertEquals("POLYGON('', point1, point2, point3)", parser.parseSelect("SELECT POLYGON(point1, point2, point3)").get(0).toADQL()); } catch(Exception ex) { ex.printStackTrace(); fail("Unexpected error! All parsed geometries are correct."); } - // CASE: ambiguity with POLYGON and a wrong nb of arguments - try { - assertEquals("POLYGON(ra, dec, 3, 4, 5, 6, 7)", parser.parseSelect("SELECT POLYGON(ra, dec, 3, 4, 5, 6, 7)").get(0).toADQL()); - } catch(Exception ex) { - ex.printStackTrace(); - fail("Unexpected error! All parsed geometries are \"correct\"."); - } + // CASE: wrong nb of arguments for POLYGON + for(String wrongQuery : new String[]{ "SELECT POLYGON(ra, dec, 3, 4, 5)", "SELECT POLYGON(ra, dec, 3, 4, 5, 6, 7)", "SELECT POLYGON(p1, p2)" }) + try { + parser.parseSelect(wrongQuery); + fail("Impossible to create a POLYGON with an incomplete list of vertices! The last point is missing or incomplete."); + } catch(Exception ex) { + assertEquals(ParseException.class, ex.getClass()); + assertTrue(ex.getMessage().trim().startsWith("Encountered \")\".")); + } } @Test @@ -904,6 +917,22 @@ public class TestADQLParser { // DECLARE A SIMPLE PARSER where all coordinate systems are allowed by default: ADQLParser parser = new ADQLParser(version); + // A coordinate system MUST be a string literal: + try { + assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT('From ' || 'here', 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;")); + fail("A coordinate system can NOT be a string concatenation!"); + } catch(ParseException pe) { + assertEquals(ParseException.class, pe.getClass()); + assertEquals(48, pe.getPosition().beginColumn); + } + try { + assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT(aColumn, 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;")); + fail("A coordinate system can NOT be a column reference!"); + } catch(ParseException pe) { + assertEquals(ParseException.class, pe.getClass()); + assertEquals((version == ADQLVersion.V2_0 ? 40 : 53), pe.getPosition().beginColumn); + } + // Test with several coordinate systems while all are allowed: try { assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT('', 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;")); @@ -919,14 +948,6 @@ public class TestADQLParser { fail("This query contains several valid coordinate systems, and all are theoretically allowed: this test should have succeeded!"); } - // Concatenation as coordinate systems not checked: - try { - assertNotNull(parser.parseQuery("SELECT * FROM foo WHERE CONTAINS(POINT('From ' || 'here', 12.3, 45.6), CIRCLE('', 1.2, 2.3, 5)) = 1;")); - } catch(ParseException pe) { - pe.printStackTrace(); - fail("This query contains a concatenation as coordinate systems (but only string constants are checked): this test should have succeeded!"); - } - // Test with several coordinate systems while only some allowed: try { parser = new ADQLParser(version);