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

[ADQL] Support bitwise operators + Fix wrong hexadecimal conversion (only for

negative values).

The implemented operators precedence is:

```
[~-](unary) >> [*/] >> [+-] >> [^&|]
```

_**Example:** `~3-1|2*5^6/1+2 = ((~3)-1)|((2*5)^((6/1)+2)) = -5`_
parent c7bede57
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import adql.query.from.OuterJoin;
import adql.query.from.OuterJoin.OuterType;
import adql.query.operand.ADQLColumn;
import adql.query.operand.ADQLOperand;
import adql.query.operand.BitNotOperand;
import adql.query.operand.Concatenation;
import adql.query.operand.NegativeOperand;
import adql.query.operand.NumericConstant;
@@ -248,6 +249,21 @@ public class ADQLQueryFactory {
		return new NegativeOperand(opToNegativate);
	}

	/**
	 * Create the object representation of the bitwise operation NOT (i.e.
	 * binary complement) applied to the given operand.
	 *
	 * @param operandToBitNot	Operand whose binary complement must be
	 *                       	computed.
	 *
	 * @return	The corresponding object representation of this bitwise
	 *        	operation.
	 *
	 * @since 2.0 */
	public BitNotOperand createBitNotOperand(ADQLOperand operandToBitNot) throws Exception {
		return new BitNotOperand(operandToBitNot);
	}

	public Concatenation createConcatenation() throws Exception {
		return new Concatenation();
	}
+5 −10
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import java.util.Set;
import adql.db.FunctionDef;
import adql.query.ClauseOffset;
import adql.query.constraint.ComparisonOperator;
import adql.query.operand.BitNotOperand;
import adql.query.operand.OperationType;
import adql.query.operand.function.geometry.AreaFunction;
import adql.query.operand.function.geometry.BoxFunction;
import adql.query.operand.function.geometry.CentroidFunction;
@@ -147,7 +149,7 @@ import adql.query.operand.function.string.LowerFunction;
 * </ul>
 *
 * @author Gr&eacute;gory Mantelet (CDS)
 * @version 2.0 (07/2019)
 * @version 2.0 (08/2019)
 * @since 2.0
 */
public class FeatureSet implements Iterable<LanguageFeature> {
@@ -584,14 +586,7 @@ public class FeatureSet implements Iterable<LanguageFeature> {
	
	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 BIT_AND = new LanguageFeature(FeatureType.ADQL_BITWISE, "BIT_AND");  // TODO BIT_AND
	public static final LanguageFeature BIT_OR = new LanguageFeature(FeatureType.ADQL_BITWISE, "BIT_OR");  // TODO BIT_OR
	public static final LanguageFeature BIT_XOR = new LanguageFeature(FeatureType.ADQL_BITWISE, "BIT_XOR");  // TODO BIT_XOR
	public static final LanguageFeature BIT_NOT = new LanguageFeature(FeatureType.ADQL_BITWISE, "BIT_NOT");  // TODO BIT_NOT
	
	public static final LanguageFeature OFFSET = new LanguageFeature(FeatureType.ADQL_OFFSET, "OFFSET");  // TODO OFFSET*/
	public static final LanguageFeature IN_UNIT = new LanguageFeature(FeatureType.ADQL_UNIT, "IN_UNIT");  // TODO IN_UNIT*/

	/** All standard features available.
	 * <p>
@@ -603,7 +598,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[]{ 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[]{ 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.
+2 −2
Original line number Diff line number Diff line
@@ -110,9 +110,9 @@ public abstract class ADQLGrammarBase implements ADQLGrammar {
		else if (!isRegularIdentifier(token.image)) {
			String message = "Invalid ADQL regular identifier: \u005c"" + token.image + "\u005c"!";
			if (getVersion() == ADQLVersion.V2_0 && token.image.matches("0[Xx][0-9a-fA-F]+"))
				message += " HINT: hexadecimal values are not supported in ADQL-2.0. You should change the grammar version of the ADQL parser to at least ADQL-2.1.";
				message += System.getProperty("line.separator", "\n") + "(HINT: hexadecimal values are not supported in ADQL-2.0. You should upgrade your ADQL parser to support at least ADQL-2.1.)";
			else
				message += " HINT: If it aims to be a column/table name/alias, you should write it between double quotes.";
				message += System.getProperty("line.separator", "\n") + " (HINT: If it aims to be a column/table name/alias, you should write it between double quotes.)";
			throw new ParseException(message, new TextPosition(token));
		}
	}
+14 −5
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
 * Modified by Gr&eacute;gory Mantelet (CDS), on Aug. 2019
 * Modifications:
 *     - change the package name
 *     - customize error message in function of the token: append an hint
 *       message or a possible cause in case of TokenMgrError
 *
 * /!\ DO NOT RE-GENERATE THIS FILE /!\
 * In case of re-generation, replace it by ParseException.java.backup (but maybe
@@ -36,6 +38,7 @@
 */
package adql.parser.grammar;

import adql.parser.ADQLParser.ADQLVersion;
import adql.query.TextPosition;

/**
@@ -46,6 +49,10 @@ import adql.query.TextPosition;
 *
 * You can modify this class to customize your error reporting
 * mechanisms so long as you retain the public fields.
 *
 * @version 2.0 (08/2019)
 * @author JavaCC
 * @author Gr&eacute;gory Mantelet (CDS)
 */
public class ParseException extends Exception {

@@ -101,9 +108,9 @@ public class ParseException extends Exception {

	private final static String buildExpandedMessage(final TokenMgrError err) {
		if (err.getMessage().indexOf("<EOF>") > 0)
			return err.getMessage() + "! Possible cause: a string between single or double quotes which is never closed (solution: well...just close it!).";
			return err.getMessage() + "!" + eol + "Possible cause: a string between single or double quotes which is never closed (solution: well...just close it!).";
		else
			return err.getMessage() + "! Possible cause: a non-ASCI/UTF-8 character (solution: remove/replace it).";
			return err.getMessage() + "!" + eol + "Possible cause: a non-ASCI/UTF-8 character (solution: remove/replace it).";
	}

	/**
@@ -190,9 +197,11 @@ public class ParseException extends Exception {
		if (maxSize == 1) {
			tok = currentToken.next;
			if (tok.adqlReserved)
				msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(tok.image).append("\" is a reserved ADQL word in " + currentToken.next.adqlVersion + ". To use it as a column/table/schema name/alias, write it between double quotes.)");
				msg.append(eol).append("(HINT: \"").append(tok.image).append("\" is a reserved ADQL word in " + currentToken.next.adqlVersion + ". To use it as a column/table/schema name/alias, write it between double quotes.)");
			else if (tok.sqlReserved)
				msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(tok.image).append("\" is not supported in ADQL " + currentToken.next.adqlVersion + ", but is however a reserved word. To use it as a column/table/schema name/alias, write it between double quotes.)");
				msg.append(eol).append("(HINT: \"").append(tok.image).append("\" is not supported in ADQL " + currentToken.next.adqlVersion + ", but is however a reserved word. To use it as a column/table/schema name/alias, write it between double quotes.)");
			else if (tok.adqlVersion == ADQLVersion.V2_0 && tok.image.matches("[~^|&]"))
				msg.append(eol).append("(HINT: \"").append(tok.image).append("\" bitwise operations are not supported in ADQL-2.0. You should migrate your ADQL parser to support at least ADQL-2.1.)");
		}

		return msg.toString();
@@ -239,7 +248,7 @@ public class ParseException extends Exception {
	/**
	 * The end of line string for this machine.
	 */
	protected String eol = System.getProperty("line.separator", "\n");
	protected static String eol = System.getProperty("line.separator", "\n");

	/**
	 * Used to convert raw characters to their escaped version
+14 −5
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
 * Modified by Gr&eacute;gory Mantelet (CDS), on Aug. 2019
 * Modifications:
 *     - change the package name
 *     - customize error message in function of the token: append an hint
 *       message or a possible cause in case of TokenMgrError
 *
 * /!\ DO NOT RE-GENERATE THIS FILE /!\
 * In case of re-generation, replace it by ParseException.java.backup (but maybe
@@ -36,6 +38,7 @@
 */
package adql.parser.grammar;

import adql.parser.ADQLParser.ADQLVersion;
import adql.query.TextPosition;

/**
@@ -46,6 +49,10 @@ import adql.query.TextPosition;
 *
 * You can modify this class to customize your error reporting
 * mechanisms so long as you retain the public fields.
 *
 * @version 2.0 (08/2019)
 * @author JavaCC
 * @author Gr&eacute;gory Mantelet (CDS)
 */
public class ParseException extends Exception {

@@ -101,9 +108,9 @@ public class ParseException extends Exception {

	private final static String buildExpandedMessage(final TokenMgrError err) {
		if (err.getMessage().indexOf("<EOF>") > 0)
			return err.getMessage() + "! Possible cause: a string between single or double quotes which is never closed (solution: well...just close it!).";
			return err.getMessage() + "!" + eol + "Possible cause: a string between single or double quotes which is never closed (solution: well...just close it!).";
		else
			return err.getMessage() + "! Possible cause: a non-ASCI/UTF-8 character (solution: remove/replace it).";
			return err.getMessage() + "!" + eol + "Possible cause: a non-ASCI/UTF-8 character (solution: remove/replace it).";
	}

	/**
@@ -190,9 +197,11 @@ public class ParseException extends Exception {
		if (maxSize == 1) {
			tok = currentToken.next;
			if (tok.adqlReserved)
				msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(tok.image).append("\" is a reserved ADQL word in " + currentToken.next.adqlVersion + ". To use it as a column/table/schema name/alias, write it between double quotes.)");
				msg.append(eol).append("(HINT: \"").append(tok.image).append("\" is a reserved ADQL word in " + currentToken.next.adqlVersion + ". To use it as a column/table/schema name/alias, write it between double quotes.)");
			else if (tok.sqlReserved)
				msg.append(System.getProperty("line.separator", "\n")).append("(HINT: \"").append(tok.image).append("\" is not supported in ADQL " + currentToken.next.adqlVersion + ", but is however a reserved word. To use it as a column/table/schema name/alias, write it between double quotes.)");
				msg.append(eol).append("(HINT: \"").append(tok.image).append("\" is not supported in ADQL " + currentToken.next.adqlVersion + ", but is however a reserved word. To use it as a column/table/schema name/alias, write it between double quotes.)");
			else if (tok.adqlVersion == ADQLVersion.V2_0 && tok.image.matches("[~^|&]"))
				msg.append(eol).append("(HINT: \"").append(tok.image).append("\" bitwise operations are not supported in ADQL-2.0. You should migrate your ADQL parser to support at least ADQL-2.1.)");
		}

		return msg.toString();
@@ -239,7 +248,7 @@ public class ParseException extends Exception {
	/**
	 * The end of line string for this machine.
	 */
	protected String eol = System.getProperty("line.separator", "\n");
	protected static String eol = System.getProperty("line.separator", "\n");

	/**
	 * Used to convert raw characters to their escaped version
Loading