diff --git a/src/tap/data/ResultSetTableIterator.java b/src/tap/data/ResultSetTableIterator.java index 9325771b0b8485072ed052938c0554a7b2f72f94..ae2fd1d41b02b9ca2bc8a8b28683d5d893026ae0 100644 --- a/src/tap/data/ResultSetTableIterator.java +++ b/src/tap/data/ResultSetTableIterator.java @@ -24,10 +24,14 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.NoSuchElementException; +import tap.db.JDBCTAPFactory; +import tap.metadata.TAPColumn; +import tap.metadata.TAPType; + /** * <p>{@link TableIterator} which lets iterate over a SQL {@link ResultSet}.</p> * - * <p>{@link #getColType()} will return the type declared in the {@link ResultSetMetaData} object.</p> + * <p>{@link #getColType()} will return a TAP type base on the one declared in the {@link ResultSetMetaData} object.</p> * * @author Grégory Mantelet (ARI) - gmantele@ari.uni-heidelberg.de * @version 2.0 (06/2014) @@ -40,8 +44,8 @@ public class ResultSetTableIterator implements TableIterator { /** Number of columns to read. */ private final int nbColumns; - /** Type of all columns. */ - private final String[] colTypes; + /** Metadata of all columns identified before the iteration. */ + private final TAPColumn[] colMeta; /** Indicate whether the row iteration has already started. */ private boolean iterationStarted = false; @@ -82,14 +86,21 @@ public class ResultSetTableIterator implements TableIterator { // count columns: nbColumns = metadata.getColumnCount(); // determine their type: - colTypes = new String[nbColumns]; - for(int i = 1; i <= nbColumns; i++) - colTypes[i - 1] = metadata.getColumnTypeName(i); + colMeta = new TAPColumn[nbColumns]; + for(int i = 1; i <= nbColumns; i++){ + TAPType datatype = JDBCTAPFactory.toTAPType(metadata.getColumnTypeName(i)); + colMeta[i - 1] = new TAPColumn(metadata.getColumnLabel(i), datatype); + } }catch(SQLException se){ throw new DataReadException("Can not get the column types of the given ResultSet!", se); } } + @Override + public TAPColumn[] getMetadata(){ + return colMeta; + } + @Override public boolean nextRow() throws DataReadException{ try{ @@ -144,7 +155,7 @@ public class ResultSetTableIterator implements TableIterator { } @Override - public String getColType() throws IllegalStateException, DataReadException{ + public TAPType getColType() throws IllegalStateException, DataReadException{ // Basically check the read state (for rows iteration): checkReadState(); @@ -155,7 +166,7 @@ public class ResultSetTableIterator implements TableIterator { throw new IllegalStateException("All columns have already been read!"); // Return the column type: - return colTypes[colIndex - 1]; + return colMeta[colIndex - 1].getDatatype(); } } diff --git a/src/tap/data/TableIterator.java b/src/tap/data/TableIterator.java index 5e6234ee389c758ae3bfdb21d552206d7c6fccd2..3051b3a52bc990b8ce253ba765b2a690df0324b6 100644 --- a/src/tap/data/TableIterator.java +++ b/src/tap/data/TableIterator.java @@ -21,6 +21,9 @@ package tap.data; import java.util.NoSuchElementException; +import tap.metadata.TAPColumn; +import tap.metadata.TAPType; + /** * <p>Let's iterate on each row and then on each column over a table dataset.</p> * @@ -48,6 +51,23 @@ import java.util.NoSuchElementException; * @since 2.0 */ public interface TableIterator { + /** + * <p>Get all the metadata column that have been successfully extracted at the creation of this iterator.</p> + * + * <p><b>Important:</b> This function should be callable at any moment from the creation of the iterator until the end of the table dataset has been reached.</p> + * + * <p><i>Note: This function MAY BE NOT IMPLEMENTED or the metadata can not be fetched. In this case, NULL will be returned.</i></p> + * + * <p><i><b>Warning:</b> If the metadata part of the original document is corrupted (i.e. false number of columns), + * the column type information should be fetched thanks to {@link #getColType()} while iterating over rows and columns.</i></p> + * + * @return An array of {@link TAPColumn} objects (each for a column of any row), + * or NULL if this function is not implemented OR if it was not possible to get these metadata. + * + * @see #getColType() + */ + public TAPColumn[] getMetadata(); + /** * <p>Go to the next row if there is one.</p> * @@ -88,13 +108,19 @@ public interface TableIterator { /** * <p>Get the type of the current column value.</p> * - * <p><i>Note: "Current column value" means here "the value last returned by {@link #nextCol()}".</i></p> + * <p><i>Note 1: "Current column value" means here "the value last returned by {@link #nextCol()}".</i></p> + * + * <p><i>Note 2: This function MAY BE NOT IMPLEMENTED or the type information can not be fetched. If this is the case, NULL will be returned.</i></p> + * + * <p><i><b>Warning:</b> In some cases, the metadata part of the original document does not match with the data + * it should have represented. In such case, the types returned here and by {@link #getMetadata()} would be different. + * <b>In case of such mismatch, the type returned by {@link #getColType()} should be considered as more correct/accurate.</b></i></p> * * @return Type of the current column value, * or NULL if this information is not available or if this function is not implemented. * * @throws IllegalStateException If {@link #nextCol()} has not yet been called. - * @throws DataReadException If an error occurs while reading the table dataset. + * @throws DataReadException If an error occurs while reading the table dataset. */ - public String getColType() throws IllegalStateException, DataReadException; + public TAPType getColType() throws IllegalStateException, DataReadException; } diff --git a/src/tap/data/VOTableIterator.java b/src/tap/data/VOTableIterator.java new file mode 100644 index 0000000000000000000000000000000000000000..00349c24714987c12681a093967334cae95d1a18 --- /dev/null +++ b/src/tap/data/VOTableIterator.java @@ -0,0 +1,467 @@ +package tap.data; + +/* + * This file is part of TAPLibrary. + * + * TAPLibrary 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. + * + * TAPLibrary 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 TAPLibrary. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright 2014 - Astronomisches Rechen Institut (ARI) + */ + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import tap.metadata.TAPColumn; +import tap.metadata.TAPType; +import tap.metadata.VotType; +import tap.metadata.VotType.VotDatatype; +import cds.savot.model.DataBinaryReader; +import cds.savot.model.FieldSet; +import cds.savot.model.SavotBinary; +import cds.savot.model.SavotField; +import cds.savot.model.SavotResource; +import cds.savot.model.SavotTD; +import cds.savot.model.SavotTR; +import cds.savot.model.SavotTableData; +import cds.savot.pull.SavotPullEngine; +import cds.savot.pull.SavotPullParser; + +/** + * <p>{@link TableIterator} which lets iterate over a VOTable input stream using Savot ({@link SavotPullParser} more exactly).</p> + * + * <p>{@link #getColType()} will return TAP type based on the type declared in the VOTable metadata part.</p> + * + * @author Grégory Mantelet (ARI) - gmantele@ari.uni-heidelberg.de + * @version 2.0 (06/2014) + * @since 2.0 + */ +public class VOTableIterator implements TableIterator { + + /** Metadata of all columns identified before the iteration. */ + private final TAPColumn[] colMeta; + /** Inner TableIterator. It lets iterate over a binary or a table data set in a transparent way. */ + private final TableIterator it; + + /** + * Build a TableIterator able to read rows and columns inside the given VOTable input stream. + * + * @param input Input stream over a VOTable document. + * + * @throws NullPointerException If NULL is given in parameter. + * @throws DataReadException If the given VOTable can not be parsed. + */ + public VOTableIterator(final InputStream input) throws DataReadException{ + // An input stream MUST BE provided: + if (input == null) + throw new NullPointerException("Missing VOTable document input stream over which to iterate!"); + + try{ + // Start parsing the VOTable: + SavotPullParser parser = new SavotPullParser(input, SavotPullEngine.SEQUENTIAL, null); + + // Get the first resource: + SavotResource resource = parser.getNextResource(); + if (resource == null) + throw new DataReadException("Incorrect VOTable format: missing resource node!"); + + // Extract the metadata about all fields: + FieldSet fields = resource.getFieldSet(0); + colMeta = extractColMeta(fields); + + // Build the iterator over the data: + SavotBinary binary = resource.getData(0).getBinary(); + if (binary != null) + it = new BinaryVOTableIterator(binary, fields, colMeta); + else + it = new DataVOTableIterator(resource.getData(0).getTableData(), colMeta); + }catch(Exception ex){ + throw new DataReadException("Unable to parse/read the given VOTable input stream!", ex); + } + } + + /** + * Extract an array of {@link TAPColumn} objects. Each corresponds to one of the fields given in parameter, + * and so corresponds to the metadata of a column. + * + * @param fields List of metadata fields provided in a VOTable. + * + * @return The corresponding list of {@link TAPColumn} objects. + */ + private static final TAPColumn[] extractColMeta(final FieldSet fields){ + // Count the number columns and initialize the array: + TAPColumn[] columns = new TAPColumn[fields.getItemCount()]; + + // Add all columns meta: + for(int i = 0; i < fields.getItemCount(); i++){ + // get the field: + SavotField field = (SavotField)fields.getItemAt(i); + + // Resolve the field type: + TAPType type = resolveVotType(field.getDataType(), field.getArraySize(), field.getXtype()).toTAPType(); + + // build the TAPColumn object: + TAPColumn col = new TAPColumn(field.getName(), type, field.getDescription(), field.getUnit(), field.getUcd(), field.getUtype()); + col.setPrincipal(false); + col.setIndexed(false); + col.setStd(false); + + // append it to the array: + columns[i] = col; + } + + return columns; + } + + /** + * Resolve a VOTable field type by using the datatype, arraysize and xtype strings as specified in a VOTable document. + * + * @param datatype Attribute value of VOTable corresponding to the datatype. + * @param arraysize Attribute value of VOTable corresponding to the arraysize. + * @param xtype Attribute value of VOTable corresponding to the xtype. + * + * @return The resolved VOTable field type, or a CHAR(*) type if the specified type can not be resolved. + */ + private static VotType resolveVotType(final String datatype, final String arraysize, final String xtype){ + // If no datatype is specified, return immediately a CHAR(*) type: + if (datatype == null || datatype.trim().length() == 0) + return new VotType(VotDatatype.CHAR, VotType.NO_SIZE, true); + + // 1. IDENTIFY THE DATATYPE: + + // Identify the specified datatype: + VotDatatype votdatatype; + try{ + votdatatype = VotDatatype.valueOf(datatype.toUpperCase()); + }catch(IllegalArgumentException iae){ + // if it can't be identified, return immediately a CHAR(*) type: + return new VotType(VotDatatype.CHAR, VotType.NO_SIZE, true); + } + + // 2. DETERMINE ITS ARRAYSIZE: + + int votarraysize = VotType.NO_SIZE; + boolean votunlimitedSize = false; + + // If no arraysize is specified, let's set it to 1 (for an elementary value): + if (arraysize == null || arraysize.trim().isEmpty()) + votarraysize = 1; + + // Otherwise, get it: + else{ + String str = arraysize.trim(); + + // Determine whether an "unlimited size" character is specified: + votunlimitedSize = str.endsWith("*"); + + // If one is specified, remove it from the arraysize string: + if (votunlimitedSize) + str = str.substring(0, str.length() - 1); + + // If a size is really specified (more characters than "*"), get the arraysize value: + if (str.length() > 0){ + try{ + votarraysize = Integer.parseInt(str); + }catch(NumberFormatException nfe){} + } + } + + // And finally build the VOTable type: + return new VotType(votdatatype, votarraysize, votunlimitedSize, xtype); + } + + /** + * <p>Check the row iteration state. That's to say whether:</p> + * <ul> + * <li>the row iteration has started = the first row has been read = a first call of {@link #nextRow()} has been done</li> + * <li>AND the row iteration is not finished = the last row has been read.</li> + * </ul> + * @throws IllegalStateException + */ + private static void checkReadState(final boolean iterationStarted, final boolean endReached) throws IllegalStateException{ + if (!iterationStarted) + throw new IllegalStateException("No row has yet been read!"); + else if (endReached) + throw new IllegalStateException("End of ResultSet already reached!"); + } + + @Override + public TAPColumn[] getMetadata(){ + return colMeta; + } + + @Override + public boolean nextRow() throws DataReadException{ + return it.nextRow(); + } + + @Override + public boolean hasNextCol() throws IllegalStateException, DataReadException{ + return it.hasNextCol(); + } + + @Override + public Object nextCol() throws NoSuchElementException, IllegalStateException, DataReadException{ + return it.nextCol(); + } + + @Override + public TAPType getColType() throws IllegalStateException, DataReadException{ + return it.getColType(); + } + + /** + * <p>{@link TableIterator} which lets iterate over a VOTable binary data part.</p> + * + * <p>This {@link TableIterator} is only usable by {@link VOTableIterator}.</p> + * + * @author Grégory Mantelet (ARI) - gmantele@ari.uni-heidelberg.de + * @version 2.0 (Jun 27, 2014) + * @since 2.0 + */ + private static class BinaryVOTableIterator implements TableIterator { + + /** Binary data reader which lets read rows and columns, and thus iterate over them. */ + private final DataBinaryReader reader; + /** Metadata of all columns identified before the iteration. <i>(In this TableIterator, they are completely provided by {@link VOTableIterator}).</i> */ + private final TAPColumn[] colMeta; + + /** The last read row. Each item is a column value. */ + private Object[] row; + + /** Indicate whether the row iteration has already started. */ + private boolean iterationStarted = false; + /** Indicate whether the last row has already been reached. */ + private boolean endReached = false; + /** Index of the last read column (=0 just after {@link #nextRow()} and before {@link #nextCol()}). */ + private int colIndex; + + /** + * Build a TableIterator on the given binary data part of a VOTable whose fields are also described in parameter. + * + * @param binary Binary data part of a VOTable document. + * @param fields Description of all the fields that should be read. + * @param columnsMeta Metadata information extracted from the VOTable metadata part. + * + * @throws DataReadException If there is an error while starting reading the given binary data. + */ + public BinaryVOTableIterator(final SavotBinary binary, final FieldSet fields, final TAPColumn[] columnsMeta) throws DataReadException{ + try{ + reader = new DataBinaryReader(binary.getStream(), fields, false); + colMeta = columnsMeta; + }catch(IOException ioe){ + throw new DataReadException("Can not open a stream to decode the binary VOTable data!", ioe); + } + } + + @Override + public TAPColumn[] getMetadata(){ + return null; + } + + @Override + public boolean nextRow() throws DataReadException{ + try{ + // Go to the next row: + boolean rowFetched = reader.next(); + // prepare the iteration over its columns: + if (rowFetched){ + row = reader.getRow(); + colIndex = -1; + iterationStarted = true; + }else{ + row = null; + colIndex = -1; + endReached = true; + } + return rowFetched; + }catch(IOException e){ + throw new DataReadException("Unable to read a VOTable row!", e); + } + } + + @Override + public boolean hasNextCol() throws IllegalStateException, DataReadException{ + // Check the read state: + checkReadState(iterationStarted, endReached); + + // Determine whether the last column has been reached or not: + return (colIndex + 1 < row.length); + } + + @Override + public Object nextCol() throws NoSuchElementException, IllegalStateException, DataReadException{ + // Check the read state and ensure there is still at least one column to read: + if (!hasNextCol()) + throw new NoSuchElementException("No more column to read!"); + + // Get the column value: + return row[++colIndex]; + } + + @Override + public TAPType getColType() throws IllegalStateException, DataReadException{ + // Basically check the read state (for rows iteration): + checkReadState(iterationStarted, endReached); + + // Check deeper the read state (for columns iteration): + if (colIndex < 0) + throw new IllegalStateException("No column has yet been read!"); + else if (colIndex >= colMeta.length) + return null; + + // Get the column value: + return colMeta[colIndex].getDatatype(); + } + + } + + /** + * <p>{@link TableIterator} which lets iterate over a VOTable table data part.</p> + * + * <p>This {@link TableIterator} is only usable by {@link VOTableIterator}.</p> + * + * @author Grégory Mantelet (ARI) - gmantele@ari.uni-heidelberg.de + * @version 2.0 (Jun 27, 2014) + * @since 2.0 + */ + private static class DataVOTableIterator implements TableIterator { + + /** Iterator over the rows contained in the VOTable data part. */ + private final Iterator<Object> data; + /** Metadata of all columns identified before the iteration. <i>(In this TableIterator, they are completely provided by {@link VOTableIterator}).</i> */ + private final TAPColumn[] colMeta; + + /** Iterator over the columns contained in the last read row. */ + private Iterator<Object> colsIt; + + /** Indicate whether the row iteration has already started. */ + private boolean iterationStarted = false; + /** Indicate whether the last row has already been reached. */ + private boolean endReached = false; + /** Index of the last read column (=0 just after {@link #nextRow()} and before {@link #nextCol()}). */ + private int colIndex; + + /** + * Build a TableIterator on the given table data part of a VOTable. + * + * @param dataset Table data part of a VOTable document. + * @param columnsMeta Metadata information extracted from the VOTable metadata part. + */ + public DataVOTableIterator(final SavotTableData dataset, final TAPColumn[] columnsMeta){ + Collection<Object> trset = dataset.getTRs().getItems(); + if (trset == null){ + data = new NullIterator(); + colMeta = columnsMeta; + iterationStarted = true; + endReached = true; + }else{ + data = trset.iterator(); + colMeta = columnsMeta; + } + } + + @Override + public TAPColumn[] getMetadata(){ + return null; + } + + @Override + public boolean nextRow() throws DataReadException{ + if (data.hasNext()){ + // Go to the next row: + SavotTR row = (SavotTR)data.next(); + + // Prepare the iteration over its columns: + Collection<Object> tdset = row.getTDSet().getItems(); + if (tdset == null) + colsIt = new NullIterator(); + else + colsIt = tdset.iterator(); + + colIndex = -1; + iterationStarted = true; + + return true; + }else{ + // No more row to read => end of VOTable reached: + endReached = true; + return false; + } + } + + @Override + public boolean hasNextCol() throws IllegalStateException, DataReadException{ + // Check the read state: + checkReadState(iterationStarted, endReached); + + // Determine whether the last column has been reached or not: + return colsIt.hasNext(); + } + + @Override + public Object nextCol() throws NoSuchElementException, IllegalStateException, DataReadException{ + // Check the read state and ensure there is still at least one column to read: + if (!hasNextCol()) + throw new NoSuchElementException("No more column to read!"); + + // Get the column value: + Object value = ((SavotTD)colsIt.next()).getContent(); + colIndex++; + return value; + } + + @Override + public TAPType getColType() throws IllegalStateException, DataReadException{ + // Basically check the read state (for rows iteration): + checkReadState(iterationStarted, endReached); + + // Check deeper the read state (for columns iteration): + if (colIndex < 0) + throw new IllegalStateException("No column has yet been read!"); + else if (colIndex >= colMeta.length) + return null; + + // Get the column value: + return colMeta[colIndex].getDatatype(); + } + + } + + /** + * Iterator over nothing. + * + * @author Grégory Mantelet (ARI) - gmantele@ari.uni-heidelberg.de + * @version 2.0 (06/2014) + * @version 2.0 + */ + private final static class NullIterator implements Iterator<Object> { + @Override + public boolean hasNext(){ + return false; + } + + @Override + public Object next(){ + return null; + } + + @Override + public void remove(){} + + } + +} diff --git a/src/tap/db/JDBCTAPFactory.java b/src/tap/db/JDBCTAPFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..8ef12bf4e06f907dafe374040ab08742ec1079ca --- /dev/null +++ b/src/tap/db/JDBCTAPFactory.java @@ -0,0 +1,228 @@ +package tap.db; + +import java.util.HashMap; +import java.util.Map; + +import tap.metadata.TAPType; +import tap.metadata.TAPType.TAPDatatype; + +public class JDBCTAPFactory { + + public static enum DBMS{ + POSTGRES; + } + + public static interface DbmsTypeConverter< T, C > { + public C convert(final T typeToConvert); + } + + public static Map<String,TAPDatatype> mapTypeAliases; + public static Map<String,DbmsTypeConverter<String,TAPType>> mapDbmsToTap; + public static Map<DBMS,Map<TAPDatatype,DbmsTypeConverter<TAPType,String>>> mapTapToDbms; + + static{ + /* DECLARE DBMS TYPE ALIASES */ + mapTypeAliases = new HashMap<String,TAPType.TAPDatatype>(); + mapTypeAliases.put("int8", TAPDatatype.BIGINT); + mapTypeAliases.put("bigserial", TAPDatatype.BIGINT); + mapTypeAliases.put("bit", TAPDatatype.VARCHAR); + mapTypeAliases.put("bit varying", TAPDatatype.VARCHAR); + mapTypeAliases.put("varbit", TAPDatatype.VARCHAR); + mapTypeAliases.put("boolean", TAPDatatype.SMALLINT); + mapTypeAliases.put("bytea", TAPDatatype.VARBINARY); + mapTypeAliases.put("character varying", TAPDatatype.VARCHAR); + mapTypeAliases.put("character", TAPDatatype.CHAR); + mapTypeAliases.put("double precision", TAPDatatype.DOUBLE); + mapTypeAliases.put("float8", TAPDatatype.DOUBLE); + mapTypeAliases.put("integer", TAPDatatype.INTEGER); + mapTypeAliases.put("int4", TAPDatatype.INTEGER); + mapTypeAliases.put("float4", TAPDatatype.REAL); + mapTypeAliases.put("int2", TAPDatatype.SMALLINT); + mapTypeAliases.put("serial", TAPDatatype.INTEGER); + mapTypeAliases.put("serial4", TAPDatatype.INTEGER); + mapTypeAliases.put("text", TAPDatatype.VARCHAR); + + /* DECLARE SPECIAL DBMS->TAP CONVERSIONS */ + mapDbmsToTap = new HashMap<String,JDBCTAPFactory.DbmsTypeConverter<String,TAPType>>(); + mapDbmsToTap.put("numeric", new DbmsTypeConverter<String,TAPType>(){ + @Override + public TAPType convert(String typeToConvert){ + return new TAPType(TAPDatatype.DOUBLE); + } + }); + mapDbmsToTap.put("decimal", new DbmsTypeConverter<String,TAPType>(){ + @Override + public TAPType convert(String typeToConvert){ + return new TAPType(TAPDatatype.DOUBLE); + } + }); + + /* DECLARE SPECIAL TAP->DBMS CONVERSIONS */ + mapTapToDbms = new HashMap<DBMS,Map<TAPDatatype,DbmsTypeConverter<TAPType,String>>>(); + // POSTGRES + HashMap<TAPDatatype,DbmsTypeConverter<TAPType,String>> postgresConverters = new HashMap<TAPDatatype,JDBCTAPFactory.DbmsTypeConverter<TAPType,String>>(); + postgresConverters.put(TAPDatatype.DOUBLE, new DbmsTypeConverter<TAPType,String>(){ + @Override + public String convert(TAPType typeToConvert){ + return "double precision"; + } + }); + DbmsTypeConverter<TAPType,String> binaryConverter = new DbmsTypeConverter<TAPType,String>(){ + @Override + public String convert(TAPType typeToConvert){ + return "bytea"; + } + }; + postgresConverters.put(TAPDatatype.VARBINARY, binaryConverter); + postgresConverters.put(TAPDatatype.BINARY, binaryConverter); + postgresConverters.put(TAPDatatype.BLOB, binaryConverter); + postgresConverters.put(TAPDatatype.CLOB, binaryConverter); + mapTapToDbms.put(DBMS.POSTGRES, postgresConverters); + } + + public JDBCTAPFactory(){ + // TODO Auto-generated constructor stub + } + + /** + * <p>Convert the given TAP column type into a column type compatible with the specified DBMS.</p> + * + * <p><i>Note 1: if no {@link TAPType} is provided, the returned DBMS type will correspond to a + * VARCHAR.</i></p> + * + * <p><i>Note 2: if no DBMS is specified or if the conversion has failed, the given TAP type will be + * just "stringified" (by calling {@link TAPType#toString()})</i></p> + * + * @param tapType A TAP column type. + * @param dbms DBMS target in which the given TAP column type must be converted. + * + * @return The corresponding DBMS column type. + */ + public static String toDbmsType(TAPType tapType, final DBMS dbms){ + // If no TAP type is specified, consider it by default as a VARCHAR type: + if (tapType == null) + tapType = new TAPType(TAPDatatype.VARCHAR); + + // By default, just "stringify" the given TAP type: + String dbmsType = tapType.toString(); + + // If some converters are defined for the specified DBMS... + if (dbms != null && mapTapToDbms.containsKey(dbms)){ + Map<TAPDatatype,DbmsTypeConverter<TAPType,String>> dbmsMap = mapTapToDbms.get(dbms); + // ...and if a converter exists for the given TAP datatype... + DbmsTypeConverter<TAPType,String> converter = dbmsMap.get(tapType.type); + if (converter != null){ + // ...convert the given TAP type: + String conversion = converter.convert(tapType); + // ...and set the DBMS conversion if NOT NULL: + if (conversion != null) + dbmsType = conversion; + } + } + + return dbmsType; + } + + /** + * <p>Convert the given DBMS column type into a compatible TAP datatype.</p> + * + * <p><i>Note: If no DBMS type is specified or if the DBMS type can not be identified, + * it will be converted as a VARCHAR.</i></p> + * + * @param dbmsType DBMS column datatype. + * + * @return The corresponding TAP column datatype. + */ + public static TAPType toTAPType(final String dbmsType){ + // If no type is provided return VARCHAR: + if (dbmsType == null || dbmsType.trim().length() == 0) + return new TAPType(TAPDatatype.VARCHAR); + + // Extract the type prefix and lower-case it: + int paramIndex = dbmsType.indexOf('('); + String dbmsTypePrefix = (paramIndex <= 0) ? dbmsType : dbmsType.substring(0, paramIndex); + dbmsTypePrefix = dbmsTypePrefix.toLowerCase(); + + // Use this type prefix as key to determine if it's a DBMS type alias and get its corresponding TAP datatype: + TAPDatatype datatype = mapTypeAliases.get(dbmsTypePrefix); + + // If it's an alias, build the corresponding TAP type: + if (datatype != null) + return new TAPType(datatype, getLengthParam(dbmsType, paramIndex)); + + // If it's not an alias, use the type prefix as key to get a corresponding converter: + DbmsTypeConverter<String,TAPType> converter = mapDbmsToTap.get(dbmsTypePrefix); + + // Try the type conversion using this converter: + TAPType taptype = null; + if (converter != null) + taptype = converter.convert(dbmsType); + + /* + * If no converter was found OR if the type conversion has failed, + * consider the given type as equivalent to a declared TAP type. + * + * /!\ But if no equivalent exists, the given type will be ignore and + * VARCHAR will be returned! + */ + if (taptype == null){ + try{ + + // Try to find an equivalent TAPType: + datatype = TAPDatatype.valueOf(dbmsTypePrefix.toUpperCase()); + + // If there is one return directly the TAPType: + taptype = new TAPType(datatype, getLengthParam(dbmsType, paramIndex)); + + }catch(IllegalArgumentException iae){ + // If none exists, return VARCHAR: + taptype = new TAPType(TAPDatatype.VARCHAR, TAPType.NO_LENGTH); + } + } + + return taptype; + } + + /** + * <p>Extract the 'length' parameter of a DBMS type string.</p> + * + * <p> + * If the given type string does not contain any parameter + * OR if the first parameter can not be casted into an integer, + * {@link TAPType#NO_LENGTH} will be returned. + * </p> + * + * @param dbmsType DBMS type string (containing the datatype and the 'length' parameter). + * @param paramIndex Index of the open bracket. + * + * @return The 'length' parameter value if found, {@link TAPType#NO_LENGTH} otherwise. + */ + private static int getLengthParam(final String dbmsType, final int paramIndex){ + // If no parameter has been previously detected, no length parameter: + if (paramIndex <= 0) + return TAPType.NO_LENGTH; + + // If there is one and that at least ONE parameter is provided.... + else{ + int lengthParam = TAPType.NO_LENGTH; + String paramsStr = dbmsType.substring(paramIndex + 1); + + // ...extract the 'length' parameter: + /* note: we suppose here that no other parameter is possible ; + * but if there are, they are ignored and we try to consider the first parameter + * as the length */ + int paramEndIndex = paramsStr.indexOf(','); + if (paramEndIndex <= 0) + paramEndIndex = paramsStr.indexOf(')'); + + // ...cast it into an integer: + try{ + lengthParam = Integer.parseInt(paramsStr.substring(0, paramEndIndex)); + }catch(Exception ex){} + + // ...and finally return it: + return lengthParam; + } + } + +} diff --git a/test/tap/data/ResultSetTableIteratorTest.java b/test/tap/data/ResultSetTableIteratorTest.java index cd0e7f9d6da32e816791ff9d24dc0b761de1dcbc..99d7057f72c81b8a73ea603e67dc6c91a21df274 100644 --- a/test/tap/data/ResultSetTableIteratorTest.java +++ b/test/tap/data/ResultSetTableIteratorTest.java @@ -43,6 +43,8 @@ public class ResultSetTableIteratorTest { ResultSet rs = DBTools.select(conn, "SELECT id, ra, deg, gmag FROM gums LIMIT 10;"); TableIterator it = new ResultSetTableIterator(rs); + // TEST there is column metadata before starting the iteration: + assertTrue(it.getMetadata() != null); final int expectedNbLines = 10, expectedNbColumns = 4; int countLines = 0, countColumns = 0; while(it.nextRow()){ @@ -75,6 +77,8 @@ public class ResultSetTableIteratorTest { ResultSet rs = DBTools.select(conn, "SELECT * FROM gums WHERE id = 'foo';"); TableIterator it = new ResultSetTableIterator(rs); + // TEST there is column metadata before starting the iteration: + assertTrue(it.getMetadata() != null); int countLines = 0; // count lines: while(it.nextRow()) diff --git a/test/tap/data/VOTableIteratorTest.java b/test/tap/data/VOTableIteratorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cc78ad3838948da681dcaf282124c8df7aab1fe3 --- /dev/null +++ b/test/tap/data/VOTableIteratorTest.java @@ -0,0 +1,172 @@ +package tap.data; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Test; + +public class VOTableIteratorTest { + + public final static String directory = "/home/gmantele/workspace/tap/test/tap/data/"; + + public final static File dataVOTable = new File(directory + "testdata.vot"); + public final static File binaryVOTable = new File(directory + "testdata_binary.vot"); + + public final static File emptyVOTable = new File(directory + "emptyset.vot"); + public final static File emptyBinaryVOTable = new File(directory + "emptyset_binary.vot"); + + @Test + public void testWithNULL(){ + try{ + new VOTableIterator(null); + fail("The constructor should have failed, because: the given VOTable is NULL."); + }catch(Exception ex){ + assertEquals(ex.getClass().getName(), "java.lang.NullPointerException"); + } + } + + @Test + public void testWithData(){ + InputStream input = null; + try{ + input = new BufferedInputStream(new FileInputStream(dataVOTable)); + TableIterator it = new VOTableIterator(input); + // TEST there is column metadata before starting the iteration: + assertTrue(it.getMetadata() != null); + final int expectedNbLines = 100, expectedNbColumns = 4; + int countLines = 0, countColumns = 0; + while(it.nextRow()){ + // count lines: + countLines++; + // reset columns count: + countColumns = 0; + while(it.hasNextCol()){ + it.nextCol(); + // count columns + countColumns++; + // TEST the column type is set (not null): + assertTrue(it.getColType() != null); + } + // TEST that all columns have been read: + assertEquals(expectedNbColumns, countColumns); + } + // TEST that all lines have been read: + assertEquals(expectedNbLines, countLines); + + }catch(Exception ex){ + ex.printStackTrace(System.err); + fail("An exception occurs while reading a correct VOTable (containing some valid rows)."); + }finally{ + try{ + if (input != null) + input.close(); + }catch(IOException e){ + e.printStackTrace(); + } + } + } + + @Test + public void testWithBinary(){ + InputStream input = null; + try{ + input = new BufferedInputStream(new FileInputStream(binaryVOTable)); + TableIterator it = new VOTableIterator(input); + // TEST there is column metadata before starting the iteration: + assertTrue(it.getMetadata() != null); + final int expectedNbLines = 100, expectedNbColumns = 4; + int countLines = 0, countColumns = 0; + while(it.nextRow()){ + // count lines: + countLines++; + // reset columns count: + countColumns = 0; + while(it.hasNextCol()){ + it.nextCol(); + // count columns + countColumns++; + // TEST the column type is set (not null): + assertTrue(it.getColType() != null); + } + // TEST that all columns have been read: + assertEquals(expectedNbColumns, countColumns); + } + // TEST that all lines have been read: + assertEquals(expectedNbLines, countLines); + + }catch(Exception ex){ + ex.printStackTrace(System.err); + fail("An exception occurs while reading a correct VOTable (containing some valid rows)."); + }finally{ + try{ + if (input != null) + input.close(); + }catch(IOException e){ + e.printStackTrace(); + } + } + } + + @Test + public void testWithEmptySet(){ + InputStream input = null; + try{ + input = new BufferedInputStream(new FileInputStream(emptyVOTable)); + TableIterator it = new VOTableIterator(input); + // TEST there is column metadata before starting the iteration: + assertTrue(it.getMetadata() != null); + int countLines = 0; + // count lines: + while(it.nextRow()) + countLines++; + // TEST that no line has been read: + assertEquals(countLines, 0); + + }catch(Exception ex){ + ex.printStackTrace(System.err); + fail("An exception occurs while reading a correct VOTable (even if empty)."); + }finally{ + try{ + if (input != null) + input.close(); + }catch(IOException e){ + e.printStackTrace(); + } + } + } + + @Test + public void testWithEmptyBinarySet(){ + InputStream input = null; + try{ + input = new BufferedInputStream(new FileInputStream(emptyBinaryVOTable)); + TableIterator it = new VOTableIterator(input); + // TEST there is column metadata before starting the iteration: + assertTrue(it.getMetadata() != null); + int countLines = 0; + // count lines: + while(it.nextRow()) + countLines++; + // TEST that no line has been read: + assertEquals(countLines, 0); + + }catch(Exception ex){ + ex.printStackTrace(System.err); + fail("An exception occurs while reading a correct binary VOTable (even if empty)."); + }finally{ + try{ + if (input != null) + input.close(); + }catch(IOException e){ + e.printStackTrace(); + } + } + } +} diff --git a/test/tap/data/emptyset.vot b/test/tap/data/emptyset.vot new file mode 100644 index 0000000000000000000000000000000000000000..fe9b28f07d38b03eb805da25fe3f0b04fe100048 --- /dev/null +++ b/test/tap/data/emptyset.vot @@ -0,0 +1,123 @@ +<?xml version='1.0'?> +<VOTABLE version="1.2" + xmlns="http://www.ivoa.net/xml/VOTable/v1.2"> +<!-- + ! VOTable written by STIL version 3.0-5+ (uk.ac.starlink.votable.VOTableWriter) + ! at 2014-06-27T15:46:42 + !--> +<RESOURCE> +<TABLE name="sn" nrows="1"> +<PARAM arraysize="19" datatype="char" name="source" value="2012arXiv1202.0132R"/> +<PARAM arraysize="9" datatype="char" name="CoordFlavor" utype="stc:AstroCoordSystem.SpaceFrame.CoordFlavor" value="SPHERICAL"/> +<PARAM arraysize="1" datatype="char" name="coord_naxes" utype="stc:AstroCoordSystem.SpaceFrame.CoordFlavor.coord_naxes" value="3"/> +<PARAM arraysize="4" datatype="char" name="CoordRefFrame" utype="stc:AstroCoordSystem.SpaceFrame.CoordRefFrame" value="ICRS"/> +<PARAM arraysize="6" datatype="char" name="Epoch" utype="stc:AstroCoords.Position3D.Epoch" value="2010.0"/> +<PARAM arraysize="1" datatype="char" name="yearDef" utype="stc:AstroCoords.Position3D.Epoch.yearDef" value="J"/> +<PARAM arraysize="41" datatype="char" name="URI" utype="stc:DataModel.URI" value="http://www.ivoa.net/xml/STC/stc-v1.30.xsd"/> +<PARAM arraysize="31" datatype="char" name="server" value="http://dc.zah.uni-heidelberg.de"/> +<PARAM arraysize="69" datatype="char" name="query" value="SELECT * FROM gums.sn WHERE sourceid = 5227706337957249025 LIMIT 2000"/> +<PARAM arraysize="36" datatype="char" name="src_res" value="Contains traces from resource gums/q"> +<DESCRIPTION>GUMS-10 is the 10th version of the Gaia Universe Model Snapshot, a +simulation of the expected contents of the Gaia cataloge run at the +MareNostrum supercomputer. The models used and the characteristics of +GUMS-10 are described in: A.C. Robin et al, "Gaia Universe Model +Snapshot. A statistical analysis of the expected contents of the Gaia +catalogue", Astronomy & Astrophysics (2012), in press. For more +details see also http://gaia.am.ub.es/GUMS-10/</DESCRIPTION> +</PARAM> +<PARAM arraysize="34" datatype="char" name="src_table" value="Contains traces from table gums.sn"> +<DESCRIPTION>Supernovae in the GUMS-10 simulated GAIA result set.</DESCRIPTION> +</PARAM> +<PARAM arraysize="54" datatype="char" name="copyright" value="Content from gums/q has rights note (see INFO content)"> +<DESCRIPTION>If you use this data, please acknowledge that GUMS was created using +the MareNostrum supercomputer.</DESCRIPTION> +</PARAM> +<PARAM arraysize="2" datatype="char" name="QUERY_STATUS" value="OK"> +<DESCRIPTION>Query successful</DESCRIPTION> +</PARAM> +<PARAM arraysize="11" datatype="char" name="Service short name" value="GAVO DC TAP"> +<DESCRIPTION>Short name for TAP service</DESCRIPTION> +</PARAM> +<PARAM arraysize="28" datatype="char" name="Service title" value="GAVO Data Center TAP service"> +<DESCRIPTION>TAP service title</DESCRIPTION> +</PARAM> +<PARAM arraysize="36" datatype="char" name="Identifier" value="ivo://org.gavo.dc/__system__/tap/run"> +<DESCRIPTION>Unique resource registry identifier</DESCRIPTION> +</PARAM> +<PARAM arraysize="16" datatype="char" name="Service publisher" value="The GAVO DC team"> +<DESCRIPTION>Publisher for TAP service</DESCRIPTION> +</PARAM> +<PARAM arraysize="55" datatype="char" name="Service reference URL" value="http://dc.zah.uni-heidelberg.de/__system__/tap/run/info"> +<DESCRIPTION>Descriptive URL for search resource</DESCRIPTION> +</PARAM> +<PARAM arraysize="50" datatype="char" name="Contact person" value="GAVO Data Center Team <gavo@ari.uni-heidelberg.de>"> +<DESCRIPTION>Individual to contact about this service</DESCRIPTION> +</PARAM> +<FIELD ID="v" datatype="float" name="v" unit="mag"> +<DESCRIPTION>Intrinsic apparent V magnitude</DESCRIPTION> +</FIELD> +<FIELD ID="colorvminusi" datatype="float" name="colorvminusi" ucd="phot.color;em.opt.V;em.opt.I" unit="mag"> +<DESCRIPTION>Intrinsic V-I color.</DESCRIPTION> +</FIELD> +<FIELD ID="meanabsolutev" datatype="float" name="meanabsolutev" ucd="phot.mag;em.opt.V" unit="mag"> +<DESCRIPTION>Mean absolute V magnitude.</DESCRIPTION> +</FIELD> +<FIELD ID="redshift" datatype="float" name="redshift" ucd="src.redshift"> +<DESCRIPTION>Object redshift.</DESCRIPTION> +</FIELD> +<FIELD ID="alpha" datatype="double" name="alpha" ucd="pos.eq.ra;meta.main" unit="deg"> +<DESCRIPTION>Right ascention of the barycenter at J2010 reference epoch in the ICRS frame</DESCRIPTION> +</FIELD> +<FIELD ID="delta" datatype="double" name="delta" ucd="pos.eq.dec;meta.main" unit="deg"> +<DESCRIPTION>Declination of the barycenter at J2010 reference epoch in the ICRS frame</DESCRIPTION> +</FIELD> +<FIELD ID="distance" datatype="float" name="distance" ucd="pos.distance;pos.heliocentric" unit="pc"> +<DESCRIPTION>Distance from the barycenter of the Solar System to the barycenter of the source at J2010 reference epoch</DESCRIPTION> +</FIELD> +<FIELD ID="mualpha" datatype="float" name="mualpha" ucd="pos.pm;pos.eq.ra" unit="mas/a"> +<DESCRIPTION>Proper motion along right ascention at J2010 reference epoch</DESCRIPTION> +</FIELD> +<FIELD ID="mudelta" datatype="float" name="mudelta" ucd="pos.pm;pos.eq.dec" unit="mas/a"> +<DESCRIPTION>Proper motion along declination at J2010 reference epoch</DESCRIPTION> +</FIELD> +<FIELD ID="radialvelocity" datatype="float" name="radialvelocity" ucd="spect.dopplerVeloc;pos.heliocentric" unit="km/s"> +<DESCRIPTION>Radial Velocity at J2010 reference epoch</DESCRIPTION> +</FIELD> +<FIELD ID="ag" datatype="float" name="ag" ucd="phys.absorption;em.opt" unit="mag"> +<DESCRIPTION>Interstellar absorption in the G band assuming the extinction law of 1989ApJ...345..245C.</DESCRIPTION> +</FIELD> +<FIELD ID="av" datatype="float" name="av" ucd="phys.absorption;em.opt.V" unit="mag"> +<DESCRIPTION>Interstellar absorption in the V-band assuming the extinction law of 1989ApJ...345..245C.</DESCRIPTION> +</FIELD> +<FIELD ID="rv" datatype="float" name="rv" ucd="arith.diff;phys.absorption;em.opt.B;em.opt.V" unit="mag"> +<DESCRIPTION>Extinction parameter according to 2003A&A...409..205D.</DESCRIPTION> +</FIELD> +<FIELD ID="magg" datatype="float" name="magg" ucd="phot.mag;em.opt.V" unit="mag"> +<DESCRIPTION>GAIA G band apparent magnitude at reference epoch. The GAIA G-band has a wide bandpass between 350 and 150 nm. This is close to Johnson V for V-I between -0.4 and 1.4.</DESCRIPTION> +</FIELD> +<FIELD ID="maggbp" datatype="float" name="maggbp" ucd="phot.mag;em.opt.B" unit="mag"> +<DESCRIPTION>GAIA G_BP band apparent magnitude at reference epoch. The GAIA G_BP band has a bandpass between 350 and 770 nm.</DESCRIPTION> +</FIELD> +<FIELD ID="maggrp" datatype="float" name="maggrp" ucd="phot.mag;em.opt.R" unit="mag"> +<DESCRIPTION>GAIA G_RP band apparent magnitude at reference epoch. The GAIA G_RP band has a bandpass between 650 and 1050 nm.</DESCRIPTION> +</FIELD> +<FIELD ID="maggrvs" datatype="float" name="maggrvs" ucd="phot.mag;em.opt;em.opt.R" unit="mag"> +<DESCRIPTION>GAIA G_RVS band apparent magnitude at reference epoch. The GAIA G_RVS band has a narrow bandpass between 850 and 880 nm.</DESCRIPTION> +</FIELD> +<FIELD ID="type" arraysize="*" datatype="char" name="type"> +<DESCRIPTION>Supernova type (one of Ia, Ib/c, II-L, II-P)</DESCRIPTION> +</FIELD> +<FIELD ID="sourceid" datatype="long" name="sourceid" ucd="meta.id;meta.main"> +<DESCRIPTION>GUMS source identifier</DESCRIPTION> +<VALUES null='-9223372036854775808'/> +</FIELD> +<FIELD ID="sourceextendedid" arraysize="*" datatype="char" name="sourceextendedid" ucd="meta.id"> +<DESCRIPTION>GUMS extended source identifier</DESCRIPTION> +</FIELD> +<DATA> +<TABLEDATA> +</TABLEDATA> +</DATA> +</TABLE> +</RESOURCE> +</VOTABLE> diff --git a/test/tap/data/emptyset_binary.vot b/test/tap/data/emptyset_binary.vot new file mode 100644 index 0000000000000000000000000000000000000000..e123464d597c1fccbaf981edcad57d4553fc5491 --- /dev/null +++ b/test/tap/data/emptyset_binary.vot @@ -0,0 +1,125 @@ +<?xml version='1.0'?> +<VOTABLE version="1.2" + xmlns="http://www.ivoa.net/xml/VOTable/v1.2"> +<!-- + ! VOTable written by STIL version 3.0-5+ (uk.ac.starlink.votable.VOTableWriter) + ! at 2014-06-27T15:47:08 + !--> +<RESOURCE> +<TABLE name="sn" nrows="1"> +<PARAM arraysize="19" datatype="char" name="source" value="2012arXiv1202.0132R"/> +<PARAM arraysize="9" datatype="char" name="CoordFlavor" utype="stc:AstroCoordSystem.SpaceFrame.CoordFlavor" value="SPHERICAL"/> +<PARAM arraysize="1" datatype="char" name="coord_naxes" utype="stc:AstroCoordSystem.SpaceFrame.CoordFlavor.coord_naxes" value="3"/> +<PARAM arraysize="4" datatype="char" name="CoordRefFrame" utype="stc:AstroCoordSystem.SpaceFrame.CoordRefFrame" value="ICRS"/> +<PARAM arraysize="6" datatype="char" name="Epoch" utype="stc:AstroCoords.Position3D.Epoch" value="2010.0"/> +<PARAM arraysize="1" datatype="char" name="yearDef" utype="stc:AstroCoords.Position3D.Epoch.yearDef" value="J"/> +<PARAM arraysize="41" datatype="char" name="URI" utype="stc:DataModel.URI" value="http://www.ivoa.net/xml/STC/stc-v1.30.xsd"/> +<PARAM arraysize="31" datatype="char" name="server" value="http://dc.zah.uni-heidelberg.de"/> +<PARAM arraysize="69" datatype="char" name="query" value="SELECT * FROM gums.sn WHERE sourceid = 5227706337957249025 LIMIT 2000"/> +<PARAM arraysize="36" datatype="char" name="src_res" value="Contains traces from resource gums/q"> +<DESCRIPTION>GUMS-10 is the 10th version of the Gaia Universe Model Snapshot, a +simulation of the expected contents of the Gaia cataloge run at the +MareNostrum supercomputer. The models used and the characteristics of +GUMS-10 are described in: A.C. Robin et al, "Gaia Universe Model +Snapshot. A statistical analysis of the expected contents of the Gaia +catalogue", Astronomy & Astrophysics (2012), in press. For more +details see also http://gaia.am.ub.es/GUMS-10/</DESCRIPTION> +</PARAM> +<PARAM arraysize="34" datatype="char" name="src_table" value="Contains traces from table gums.sn"> +<DESCRIPTION>Supernovae in the GUMS-10 simulated GAIA result set.</DESCRIPTION> +</PARAM> +<PARAM arraysize="54" datatype="char" name="copyright" value="Content from gums/q has rights note (see INFO content)"> +<DESCRIPTION>If you use this data, please acknowledge that GUMS was created using +the MareNostrum supercomputer.</DESCRIPTION> +</PARAM> +<PARAM arraysize="2" datatype="char" name="QUERY_STATUS" value="OK"> +<DESCRIPTION>Query successful</DESCRIPTION> +</PARAM> +<PARAM arraysize="11" datatype="char" name="Service short name" value="GAVO DC TAP"> +<DESCRIPTION>Short name for TAP service</DESCRIPTION> +</PARAM> +<PARAM arraysize="28" datatype="char" name="Service title" value="GAVO Data Center TAP service"> +<DESCRIPTION>TAP service title</DESCRIPTION> +</PARAM> +<PARAM arraysize="36" datatype="char" name="Identifier" value="ivo://org.gavo.dc/__system__/tap/run"> +<DESCRIPTION>Unique resource registry identifier</DESCRIPTION> +</PARAM> +<PARAM arraysize="16" datatype="char" name="Service publisher" value="The GAVO DC team"> +<DESCRIPTION>Publisher for TAP service</DESCRIPTION> +</PARAM> +<PARAM arraysize="55" datatype="char" name="Service reference URL" value="http://dc.zah.uni-heidelberg.de/__system__/tap/run/info"> +<DESCRIPTION>Descriptive URL for search resource</DESCRIPTION> +</PARAM> +<PARAM arraysize="50" datatype="char" name="Contact person" value="GAVO Data Center Team <gavo@ari.uni-heidelberg.de>"> +<DESCRIPTION>Individual to contact about this service</DESCRIPTION> +</PARAM> +<FIELD ID="v" datatype="float" name="v" unit="mag"> +<DESCRIPTION>Intrinsic apparent V magnitude</DESCRIPTION> +</FIELD> +<FIELD ID="colorvminusi" datatype="float" name="colorvminusi" ucd="phot.color;em.opt.V;em.opt.I" unit="mag"> +<DESCRIPTION>Intrinsic V-I color.</DESCRIPTION> +</FIELD> +<FIELD ID="meanabsolutev" datatype="float" name="meanabsolutev" ucd="phot.mag;em.opt.V" unit="mag"> +<DESCRIPTION>Mean absolute V magnitude.</DESCRIPTION> +</FIELD> +<FIELD ID="redshift" datatype="float" name="redshift" ucd="src.redshift"> +<DESCRIPTION>Object redshift.</DESCRIPTION> +</FIELD> +<FIELD ID="alpha" datatype="double" name="alpha" ucd="pos.eq.ra;meta.main" unit="deg"> +<DESCRIPTION>Right ascention of the barycenter at J2010 reference epoch in the ICRS frame</DESCRIPTION> +</FIELD> +<FIELD ID="delta" datatype="double" name="delta" ucd="pos.eq.dec;meta.main" unit="deg"> +<DESCRIPTION>Declination of the barycenter at J2010 reference epoch in the ICRS frame</DESCRIPTION> +</FIELD> +<FIELD ID="distance" datatype="float" name="distance" ucd="pos.distance;pos.heliocentric" unit="pc"> +<DESCRIPTION>Distance from the barycenter of the Solar System to the barycenter of the source at J2010 reference epoch</DESCRIPTION> +</FIELD> +<FIELD ID="mualpha" datatype="float" name="mualpha" ucd="pos.pm;pos.eq.ra" unit="mas/a"> +<DESCRIPTION>Proper motion along right ascention at J2010 reference epoch</DESCRIPTION> +</FIELD> +<FIELD ID="mudelta" datatype="float" name="mudelta" ucd="pos.pm;pos.eq.dec" unit="mas/a"> +<DESCRIPTION>Proper motion along declination at J2010 reference epoch</DESCRIPTION> +</FIELD> +<FIELD ID="radialvelocity" datatype="float" name="radialvelocity" ucd="spect.dopplerVeloc;pos.heliocentric" unit="km/s"> +<DESCRIPTION>Radial Velocity at J2010 reference epoch</DESCRIPTION> +</FIELD> +<FIELD ID="ag" datatype="float" name="ag" ucd="phys.absorption;em.opt" unit="mag"> +<DESCRIPTION>Interstellar absorption in the G band assuming the extinction law of 1989ApJ...345..245C.</DESCRIPTION> +</FIELD> +<FIELD ID="av" datatype="float" name="av" ucd="phys.absorption;em.opt.V" unit="mag"> +<DESCRIPTION>Interstellar absorption in the V-band assuming the extinction law of 1989ApJ...345..245C.</DESCRIPTION> +</FIELD> +<FIELD ID="rv" datatype="float" name="rv" ucd="arith.diff;phys.absorption;em.opt.B;em.opt.V" unit="mag"> +<DESCRIPTION>Extinction parameter according to 2003A&A...409..205D.</DESCRIPTION> +</FIELD> +<FIELD ID="magg" datatype="float" name="magg" ucd="phot.mag;em.opt.V" unit="mag"> +<DESCRIPTION>GAIA G band apparent magnitude at reference epoch. The GAIA G-band has a wide bandpass between 350 and 150 nm. This is close to Johnson V for V-I between -0.4 and 1.4.</DESCRIPTION> +</FIELD> +<FIELD ID="maggbp" datatype="float" name="maggbp" ucd="phot.mag;em.opt.B" unit="mag"> +<DESCRIPTION>GAIA G_BP band apparent magnitude at reference epoch. The GAIA G_BP band has a bandpass between 350 and 770 nm.</DESCRIPTION> +</FIELD> +<FIELD ID="maggrp" datatype="float" name="maggrp" ucd="phot.mag;em.opt.R" unit="mag"> +<DESCRIPTION>GAIA G_RP band apparent magnitude at reference epoch. The GAIA G_RP band has a bandpass between 650 and 1050 nm.</DESCRIPTION> +</FIELD> +<FIELD ID="maggrvs" datatype="float" name="maggrvs" ucd="phot.mag;em.opt;em.opt.R" unit="mag"> +<DESCRIPTION>GAIA G_RVS band apparent magnitude at reference epoch. The GAIA G_RVS band has a narrow bandpass between 850 and 880 nm.</DESCRIPTION> +</FIELD> +<FIELD ID="type" arraysize="*" datatype="char" name="type"> +<DESCRIPTION>Supernova type (one of Ia, Ib/c, II-L, II-P)</DESCRIPTION> +</FIELD> +<FIELD ID="sourceid" datatype="long" name="sourceid" ucd="meta.id;meta.main"> +<DESCRIPTION>GUMS source identifier</DESCRIPTION> +<VALUES null='-9223372036854775808'/> +</FIELD> +<FIELD ID="sourceextendedid" arraysize="*" datatype="char" name="sourceextendedid" ucd="meta.id"> +<DESCRIPTION>GUMS extended source identifier</DESCRIPTION> +</FIELD> +<DATA> +<BINARY> +<STREAM encoding='base64'> +</STREAM> +</BINARY> +</DATA> +</TABLE> +</RESOURCE> +</VOTABLE> diff --git a/test/tap/data/testdata.vot b/test/tap/data/testdata.vot new file mode 100644 index 0000000000000000000000000000000000000000..bfec957f865ae0e186109adc3edafb4163f34872 --- /dev/null +++ b/test/tap/data/testdata.vot @@ -0,0 +1,676 @@ +<?xml version='1.0'?> +<VOTABLE version="1.2" + xmlns="http://www.ivoa.net/xml/VOTable/v1.2"> +<!-- + ! VOTable written by STIL version 3.0-5+ (uk.ac.starlink.votable.VOTableWriter) + ! at 2014-06-27T15:28:34 + !--> +<RESOURCE> +<TABLE name="sn" nrows="100"> +<PARAM arraysize="19" datatype="char" name="source" value="2012arXiv1202.0132R"/> +<PARAM arraysize="9" datatype="char" name="CoordFlavor" utype="stc:AstroCoordSystem.SpaceFrame.CoordFlavor" value="SPHERICAL"/> +<PARAM arraysize="1" datatype="char" name="coord_naxes" utype="stc:AstroCoordSystem.SpaceFrame.CoordFlavor.coord_naxes" value="3"/> +<PARAM arraysize="4" datatype="char" name="CoordRefFrame" utype="stc:AstroCoordSystem.SpaceFrame.CoordRefFrame" value="ICRS"/> +<PARAM arraysize="6" datatype="char" name="Epoch" utype="stc:AstroCoords.Position3D.Epoch" value="2010.0"/> +<PARAM arraysize="1" datatype="char" name="yearDef" utype="stc:AstroCoords.Position3D.Epoch.yearDef" value="J"/> +<PARAM arraysize="41" datatype="char" name="URI" utype="stc:DataModel.URI" value="http://www.ivoa.net/xml/STC/stc-v1.30.xsd"/> +<PARAM arraysize="31" datatype="char" name="server" value="http://dc.zah.uni-heidelberg.de"/> +<PARAM arraysize="58" datatype="char" name="query" value="SELECT sourceid, alpha, delta, magg FROM gums.sn LIMIT 100"/> +<PARAM arraysize="36" datatype="char" name="src_res" value="Contains traces from resource gums/q"> +<DESCRIPTION>GUMS-10 is the 10th version of the Gaia Universe Model Snapshot, a +simulation of the expected contents of the Gaia cataloge run at the +MareNostrum supercomputer. The models used and the characteristics of +GUMS-10 are described in: A.C. Robin et al, "Gaia Universe Model +Snapshot. A statistical analysis of the expected contents of the Gaia +catalogue", Astronomy & Astrophysics (2012), in press. For more +details see also http://gaia.am.ub.es/GUMS-10/</DESCRIPTION> +</PARAM> +<PARAM arraysize="34" datatype="char" name="src_table" value="Contains traces from table gums.sn"> +<DESCRIPTION>Supernovae in the GUMS-10 simulated GAIA result set.</DESCRIPTION> +</PARAM> +<PARAM arraysize="54" datatype="char" name="copyright" value="Content from gums/q has rights note (see INFO content)"> +<DESCRIPTION>If you use this data, please acknowledge that GUMS was created using +the MareNostrum supercomputer.</DESCRIPTION> +</PARAM> +<PARAM arraysize="2" datatype="char" name="QUERY_STATUS" value="OK"> +<DESCRIPTION>Query successful</DESCRIPTION> +</PARAM> +<PARAM arraysize="8" datatype="char" name="QUERY_STATUS" value="OVERFLOW"/> +<PARAM arraysize="11" datatype="char" name="Service short name" value="GAVO DC TAP"> +<DESCRIPTION>Short name for TAP service</DESCRIPTION> +</PARAM> +<PARAM arraysize="28" datatype="char" name="Service title" value="GAVO Data Center TAP service"> +<DESCRIPTION>TAP service title</DESCRIPTION> +</PARAM> +<PARAM arraysize="36" datatype="char" name="Identifier" value="ivo://org.gavo.dc/__system__/tap/run"> +<DESCRIPTION>Unique resource registry identifier</DESCRIPTION> +</PARAM> +<PARAM arraysize="16" datatype="char" name="Service publisher" value="The GAVO DC team"> +<DESCRIPTION>Publisher for TAP service</DESCRIPTION> +</PARAM> +<PARAM arraysize="55" datatype="char" name="Service reference URL" value="http://dc.zah.uni-heidelberg.de/__system__/tap/run/info"> +<DESCRIPTION>Descriptive URL for search resource</DESCRIPTION> +</PARAM> +<PARAM arraysize="50" datatype="char" name="Contact person" value="GAVO Data Center Team <gavo@ari.uni-heidelberg.de>"> +<DESCRIPTION>Individual to contact about this service</DESCRIPTION> +</PARAM> +<FIELD ID="sourceid" datatype="long" name="sourceid" ucd="meta.id;meta.main"> +<DESCRIPTION>GUMS source identifier</DESCRIPTION> +<VALUES null='-9223372036854775808'/> +</FIELD> +<FIELD ID="alpha" datatype="double" name="alpha" ucd="pos.eq.ra;meta.main" unit="deg"> +<DESCRIPTION>Right ascention of the barycenter at J2010 reference epoch in the ICRS frame</DESCRIPTION> +</FIELD> +<FIELD ID="delta" datatype="double" name="delta" ucd="pos.eq.dec;meta.main" unit="deg"> +<DESCRIPTION>Declination of the barycenter at J2010 reference epoch in the ICRS frame</DESCRIPTION> +</FIELD> +<FIELD ID="magg" datatype="float" name="magg" ucd="phot.mag;em.opt.V" unit="mag"> +<DESCRIPTION>GAIA G band apparent magnitude at reference epoch. The GAIA G-band has a wide bandpass between 350 and 150 nm. This is close to Johnson V for V-I between -0.4 and 1.4.</DESCRIPTION> +</FIELD> +<DATA> +<TABLEDATA> + <TR> + <TD>5227706337957249025</TD> + <TD>315.196288862219</TD> + <TD>35.8348069501976</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228535898005569537</TD> + <TD>316.147921016408</TD> + <TD>36.6446327038496</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228619830256467969</TD> + <TD>318.330750006546</TD> + <TD>37.1427090694981</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228490199553540097</TD> + <TD>317.277486660807</TD> + <TD>37.0393622283472</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228526638056079361</TD> + <TD>315.539651502155</TD> + <TD>36.8330799223032</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228191235470000129</TD> + <TD>314.547544336433</TD> + <TD>37.0316381891978</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228254186805657601</TD> + <TD>313.515158379912</TD> + <TD>37.4594494511725</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228511485411459073</TD> + <TD>315.14630133005</TD> + <TD>37.30463920468</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228510390194798593</TD> + <TD>315.138724413456</TD> + <TD>37.3939357419666</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228207019474812929</TD> + <TD>315.105090571779</TD> + <TD>37.7967663884429</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228645273642729473</TD> + <TD>316.445593967068</TD> + <TD>37.7724610890285</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228210176275775489</TD> + <TD>314.202309571622</TD> + <TD>37.7622018074421</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228340180640858113</TD> + <TD>313.926940760892</TD> + <TD>38.1681256686532</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228338668812369921</TD> + <TD>313.90078126178</TD> + <TD>38.3468303111387</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228678658423521281</TD> + <TD>318.638315340027</TD> + <TD>37.4599061823721</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228643048849670145</TD> + <TD>319.842618598044</TD> + <TD>37.9120544280358</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228662732684787713</TD> + <TD>317.822382752931</TD> + <TD>37.730199142655</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228557072194338817</TD> + <TD>320.851132165837</TD> + <TD>38.0701678757365</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228059294074667009</TD> + <TD>322.683603029896</TD> + <TD>38.732846513021</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5227925888095485953</TD> + <TD>320.553882864028</TD> + <TD>38.6789639187946</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5227935367088308225</TD> + <TD>320.101290659979</TD> + <TD>39.0461898040604</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5227934688483475457</TD> + <TD>320.567657954422</TD> + <TD>39.2569187331424</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228419671895572481</TD> + <TD>316.501197124071</TD> + <TD>38.3542948966148</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228404837078532097</TD> + <TD>317.530403840919</TD> + <TD>39.5711378023383</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228457149780197377</TD> + <TD>319.129957970345</TD> + <TD>38.8903631574443</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228411159270391809</TD> + <TD>318.350167533456</TD> + <TD>39.3739776364656</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228411343953985537</TD> + <TD>318.482291321702</TD> + <TD>39.4682813466895</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224886425639452673</TD> + <TD>319.915330168399</TD> + <TD>40.5474606685377</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5226038743890132993</TD> + <TD>310.809142713647</TD> + <TD>37.2981603041502</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225901627059208193</TD> + <TD>310.195297620624</TD> + <TD>38.1682983805255</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228389010124046337</TD> + <TD>314.311278360606</TD> + <TD>39.1132344243341</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228357485064093697</TD> + <TD>313.765487694087</TD> + <TD>39.2010205946055</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228357416344616961</TD> + <TD>313.948253770717</TD> + <TD>39.2341334918952</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228138918473367553</TD> + <TD>311.600215055814</TD> + <TD>38.7829579962378</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225905883371798529</TD> + <TD>309.209065483013</TD> + <TD>38.3922939934094</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225922745413402625</TD> + <TD>308.273187634308</TD> + <TD>38.623472717439</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228170748475998209</TD> + <TD>311.504809355259</TD> + <TD>39.2736949239031</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228128756580745217</TD> + <TD>310.060117657241</TD> + <TD>39.6150923667196</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228125286247170049</TD> + <TD>310.391975607677</TD> + <TD>39.8567447863678</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224523603982155777</TD> + <TD>310.152548466881</TD> + <TD>40.5933397790503</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228287051895406593</TD> + <TD>315.254195083038</TD> + <TD>40.0540124515679</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228273862050840577</TD> + <TD>316.999352337993</TD> + <TD>40.027560397733</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225021858843197441</TD> + <TD>318.644478458537</TD> + <TD>40.6779438099924</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225035018622992385</TD> + <TD>317.991463519871</TD> + <TD>40.9677441144194</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225072127140429825</TD> + <TD>316.867441178056</TD> + <TD>41.9057772663151</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225072367658598401</TD> + <TD>317.075907997518</TD> + <TD>41.9597478851952</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224716538208059393</TD> + <TD>313.033381590424</TD> + <TD>41.0862110982932</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224690454871670785</TD> + <TD>311.948458977198</TD> + <TD>41.2530675452654</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225070142865539073</TD> + <TD>317.083554655278</TD> + <TD>42.1259327238697</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224684089730138113</TD> + <TD>314.089161892257</TD> + <TD>41.9708284872533</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224636059110866945</TD> + <TD>314.400321502975</TD> + <TD>42.3087726851734</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224644606095785985</TD> + <TD>313.645709386859</TD> + <TD>42.4971549481861</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225193335412490241</TD> + <TD>315.244056852409</TD> + <TD>42.906387451096</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228101612387434497</TD> + <TD>323.946749631999</TD> + <TD>38.9774811407551</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228088950823845889</TD> + <TD>322.965760533976</TD> + <TD>39.4816358229734</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228086506987454465</TD> + <TD>322.524642165751</TD> + <TD>39.3913412985295</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228082809020612609</TD> + <TD>323.086525996038</TD> + <TD>39.9569058778203</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5228085098238181377</TD> + <TD>323.378976745126</TD> + <TD>39.9909965671913</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5227900238550794241</TD> + <TD>325.947644795287</TD> + <TD>39.8622684927386</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224755742669537281</TD> + <TD>327.292078064864</TD> + <TD>40.473580488463</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224801402466861057</TD> + <TD>326.41569461502</TD> + <TD>41.1675012881196</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224907135971753985</TD> + <TD>321.814585593307</TD> + <TD>40.5017107987482</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224912689364467713</TD> + <TD>322.474668103376</TD> + <TD>40.7876461525313</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224941637444042753</TD> + <TD>320.738328210729</TD> + <TD>40.5629925694948</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224940666781433857</TD> + <TD>320.250893992984</TD> + <TD>41.1634130035394</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224927141929418753</TD> + <TD>321.863542181784</TD> + <TD>41.5729254211298</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224986902104375297</TD> + <TD>325.246238155948</TD> + <TD>42.1565777812423</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225019698474647553</TD> + <TD>323.396785057197</TD> + <TD>41.5880307398769</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224955600382722049</TD> + <TD>322.517800858037</TD> + <TD>41.8237610271847</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224831699166167041</TD> + <TD>323.118494600869</TD> + <TD>42.3750358062487</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224858555596668929</TD> + <TD>324.918116160156</TD> + <TD>42.3752514943318</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224856356573413377</TD> + <TD>324.4784816304</TD> + <TD>42.46964115857</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260489398125854721</TD> + <TD>328.501192472745</TD> + <TD>40.7150346615374</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5264154912194822145</TD> + <TD>328.849577108117</TD> + <TD>41.0695787815177</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260548449631207425</TD> + <TD>328.800988064444</TD> + <TD>42.0664845440737</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224757619570245633</TD> + <TD>326.101379574238</TD> + <TD>41.806210370532</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224756915195609089</TD> + <TD>326.471956864544</TD> + <TD>42.0126282312272</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260532828835151873</TD> + <TD>327.435294140766</TD> + <TD>42.3992262672942</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260531072193527809</TD> + <TD>327.198909516082</TD> + <TD>42.7478419636105</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260542758799540225</TD> + <TD>327.887606567932</TD> + <TD>42.6236566188535</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260660973479395329</TD> + <TD>326.073858008429</TD> + <TD>43.3546455828375</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260725440938508289</TD> + <TD>326.558221138756</TD> + <TD>43.4106167711329</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5264186024937914369</TD> + <TD>329.486489620386</TD> + <TD>42.6516399387462</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260511212264751105</TD> + <TD>328.31979095659</TD> + <TD>43.1663725965885</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5264374758685802497</TD> + <TD>329.515222942698</TD> + <TD>43.9904808369981</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5264303453638754305</TD> + <TD>329.435473863596</TD> + <TD>44.0758732707729</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5260592159513378817</TD> + <TD>329.128518386386</TD> + <TD>44.2614704113209</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225085673467281409</TD> + <TD>319.120731512924</TD> + <TD>41.5540952888462</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224915403783798785</TD> + <TD>320.791989793507</TD> + <TD>42.2286522853318</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225266367036391425</TD> + <TD>320.762347236735</TD> + <TD>42.4649033314846</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224960535300145153</TD> + <TD>322.54003062151</TD> + <TD>42.2407563101143</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224862219203772417</TD> + <TD>323.333101161478</TD> + <TD>42.5494790946244</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224835594701504513</TD> + <TD>322.065062640506</TD> + <TD>43.1338723489886</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225263253185101825</TD> + <TD>316.390889854207</TD> + <TD>42.7484218698054</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225213848176295937</TD> + <TD>316.472765214816</TD> + <TD>43.499451176508</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225112469768241153</TD> + <TD>319.657659923454</TD> + <TD>43.4408787249805</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225153065799122945</TD> + <TD>320.387669861088</TD> + <TD>43.8725637888719</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5225098042973093889</TD> + <TD>321.970847371195</TD> + <TD>44.2731477586804</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224328779970641921</TD> + <TD>321.402786393259</TD> + <TD>44.5459368319667</TD> + <TD>0.0</TD> + </TR> + <TR> + <TD>5224353149615079425</TD> + <TD>318.918788589935</TD> + <TD>44.3809159912124</TD> + <TD>0.0</TD> + </TR> +</TABLEDATA> +</DATA> +</TABLE> +</RESOURCE> +</VOTABLE> diff --git a/test/tap/data/testdata_binary.vot b/test/tap/data/testdata_binary.vot new file mode 100644 index 0000000000000000000000000000000000000000..829a5b88f3bfbf8b803d35405779860be2e4d303 --- /dev/null +++ b/test/tap/data/testdata_binary.vot @@ -0,0 +1,137 @@ +<?xml version='1.0'?> +<VOTABLE version="1.2" + xmlns="http://www.ivoa.net/xml/VOTable/v1.2"> +<!-- + ! VOTable written by STIL version 3.0-5+ (uk.ac.starlink.votable.VOTableWriter) + ! at 2014-06-27T15:28:54 + !--> +<RESOURCE> +<TABLE name="sn" nrows="100"> +<PARAM arraysize="19" datatype="char" name="source" value="2012arXiv1202.0132R"/> +<PARAM arraysize="9" datatype="char" name="CoordFlavor" utype="stc:AstroCoordSystem.SpaceFrame.CoordFlavor" value="SPHERICAL"/> +<PARAM arraysize="1" datatype="char" name="coord_naxes" utype="stc:AstroCoordSystem.SpaceFrame.CoordFlavor.coord_naxes" value="3"/> +<PARAM arraysize="4" datatype="char" name="CoordRefFrame" utype="stc:AstroCoordSystem.SpaceFrame.CoordRefFrame" value="ICRS"/> +<PARAM arraysize="6" datatype="char" name="Epoch" utype="stc:AstroCoords.Position3D.Epoch" value="2010.0"/> +<PARAM arraysize="1" datatype="char" name="yearDef" utype="stc:AstroCoords.Position3D.Epoch.yearDef" value="J"/> +<PARAM arraysize="41" datatype="char" name="URI" utype="stc:DataModel.URI" value="http://www.ivoa.net/xml/STC/stc-v1.30.xsd"/> +<PARAM arraysize="31" datatype="char" name="server" value="http://dc.zah.uni-heidelberg.de"/> +<PARAM arraysize="58" datatype="char" name="query" value="SELECT sourceid, alpha, delta, magg FROM gums.sn LIMIT 100"/> +<PARAM arraysize="36" datatype="char" name="src_res" value="Contains traces from resource gums/q"> +<DESCRIPTION>GUMS-10 is the 10th version of the Gaia Universe Model Snapshot, a +simulation of the expected contents of the Gaia cataloge run at the +MareNostrum supercomputer. The models used and the characteristics of +GUMS-10 are described in: A.C. Robin et al, "Gaia Universe Model +Snapshot. A statistical analysis of the expected contents of the Gaia +catalogue", Astronomy & Astrophysics (2012), in press. For more +details see also http://gaia.am.ub.es/GUMS-10/</DESCRIPTION> +</PARAM> +<PARAM arraysize="34" datatype="char" name="src_table" value="Contains traces from table gums.sn"> +<DESCRIPTION>Supernovae in the GUMS-10 simulated GAIA result set.</DESCRIPTION> +</PARAM> +<PARAM arraysize="54" datatype="char" name="copyright" value="Content from gums/q has rights note (see INFO content)"> +<DESCRIPTION>If you use this data, please acknowledge that GUMS was created using +the MareNostrum supercomputer.</DESCRIPTION> +</PARAM> +<PARAM arraysize="2" datatype="char" name="QUERY_STATUS" value="OK"> +<DESCRIPTION>Query successful</DESCRIPTION> +</PARAM> +<PARAM arraysize="8" datatype="char" name="QUERY_STATUS" value="OVERFLOW"/> +<PARAM arraysize="11" datatype="char" name="Service short name" value="GAVO DC TAP"> +<DESCRIPTION>Short name for TAP service</DESCRIPTION> +</PARAM> +<PARAM arraysize="28" datatype="char" name="Service title" value="GAVO Data Center TAP service"> +<DESCRIPTION>TAP service title</DESCRIPTION> +</PARAM> +<PARAM arraysize="36" datatype="char" name="Identifier" value="ivo://org.gavo.dc/__system__/tap/run"> +<DESCRIPTION>Unique resource registry identifier</DESCRIPTION> +</PARAM> +<PARAM arraysize="16" datatype="char" name="Service publisher" value="The GAVO DC team"> +<DESCRIPTION>Publisher for TAP service</DESCRIPTION> +</PARAM> +<PARAM arraysize="55" datatype="char" name="Service reference URL" value="http://dc.zah.uni-heidelberg.de/__system__/tap/run/info"> +<DESCRIPTION>Descriptive URL for search resource</DESCRIPTION> +</PARAM> +<PARAM arraysize="50" datatype="char" name="Contact person" value="GAVO Data Center Team <gavo@ari.uni-heidelberg.de>"> +<DESCRIPTION>Individual to contact about this service</DESCRIPTION> +</PARAM> +<FIELD ID="sourceid" datatype="long" name="sourceid" ucd="meta.id;meta.main"> +<DESCRIPTION>GUMS source identifier</DESCRIPTION> +<VALUES null='-9223372036854775808'/> +</FIELD> +<FIELD ID="alpha" datatype="double" name="alpha" ucd="pos.eq.ra;meta.main" unit="deg"> +<DESCRIPTION>Right ascention of the barycenter at J2010 reference epoch in the ICRS frame</DESCRIPTION> +</FIELD> +<FIELD ID="delta" datatype="double" name="delta" ucd="pos.eq.dec;meta.main" unit="deg"> +<DESCRIPTION>Declination of the barycenter at J2010 reference epoch in the ICRS frame</DESCRIPTION> +</FIELD> +<FIELD ID="magg" datatype="float" name="magg" ucd="phot.mag;em.opt.V" unit="mag"> +<DESCRIPTION>GAIA G band apparent magnitude at reference epoch. The GAIA G-band has a wide bandpass between 350 and 150 nm. This is close to Johnson V for V-I between -0.4 and 1.4.</DESCRIPTION> +</FIELD> +<DATA> +<BINARY> +<STREAM encoding='base64'> +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 +W6obV0BGMMHa7mPtAAAAAA== +</STREAM> +</BINARY> +</DATA> +</TABLE> +</RESOURCE> +</VOTABLE>