diff --git a/src/adql/query/operand/function/geometry/CentroidFunction.java b/src/adql/query/operand/function/geometry/CentroidFunction.java index 23a2b7852972ed5df64646e54739db87b29842b0..049d9c38ecf2d889b8503dbd7d3b2bb0df729b4c 100644 --- a/src/adql/query/operand/function/geometry/CentroidFunction.java +++ b/src/adql/query/operand/function/geometry/CentroidFunction.java @@ -16,7 +16,7 @@ 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-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -36,7 +36,7 @@ import adql.query.operand.ADQLOperand; * </i></p> * * @author Grégory Mantelet (CDS;ARI) - * @version 1.4 (06/2015) + * @version 1.4 (02/2017) */ public class CentroidFunction extends GeometryFunction { @@ -80,7 +80,7 @@ public class CentroidFunction extends GeometryFunction { @Override public boolean isNumeric(){ - return true; + return false; } @Override @@ -90,7 +90,7 @@ public class CentroidFunction extends GeometryFunction { @Override public boolean isGeometry(){ - return false; + return true; } @Override diff --git a/src/adql/translator/PgSphereTranslator.java b/src/adql/translator/PgSphereTranslator.java index 6474ab34bea48921ee21b66dba4c853b8ac00732..358d79d79f20814dee9f4ee92f879e5ae63d0c6b 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-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2017 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -34,6 +34,7 @@ import adql.query.constraint.Comparison; 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; import adql.query.operand.function.geometry.CircleFunction; import adql.query.operand.function.geometry.ContainsFunction; import adql.query.operand.function.geometry.DistanceFunction; @@ -48,7 +49,7 @@ import adql.query.operand.function.geometry.PolygonFunction; * The other functions are managed by {@link PostgreSQLTranslator}.</p> * * @author Grégory Mantelet (CDS;ARI) - * @version 1.4 (07/2015) + * @version 1.4 (07/2017) */ public class PgSphereTranslator extends PostgreSQLTranslator { @@ -72,7 +73,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { * Builds a PgSphereTranslator which always translates in SQL all identifiers (schema, table and column) in the specified case sensitivity ; * in other words, schema, table and column names will all be surrounded or not by double quotes in the SQL translation. * - * @param allCaseSensitive <i>true</i> to translate all identifiers in a case sensitive manner (surrounded by double quotes), <i>false</i> for case insensitivity. + * @param allCaseSensitive <i>true</i> to translate all identifiers in a case sensitive manner (surrounded by double quotes), <i>false</i> for case insensitivity. * * @see PostgreSQLTranslator#PostgreSQLTranslator(boolean) */ @@ -174,6 +175,13 @@ public class PgSphereTranslator extends PostgreSQLTranslator { return str.toString(); } + @Override + public String translate(CentroidFunction centroidFunction) throws TranslationException{ + StringBuffer str = new StringBuffer("center("); + str.append(translate(centroidFunction.getParameter(0))).append(")"); + return str.toString(); + } + @Override public String translate(ContainsFunction fct) throws TranslationException{ StringBuffer str = new StringBuffer("("); @@ -245,7 +253,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { String objType = pgo.getType().toLowerCase(); String geomStr = pgo.getValue(); - /* Only spoint, scircle, sbox and spoly are supported ; + /* Only spoint, scircle, sbox and spoly are supported ; * these geometries are parsed and transformed in Region instances:*/ if (objType.equals("spoint")) return (new PgSphereGeometryParser()).parsePoint(geomStr); @@ -434,7 +442,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { * Finalize the parsing. * No more characters (except eventually some space characters) should remain in the PgSphere expression to parse. * - * @throws ParseException If other non-space characters remains. + * @throws ParseException If other non-space characters remains. */ private void end() throws ParseException{ // Skip all spaces: @@ -451,7 +459,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { } /** - * Tool function which skips all next space characters until the next meaningful characters. + * Tool function which skips all next space characters until the next meaningful characters. */ private void skipSpaces(){ while(pos < expr.length() && Character.isWhitespace(expr.charAt(pos))) @@ -555,7 +563,7 @@ public class PgSphereTranslator extends PostgreSQLTranslator { } /** - * Internal spoint parsing function. It parses the PgSphere expression stored in this parser as a point. + * Internal spoint parsing function. It parses the PgSphere expression stored in this parser as a point. * * @return The ra and dec coordinates (in degrees) of the parsed point. * @@ -624,7 +632,8 @@ public class PgSphereTranslator extends PostgreSQLTranslator { end(); // Build the STC Box region: - double width = Math.abs(northeast[0] - southwest[0]), height = Math.abs(northeast[1] - southwest[1]); + double width = Math.abs(northeast[0] - southwest[0]), + height = Math.abs(northeast[1] - southwest[1]); double[] center = new double[]{northeast[0] - width / 2,northeast[1] - height / 2}; return new Region(null, center, width, height); } diff --git a/src/tap/data/ResultSetTableIterator.java b/src/tap/data/ResultSetTableIterator.java index 0f2e10ccd558ca2a106de381b3a8521050537187..487dde7c3810c3f5543e983ddd4aa821db8d3cf0 100644 --- a/src/tap/data/ResultSetTableIterator.java +++ b/src/tap/data/ResultSetTableIterator.java @@ -16,13 +16,16 @@ package tap.data; * You should have received a copy of the GNU Lesser General Public License * along with TAPLibrary. If not, see <http://www.gnu.org/licenses/>. * - * Copyright 2014-2016 - Astronomisches Rechen Institut (ARI) + * Copyright 2014-2017 - Astronomisches Rechen Institut (ARI) */ +import java.sql.Date; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.sql.Time; import java.sql.Timestamp; +import java.text.SimpleDateFormat; import java.util.NoSuchElementException; import adql.db.DBColumn; @@ -43,7 +46,7 @@ import uws.ISO8601Format; * </i></p> * * @author Grégory Mantelet (ARI) - * @version 2.1 (09/2016) + * @version 2.1 (02/2017) * @since 2.0 */ public class ResultSetTableIterator implements TableIterator { @@ -73,6 +76,11 @@ public class ResultSetTableIterator implements TableIterator { /** Index of the last read column (=0 just after {@link #nextRow()} and before {@link #nextCol()}, ={@link #nbColumns} after the last column has been read). */ private int colIndex; + /** Formatter to use in order to format java.sql.Date values. */ + private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + /** Formatter to use in order to format java.sql.Time values. */ + private static SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); + /** * <p>Build a TableIterator able to read rows and columns of the given ResultSet.</p> * @@ -687,7 +695,7 @@ public class ResultSetTableIterator implements TableIterator { * * <p>By default, the following function performs the following formatting:</p> * <ul> - * <li><b>If {@link Timestamp}:</b> the date-time is converted into a string with the ISO8601 format (see {@link ISO8601Format}).</li> + * <li><b>If {@link Timestamp}, {@link Date} or {@link Time}:</b> the date-time is converted into a string with the ISO8601 format (see {@link ISO8601Format}).</li> * <li><b>If a single CHAR is declared and a String is given:</b> only the first character is returned as a {@link Character} object.</li> * <li><b>If the value is declared as a Geometry:</b> the geometry is formatted as a STC-S expression.</li> * </ul> @@ -703,9 +711,16 @@ public class ResultSetTableIterator implements TableIterator { protected Object formatColValue(Object colValue) throws DataReadException{ if (colValue != null){ DBType colType = getColType(); - // if the column value is a Timestamp object, format it in ISO8601: - if (colValue instanceof Timestamp) - colValue = ISO8601Format.format(((Timestamp)colValue).getTime()); + // if the column value is a java.sql.Time object, format it into an ISO8601 time (i.e. with the format: HH:mm:ss): + if (colValue instanceof java.sql.Time) + colValue = timeFormat.format((java.sql.Time)colValue); + // if the column value is a java.sql.Date object, format it into an ISO8601 date (i.e. with the format: yyyy-MM-dd): + else if (colValue instanceof java.sql.Date) + colValue = dateFormat.format((java.sql.Date)colValue); + // if the column value is a Timestamp (or java.util.Date) object, format it into an ISO8601 date-time: + // note: java.sql.Timestamp extends java.util.Date. That's why the next condition also works for java.sql.Timestamp. + else if (colValue instanceof java.util.Date) + colValue = ISO8601Format.format((java.util.Date)colValue); // if the type is Integer but it is declared as a SMALLINT cast the value (absolutely required for the FITS format): else if (colValue instanceof Integer && colType != null && colValue != null && colType.type == DBDatatype.SMALLINT) colValue = new Short(((Integer)colValue).shortValue()); diff --git a/test/adql/query/operand/function/geometry/TestCentroidFunction.java b/test/adql/query/operand/function/geometry/TestCentroidFunction.java new file mode 100644 index 0000000000000000000000000000000000000000..ee1795015d8e2895a11b568f3734265182f3f01c --- /dev/null +++ b/test/adql/query/operand/function/geometry/TestCentroidFunction.java @@ -0,0 +1,28 @@ +package adql.query.operand.function.geometry; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; + +import adql.query.operand.NumericConstant; +import adql.query.operand.StringConstant; +import adql.query.operand.function.geometry.GeometryFunction.GeometryValue; + +public class TestCentroidFunction { + + @Test + public void testIsGeometry(){ + try{ + CentroidFunction centfc = new CentroidFunction(new GeometryValue<GeometryFunction>(new CircleFunction(new StringConstant("ICRS"), new NumericConstant(128.23), new NumericConstant(0.53), new NumericConstant(2)))); + assertTrue(centfc.isGeometry()); + assertFalse(centfc.isNumeric()); + assertFalse(centfc.isString()); + }catch(Throwable t){ + t.printStackTrace(System.err); + fail("An error occured while building a simple CentroidFunction! (see the console for more details)"); + } + } + +} diff --git a/test/adql/translator/TestPgSphereTranslator.java b/test/adql/translator/TestPgSphereTranslator.java index 2f34471fc7be78303a7945fee526c63fb425e71f..346ed8057c2558b1aa57ef828d04e55872fd19c6 100644 --- a/test/adql/translator/TestPgSphereTranslator.java +++ b/test/adql/translator/TestPgSphereTranslator.java @@ -19,6 +19,12 @@ import adql.db.DBType; import adql.db.DBType.DBDatatype; import adql.db.STCS.Region; import adql.parser.ParseException; +import adql.query.operand.NumericConstant; +import adql.query.operand.StringConstant; +import adql.query.operand.function.geometry.CentroidFunction; +import adql.query.operand.function.geometry.CircleFunction; +import adql.query.operand.function.geometry.GeometryFunction; +import adql.query.operand.function.geometry.GeometryFunction.GeometryValue; public class TestPgSphereTranslator { @@ -34,6 +40,18 @@ public class TestPgSphereTranslator { @After public void tearDown() throws Exception{} + @Test + public void testTranslateCentroidFunction(){ + try{ + PgSphereTranslator translator = new PgSphereTranslator(); + CentroidFunction centfc = new CentroidFunction(new GeometryValue<GeometryFunction>(new CircleFunction(new StringConstant("ICRS"), new NumericConstant(128.23), new NumericConstant(0.53), new NumericConstant(2)))); + assertEquals("center(scircle(spoint(radians(128.23),radians(0.53)),radians(2)))", translator.translate(centfc)); + }catch(Throwable t){ + t.printStackTrace(System.err); + fail("An error occured while building a simple CentroidFunction! (see the console for more details)"); + } + } + @Test public void testConvertTypeFromDB(){ PgSphereTranslator translator = new PgSphereTranslator(); diff --git a/test/tap/data/ResultSetTableIteratorTest.java b/test/tap/data/ResultSetTableIteratorTest.java index bc7891760d5eb4396c54fe60984aa03e25fb10a5..65019ccd119156367a7c75f3426c2847efa0b813 100644 --- a/test/tap/data/ResultSetTableIteratorTest.java +++ b/test/tap/data/ResultSetTableIteratorTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.fail; import java.sql.Connection; import java.sql.ResultSet; +import java.util.GregorianCalendar; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -64,7 +65,7 @@ public class ResultSetTableIteratorTest { // TEST that all columns have been read: assertEquals(expectedNbColumns, countColumns); } - // TEST that all lines have been read: + // TEST that all lines have been read: assertEquals(expectedNbLines, countLines); }catch(Exception ex){ @@ -92,7 +93,7 @@ public class ResultSetTableIteratorTest { // count lines: while(it.nextRow()) countLines++; - // TEST that no line has been read: + // TEST that no line has been read: assertEquals(countLines, 0); }catch(Exception ex){ @@ -124,4 +125,44 @@ public class ResultSetTableIteratorTest { assertEquals(ex.getClass().getName(), "tap.data.DataReadException"); } } + + @Test + public void testDateFormat(){ + ResultSet rs = null; + try{ + // create a valid ResultSet: + rs = DBTools.select(conn, "SELECT * FROM gums LIMIT 1;"); + + // Create the iterator: + ResultSetTableIterator rsit = new ResultSetTableIterator(rs); + assertTrue(rsit.nextRow()); + assertTrue(rsit.hasNextCol()); + rsit.nextCol(); + + // Set a date-time: + GregorianCalendar cal = new GregorianCalendar(); + cal.set(2017, GregorianCalendar.FEBRUARY, 1, 15, 13, 56); // 1st Feb. 2017 - 15:13:56 CET + + // Try to format it from a java.SQL.Timestamp into a ISO8601 date-time: + assertEquals("2017-02-01T14:13:56Z", rsit.formatColValue(new java.sql.Timestamp(cal.getTimeInMillis()))); + // Try to format it from a java.UTIL.Date into an ISO8601 date-time: + assertEquals("2017-02-01T14:13:56Z", rsit.formatColValue(cal.getTime())); + + // Try to format it from a java.SQL.Date into a simple date (no time indication): + assertEquals("2017-02-01", rsit.formatColValue(new java.sql.Date(cal.getTimeInMillis()))); + + // Try to format it into a simple time (no date indication): + assertEquals("15:13:56", rsit.formatColValue(new java.sql.Time(cal.getTimeInMillis()))); + + }catch(Exception ex){ + ex.printStackTrace(System.err); + fail("An exception occurs while formatting dates/times."); + }finally{ + if (rs != null){ + try{ + rs.close(); + }catch(Exception ex){} + } + } + } }