Commit 6f607bc6 authored by gmantele's avatar gmantele
Browse files

[ADQL,TAP] Add geometry format in output and correct upload of STC-S regions....

[ADQL,TAP] Add geometry format in output and correct upload of STC-S regions. Geometrical type conversion from and into a DB type is now required in all JDBCTranslator. This allows formatting of geometrical column value coming from the database, but also the translation of STC-S expressions provided in uploaded table into geometrical column values.
parent 9d511687
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -1236,7 +1236,7 @@ public final class STCS {
	 * Let parse any STC-S expression.
	 * 
	 * @author Grégory Mantelet (ARI)
	 * @version 1.3 (10/2014)
	 * @version 1.3 (11/2014)
	 * @since 1.3
	 */
	private static class STCSParser {
@@ -1318,7 +1318,7 @@ public final class STCS {
		 * @param newStcs	New STC-S expression to parse from now.
		 */
		private void init(final String newStcs){
			stcs = (newStcs == null) ? "" : newStcs.replaceAll("\\s", " ");
			stcs = (newStcs == null) ? "" : newStcs;
			token = null;
			buffer = new StringBuffer();
			pos = 0;
@@ -1351,7 +1351,7 @@ public final class STCS {
		 * Tool function which skip all next space characters until the next meaningful characters. 
		 */
		private void skipSpaces(){
			while(pos < stcs.length() && stcs.charAt(pos) == ' ')
			while(pos < stcs.length() && Character.isWhitespace(stcs.charAt(pos)))
				pos++;
		}

@@ -1371,7 +1371,7 @@ public final class STCS {
			skipSpaces();

			// Fetch all characters until word separator (a space or a open/close parenthesis):
			while(pos < stcs.length() && stcs.charAt(pos) != ' ' && stcs.charAt(pos) != '(' && stcs.charAt(pos) != ')')
			while(pos < stcs.length() && !Character.isWhitespace(stcs.charAt(pos)) && stcs.charAt(pos) != '(' && stcs.charAt(pos) != ')')
				buffer.append(stcs.charAt(pos++));

			// If no character has been fetched while at least one was expected, throw an exception:
+84 −6
Original line number Diff line number Diff line
@@ -23,9 +23,13 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import tap.data.DataReadException;
import adql.db.DBColumn;
import adql.db.DBTable;
import adql.db.DBType;
import adql.db.STCS.Region;
import adql.db.exception.UnresolvedJoin;
import adql.parser.ParseException;
import adql.query.ADQLList;
import adql.query.ADQLObject;
import adql.query.ADQLOrder;
@@ -93,8 +97,9 @@ import adql.query.operand.function.geometry.RegionFunction;
 * <h3>PostgreSQLTranslator and PgSphereTranslator</h3>
 * 
 * <p>
 * 	{@link PgSphereTranslator} extends {@link PostgreSQLTranslator} and is just translating geometrical
 * 	functions according to the syntax given by PgSphere.
 * 	{@link PgSphereTranslator} extends {@link PostgreSQLTranslator} and is able to translate geometrical
 * 	functions according to the syntax given by PgSphere. But it can also convert geometrical types
 * 	(from and toward the database), translate PgSphere regions into STC expression and vice-versa.
 * </p>
 * 
 * <p>
@@ -150,8 +155,8 @@ import adql.query.operand.function.geometry.RegionFunction;
 * </p>
 * 
 * <p><i>Note:
 * 	Geometrical function have not been translated here. They stay abstract because it is obviously impossible to have a generic
 * 	translation ; it totally depends from the database system.
 * 	Geometrical regions and types have not been managed here. They stay abstract because it is obviously impossible to have a generic
 * 	translation and conversion ; it totally depends from the database system.
 * </i></p>
 * 
 * <h3>Translation of "FROM" with JOINs</h3>
@@ -162,8 +167,8 @@ import adql.query.operand.function.geometry.RegionFunction;
 * </p>
 * 
 * @author Gr&eacute;gory Mantelet (ARI)
 * @version 1.3 (09/2014)
 * @since 2.0
 * @version 1.3 (11/2014)
 * @since 1.3
 * 
 * @see PostgreSQLTranslator
 * @see PgSphereTranslator
@@ -802,4 +807,77 @@ public abstract class JDBCTranslator implements ADQLTranslator {
		return translate(geomValue.getValue());
	}

	/**
	 * Convert any type provided by a JDBC driver into a type understandable by the ADQL/TAP library.
	 * 
	 * @param dbmsType			Type returned by a JDBC driver. <i>Note: this value is returned by ResultSetMetadata.getColumnType(int) and correspond to a type of java.sql.Types</i>
	 * @param rawDbmsTypeName	Full name of the type returned by a JDBC driver. <i>Note: this name is returned by ResultSetMetadata.getColumnTypeName(int) ; this name may contain parameters</i>
	 * @param dbmsTypeName		Name of type, without the eventual parameters. <i>Note: this name is extracted from rawDbmsTypeName.</i>
	 * @param typeParams		The eventual type parameters (e.g. char string length). <i>Note: these parameters are extracted from rawDbmsTypeName.</i>
	 * 
	 * @return	The corresponding ADQL/TAP type or NULL if the specified type is unknown.
	 */
	public abstract DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, final String dbmsTypeName, final String[] typeParams);

	/**
	 * <p>Convert any type provided by the ADQL/TAP library into a type understandable by a JDBC driver.</p>
	 * 
	 * <p><i>Note:
	 * 	The returned DBMS type may contain some parameters between brackets.
	 * </i></p>
	 * 
	 * @param type	The ADQL/TAP library's type to convert.
	 * 
	 * @return	The corresponding DBMS type or NULL if the specified type is unknown.
	 */
	public abstract String convertTypeToDB(final DBType type);

	/**
	 * <p>Parse the given JDBC column value as a geometry object and convert it into a {@link Region}.</p>
	 * 
	 * <p><i>Note:
	 * 	Generally the returned object will be used to get its STC-S expression.
	 * </i></p>
	 * 
	 * <p><i>Note:
	 * 	If the given column value is NULL, NULL will be returned.
	 * </i></p>
	 * 
	 * <p><i><b>Important note:</b>
	 * 	This function is called ONLY for value of columns flagged as geometries by
	 * 	{@link #convertTypeFromDB(int, String, String, String[])}. So the value should always
	 * 	be of the expected type and format. However, if it turns out that the type is wrong
	 * 	and that the conversion is finally impossible, this function SHOULD throw a
	 * 	{@link DataReadException}.
	 * </i></p>
	 * 
	 * @param jdbcColValue	A JDBC column value (returned by ResultSet.getObject(int)).
	 * 
	 * @return	The corresponding {@link Region} if the given value is a geometry.
	 * 
	 * @throws ParseException	If the given object is not a geometrical object
	 *                       	or can not be transformed into a {@link Region} object.
	 */
	public abstract Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException;

	/**
	 * <p>Convert the given STC region into a DB column value.</p>
	 * 
	 * <p><i>Note:
	 * 	This function is used only by the UPLOAD feature, to import geometries provided as STC-S expression in
	 * 	a VOTable document inside a DB column.
	 * </i></p>
	 * 
	 * <p><i>Note:
	 * 	If the given region is NULL, NULL will be returned.
	 * </i></p>
	 * 
	 * @param stcs	The region to store in the DB.
	 * 
	 * @return	The corresponding DB column object.
	 * 
	 * @throws ParseException	If the given STC Region can not be converted into a DB object.
	 */
	public abstract Object translateGeometryToDB(final Region region) throws ParseException;

}
+553 −6

File changed.

Preview size limit exceeded, changes collapsed.

+109 −1
Original line number Diff line number Diff line
@@ -20,6 +20,10 @@ package adql.translator;
 *                       Astronomisches Rechen Institut (ARI)
 */

import adql.db.DBType;
import adql.db.DBType.DBDatatype;
import adql.db.STCS.Region;
import adql.parser.ParseException;
import adql.query.IdentifierField;
import adql.query.operand.StringConstant;
import adql.query.operand.function.MathFunction;
@@ -46,7 +50,7 @@ import adql.query.operand.function.geometry.RegionFunction;
 * </i></p>
 * 
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 1.3 (10/2014)
 * @version 1.3 (11/2014)
 * 
 * @see PgSphereTranslator
 */
@@ -188,4 +192,108 @@ public class PostgreSQLTranslator extends JDBCTranslator {
		return getDefaultADQLFunction(region);
	}

	@Override
	public DBType convertTypeFromDB(final int dbmsType, final String rawDbmsTypeName, String dbmsTypeName, final String[] params){
		// If no type is provided return VARCHAR:
		if (dbmsTypeName == null || dbmsTypeName.trim().length() == 0)
			return new DBType(DBDatatype.VARCHAR, DBType.NO_LENGTH);

		// Put the dbmsTypeName in lower case for the following comparisons:
		dbmsTypeName = dbmsTypeName.toLowerCase();

		// Extract the length parameter (always the first one):
		int lengthParam = DBType.NO_LENGTH;
		if (params != null && params.length > 0){
			try{
				lengthParam = Integer.parseInt(params[0]);
			}catch(NumberFormatException nfe){}
		}

		// SMALLINT
		if (dbmsTypeName.equals("smallint") || dbmsTypeName.equals("int2") || dbmsTypeName.equals("smallserial") || dbmsTypeName.equals("serial2") || dbmsTypeName.equals("boolean") || dbmsTypeName.equals("bool"))
			return new DBType(DBDatatype.SMALLINT);
		// INTEGER
		else if (dbmsTypeName.equals("integer") || dbmsTypeName.equals("int") || dbmsTypeName.equals("int4") || dbmsTypeName.equals("serial") || dbmsTypeName.equals("serial4"))
			return new DBType(DBDatatype.INTEGER);
		// BIGINT
		else if (dbmsTypeName.equals("bigint") || dbmsTypeName.equals("int8") || dbmsTypeName.equals("bigserial") || dbmsTypeName.equals("bigserial8"))
			return new DBType(DBDatatype.BIGINT);
		// REAL
		else if (dbmsTypeName.equals("real") || dbmsTypeName.equals("float4"))
			return new DBType(DBDatatype.REAL);
		// DOUBLE
		else if (dbmsTypeName.equals("double precision") || dbmsTypeName.equals("float8"))
			return new DBType(DBDatatype.DOUBLE);
		// BINARY
		else if (dbmsTypeName.equals("bit"))
			return new DBType(DBDatatype.BINARY, lengthParam);
		// VARBINARY
		else if (dbmsTypeName.equals("bit varying") || dbmsTypeName.equals("varbit"))
			return new DBType(DBDatatype.VARBINARY, lengthParam);
		// CHAR
		else if (dbmsTypeName.equals("char") || dbmsTypeName.equals("character"))
			return new DBType(DBDatatype.CHAR, lengthParam);
		// VARCHAR
		else if (dbmsTypeName.equals("varchar") || dbmsTypeName.equals("character varying"))
			return new DBType(DBDatatype.VARCHAR, lengthParam);
		// BLOB
		else if (dbmsTypeName.equals("bytea"))
			return new DBType(DBDatatype.BLOB);
		// CLOB
		else if (dbmsTypeName.equals("text"))
			return new DBType(DBDatatype.CLOB);
		// TIMESTAMP
		else if (dbmsTypeName.equals("timestamp") || dbmsTypeName.equals("timestamptz") || dbmsTypeName.equals("time") || dbmsTypeName.equals("timetz") || dbmsTypeName.equals("date"))
			return new DBType(DBDatatype.TIMESTAMP);
		// Default:
		else
			return new DBType(DBDatatype.VARCHAR, DBType.NO_LENGTH);
	}

	@Override
	public String convertTypeToDB(final DBType type){
		if (type == null)
			return "VARCHAR";

		switch(type.type){

			case SMALLINT:
			case INTEGER:
			case REAL:
			case BIGINT:
			case CHAR:
			case VARCHAR:
			case TIMESTAMP:
				return type.type.toString();

			case DOUBLE:
				return "DOUBLE PRECISION";

			case BINARY:
			case VARBINARY:
				return "bytea";

			case BLOB:
				return "bytea";

			case CLOB:
				return "TEXT";

			case POINT:
			case REGION:
			default:
				return "VARCHAR";
		}
	}

	@Override
	public Region translateGeometryFromDB(final Object jdbcColValue) throws ParseException{
		throw new ParseException("Unsupported geometrical value! The value \"" + jdbcColValue + "\" can not be parsed as a region.");
	}

	@Override
	public Object translateGeometryToDB(final Region region) throws ParseException{
		throw new ParseException("Geometries can not be uploaded in the database in this implementation!");
	}

}
+207 −111

File changed.

Preview size limit exceeded, changes collapsed.

Loading