Commit bccfe162 authored by Grégory Mantelet's avatar Grégory Mantelet
Browse files

[ADQL] Support the function IN_UNIT(...). (just for parsing....no translation

done because the function must also be available in the database)
parent 0bad1f8b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import adql.query.operand.function.MathFunction;
import adql.query.operand.function.MathFunctionType;
import adql.query.operand.function.SQLFunction;
import adql.query.operand.function.SQLFunctionType;
import adql.query.operand.function.UnitConversionFunction;
import adql.query.operand.function.UserDefinedFunction;
import adql.query.operand.function.geometry.AreaFunction;
import adql.query.operand.function.geometry.BoxFunction;
@@ -317,6 +318,11 @@ public class ADQLQueryFactory {
		return new MathFunction(type, param1, param2);
	}

	/** @since 2.0 */
	public UnitConversionFunction createUnitConversionFunction(final ADQLOperand value, final ADQLOperand targetUnit) throws Exception {
		return new UnitConversionFunction(value, targetUnit);
	}

	/**
	 * Creates the user defined functions called as the given name and with
	 * the given parameters.
+3 −4
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import adql.query.ClauseOffset;
import adql.query.constraint.ComparisonOperator;
import adql.query.operand.BitNotOperand;
import adql.query.operand.OperationType;
import adql.query.operand.function.UnitConversionFunction;
import adql.query.operand.function.geometry.AreaFunction;
import adql.query.operand.function.geometry.BoxFunction;
import adql.query.operand.function.geometry.CentroidFunction;
@@ -584,9 +585,7 @@ public class FeatureSet implements Iterable<LanguageFeature> {
	
	public static final LanguageFeature WITH = new LanguageFeature(FeatureType.ADQL_COMMON_TABLE, "WITH");  // TODO WITH
	
	public static final LanguageFeature CAST = new LanguageFeature(FeatureType.ADQL_TYPE, "CAST");  // TODO CAST
	
	public static final LanguageFeature IN_UNIT = new LanguageFeature(FeatureType.ADQL_UNIT, "IN_UNIT");  // TODO IN_UNIT*/
	public static final LanguageFeature CAST = new LanguageFeature(FeatureType.ADQL_TYPE, "CAST");  // TODO CAST*/

	/** All standard features available.
	 * <p>
@@ -598,7 +597,7 @@ public class FeatureSet implements Iterable<LanguageFeature> {
	 * <p><i><b>Important note:</b>
	 * 	All of them must be optional and must have a type.
	 * </i></p> */
	static LanguageFeature[] availableFeatures = new LanguageFeature[]{ BitNotOperand.FEATURE, OperationType.BIT_AND.getFeatureDescription(), OperationType.BIT_OR.getFeatureDescription(), OperationType.BIT_XOR.getFeatureDescription(), ClauseOffset.FEATURE, ComparisonOperator.ILIKE.getFeatureDescription(), LowerFunction.FEATURE, AreaFunction.FEATURE, BoxFunction.FEATURE, CentroidFunction.FEATURE, CircleFunction.FEATURE, ContainsFunction.FEATURE, ExtractCoord.FEATURE_COORD1, ExtractCoord.FEATURE_COORD2, ExtractCoordSys.FEATURE, DistanceFunction.FEATURE, IntersectsFunction.FEATURE, PointFunction.FEATURE, PolygonFunction.FEATURE, RegionFunction.FEATURE };
	static LanguageFeature[] availableFeatures = new LanguageFeature[]{ UnitConversionFunction.FEATURE, BitNotOperand.FEATURE, OperationType.BIT_AND.getFeatureDescription(), OperationType.BIT_OR.getFeatureDescription(), OperationType.BIT_XOR.getFeatureDescription(), ClauseOffset.FEATURE, ComparisonOperator.ILIKE.getFeatureDescription(), LowerFunction.FEATURE, AreaFunction.FEATURE, BoxFunction.FEATURE, CentroidFunction.FEATURE, CircleFunction.FEATURE, ContainsFunction.FEATURE, ExtractCoord.FEATURE_COORD1, ExtractCoord.FEATURE_COORD2, ExtractCoordSys.FEATURE, DistanceFunction.FEATURE, IntersectsFunction.FEATURE, PointFunction.FEATURE, PolygonFunction.FEATURE, RegionFunction.FEATURE };

	/**
	 * List all available language features.
+21 −0
Original line number Diff line number Diff line
@@ -387,6 +387,13 @@ TOKEN : {
|	< TAN: "TAN" >     { matchedToken.adqlReserved = matchedToken.isFunctionName = true; }
}

/* ******************** */
/* Conversion functions */
/* ******************** */
TOKEN : {
	< IN_UNIT: "IN_UNIT" >   { matchedToken.adqlReserved = matchedToken.isFunctionName = true; }
}

/* ******* */
/* Comment */
/* ******* */
@@ -1493,10 +1500,24 @@ ADQLFunction NumericFunction(): {ADQLFunction fct;} {
	(fct=MathFunction()
	| fct=TrigFunction()
	| fct=GeometryFunction()
	| fct=UnitConversionFunction()
	| fct=UserDefinedFunction() { ((UserDefinedFunction)fct).setExpectedType('N'); })
	{return fct;}
}

UnitConversionFunction UnitConversionFunction() : { Token start, end; ADQLOperand value, destUnit; } {
	start=<IN_UNIT> <LEFT_PAR> value=NumericExpression() <COMMA> destUnit=StringExpression() end=<RIGHT_PAR>
	{
		try {
			UnitConversionFunction fct = queryFactory.createUnitConversionFunction(value, destUnit);
			fct.setPosition(new TextPosition(start, end));
			return fct;
		}catch(Exception ex) {
			throw generateParseException(ex);
		}
	}
}

MathFunction MathFunction(): {Token fct=null, end; ADQLOperand param1=null, param2=null; NumericConstant integerValue = null;} {
	try{
		((fct=<ABS> <LEFT_PAR> param1=NumericExpression() end=<RIGHT_PAR>)
+202 −0
Original line number Diff line number Diff line
package adql.query.operand.function;

/*
 * This file is part of ADQLLibrary.
 *
 * ADQLLibrary is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ADQLLibrary is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with ADQLLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2019 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
 */

import adql.parser.feature.LanguageFeature;
import adql.query.ADQLObject;
import adql.query.operand.ADQLOperand;

/**
 * It represents the IN_UNIT function of ADQL.
 *
 * <p>This function converts the given value into the given VO-Unit.</p>
 *
 * <p>
 * 	This function should report an error if the specified unit is not valid or
 * 	if the conversion is not possible.
 * </p>
 *
 * @author Gr&eacute;gory Mantelet (CDS)
 * @version 2.0 (08/2019)
 * @since 2.0
 */
public class UnitConversionFunction extends ADQLFunction {

	/** Description of this ADQL Feature. */
	public static final LanguageFeature FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_UNIT, "IN_UNIT", true, "Convert the given value (1st argument) into the given VO-Unit (2nd argument).");

	/** Constant name of this function. */
	protected final String FCT_NAME = "IN_UNIT";

	/** The value to convert. */
	protected ADQLOperand value;

	/** The VO-Unit into which the value must be converted. */
	protected ADQLOperand targetUnit;

	/**
	 * Create the object representation of the ADQL function IN_UNIT.
	 *
	 * @param value			The value to convert.
	 * @param targetUnit	The VO-Unit into which the value must be converted.
	 *
	 * @throws NullPointerException		If one of the given operands is NULL.
	 * @throws IllegalArgumentException	If the 1st operand is not a numeric,
	 *                                 	or if the 2nd is not a string.
	 */
	public UnitConversionFunction(final ADQLOperand value, final ADQLOperand targetUnit) throws NullPointerException, IllegalArgumentException {
		setValue(value);
		setTargetUnit(targetUnit);
	}

	/**
	 * Get the numeric operand to convert into a different unit.
	 *
	 * @return	The value to convert.
	 */
	public final ADQLOperand getValue() {
		return value;
	}

	/**
	 * Set the numeric operand to convert into a different unit.
	 *
	 * @param value	The value to convert.
	 *
	 * @throws NullPointerException		If the given operand is NULL.
	 * @throws IllegalArgumentException	If the given operand is not a numeric.
	 */
	public final void setValue(final ADQLOperand value) throws NullPointerException, IllegalArgumentException {
		if (value == null)
			throw new NullPointerException("The 1st argument of the ADQL function " + FCT_NAME + " (i.e. the value to convert) must be non-NULL!");

		if (!value.isNumeric())
			throw new IllegalArgumentException("The 1st argument of the ADQL function " + FCT_NAME + " (i.e. the value to convert) must be a numeric!");

		this.value = value;
	}

	/**
	 * Get the VO-Unit into which the value must be converted.
	 *
	 * @return	The target unit.
	 */
	public final ADQLOperand getTargetUnit() {
		return targetUnit;
	}

	/**
	 * Set the VO-Unit into which the value must be converted.
	 *
	 * @param targetUnit	The target unit.
	 *
	 * @throws NullPointerException		If the given operand is NULL.
	 * @throws IllegalArgumentException	If the given operand is not a string.
	 */
	public final void setTargetUnit(final ADQLOperand targetUnit) throws NullPointerException, IllegalArgumentException {
		if (targetUnit == null)
			throw new NullPointerException("The 2nd argument of the ADQL function " + FCT_NAME + " (i.e. target unit) must be non-NULL!");

		if (!targetUnit.isString())
			throw new IllegalArgumentException("The 2nd argument of the ADQL function " + FCT_NAME + " (i.e. target unit) must be of type VARCHAR (i.e. a string)!");

		this.targetUnit = targetUnit;
	}

	@Override
	public final boolean isNumeric() {
		return true;
	}

	@Override
	public final boolean isString() {
		return false;
	}

	@Override
	public final boolean isGeometry() {
		return false;
	}

	@Override
	public String getName() {
		return FCT_NAME;
	}

	@Override
	public LanguageFeature getFeatureDescription() {
		return FEATURE;
	}

	@Override
	public ADQLObject getCopy() throws Exception {
		return new UnitConversionFunction((ADQLOperand)value.getCopy(), (ADQLOperand)targetUnit.getCopy());
	}

	@Override
	public int getNbParameters() {
		return 2;
	}

	@Override
	public ADQLOperand[] getParameters() {
		return new ADQLOperand[]{ value, targetUnit };
	}

	@Override
	public ADQLOperand getParameter(int index) throws ArrayIndexOutOfBoundsException {
		if (index < 0 || index >= getNbParameters())
			throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + FCT_NAME + "\" (nb required params = " + getNbParameters() + ")!");

		switch(index) {
			case 0:
				return value;
			case 1:
				return targetUnit;
			default:
				return null;
		}
	}

	@Override
	public ADQLOperand setParameter(int index, ADQLOperand replacer) throws ArrayIndexOutOfBoundsException, NullPointerException, Exception {
		if (index < 0 || index >= getNbParameters())
			throw new ArrayIndexOutOfBoundsException("No " + index + "-th parameter for the function \"" + FCT_NAME + "\" (nb required params = " + getNbParameters() + ")!");
		else if (replacer == null)
			throw new NullPointerException("Impossible to remove any parameter from the " + FCT_NAME + " function! All parameters are required!");
		else {
			ADQLOperand replaced = null;
			switch(index) {
				case 0:
					replaced = value;
					setValue(replacer);
					setPosition(null);
					break;
				case 1:
					replaced = targetUnit;
					setTargetUnit(replacer);
					setPosition(null);
					break;
			}
			return replaced;
		}
	}

}
+6 −5
Original line number Diff line number Diff line
@@ -64,15 +64,16 @@ public class LowerFunction extends ADQLFunction {
	 * Builds a LOWER function with its parameter.
	 *
	 * @param param		Parameter of LOWER.
	 * @throws NullPointerException	If the given operand is NULL
	 *                             	or if it's not a string parameter.
	 *
	 * @throws NullPointerException		If the given operand is NULL.
	 * @throws IllegalArgumentException	If the operand is not a string parameter.
	 */
	public LowerFunction(final ADQLOperand strParam) {
	public LowerFunction(final ADQLOperand strParam) throws NullPointerException, IllegalArgumentException {
		if (strParam == null)
			throw new NullPointerException("The function " + FCT_NAME + " must have one non-NULL parameter!");

		if (!strParam.isString())
			throw new NullPointerException("The ADQL function " + FCT_NAME + " must have one parameter of type VARCHAR (i.e. a String)!");
			throw new IllegalArgumentException("The ADQL function " + FCT_NAME + " must have one parameter of type VARCHAR (i.e. a String)!");

		this.strParam = strParam;
	}