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

[ADQL] Adapt the previous commit to add OFFSET into the FeatureSet. With the

previous commit, OFFSET was always available although it is actually an optional
feature.
parent 8a2ce121
Loading
Loading
Loading
Loading
+17 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import adql.parser.IdentifierItems.IdentifierItem;
import adql.query.ADQLOrder;
import adql.query.ADQLQuery;
import adql.query.ClauseConstraints;
import adql.query.ClauseOffset;
import adql.query.ColumnReference;
import adql.query.IdentifierField;
import adql.query.SelectItem;
@@ -89,7 +90,7 @@ import adql.query.operand.function.string.LowerFunction;
 * </p>
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.0 (07/2019)
 * @version 2.0 (08/2019)
 *
 * @see ADQLParser
 */
@@ -487,4 +488,19 @@ public class ADQLQueryFactory {
			colRef.setPosition(position);
		return colRef;
	}

	/**
	 * Create a {@link ClauseOffset}.
	 *
	 * @param offsetValue	The OFFSET's value. <b>MUST be POSITIVE</b>
	 *
	 * @return	The created {@link ClauseOffset}.
	 *
	 * @throws Exception	If the given OFFSET value is incorrect.
	 *
	 * @since 2.0
	 */
	public ClauseOffset createOffset(final int offsetValue) throws Exception {
		return new ClauseOffset(offsetValue);
	}
}
+7 −6
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import java.util.NoSuchElementException;
import java.util.Set;

import adql.db.FunctionDef;
import adql.query.ClauseOffset;
import adql.query.constraint.ComparisonOperator;
import adql.query.operand.function.geometry.AreaFunction;
import adql.query.operand.function.geometry.BoxFunction;
@@ -602,7 +603,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[]{ 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[]{ 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.
+7 −3
Original line number Diff line number Diff line
@@ -579,13 +579,17 @@ void OrderBy(): {ClauseADQL<ADQLOrder> orderBy = query.getOrderBy(); ADQLOrder o
	{ orderBy.setPosition(new TextPosition(start, token)); }
}

void Offset(): { Token t; } {
	<OFFSET> t=<UNSIGNED_INTEGER>
void Offset(): { Token start, t; } {
	start=<OFFSET> t=<UNSIGNED_INTEGER>
	{
		try{
			query.setOffset(Integer.parseInt(t.image));
		  	ClauseOffset offset = queryFactory.createOffset(Integer.parseInt(t.image));
		  	offset.setPosition(new TextPosition(start, t));
			query.setOffset(offset);
		}catch(NumberFormatException nfe){
			throw new ParseException("The OFFSET limit (\""+t.image+"\") isn't a regular unsigned integer!", new TextPosition(t));
		}catch(Exception ex) {
			throw generateParseException(ex);
		}
	}
}
+25 −40
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ public class ADQLQuery implements ADQLObject {

	/** The ADQL clause OFFSET.
	 * @since 2.0 */
	private int offset;
	private ClauseOffset offset;

	/** Position of this Query (or sub-query) inside the whole given ADQL query
	 * string.
@@ -116,7 +116,7 @@ public class ADQLQuery implements ADQLObject {
		groupBy = new ClauseADQL<ADQLColumn>("GROUP BY");
		having = new ClauseConstraints("HAVING");
		orderBy = new ClauseADQL<ADQLOrder>("ORDER BY");
		offset = -1;
		offset = null;
	}

	/**
@@ -135,7 +135,7 @@ public class ADQLQuery implements ADQLObject {
		groupBy = (ClauseADQL<ADQLColumn>)toCopy.groupBy.getCopy();
		having = (ClauseConstraints)toCopy.having.getCopy();
		orderBy = (ClauseADQL<ADQLOrder>)toCopy.orderBy.getCopy();
		offset = toCopy.offset;
		offset = (ClauseOffset)toCopy.offset.getCopy();
		position = (toCopy.position == null) ? null : new TextPosition(toCopy.position);
	}

@@ -166,7 +166,7 @@ public class ADQLQuery implements ADQLObject {
		groupBy.clear();
		having.clear();
		orderBy.clear();
		offset = -1;
		offset = null;
		position = null;
	}

@@ -342,40 +342,14 @@ public class ADQLQuery implements ADQLObject {
	 * Gets the OFFSET value of this query.
	 *
	 * @return	Its OFFSET value,
	 *        	or a negative value if no OFFSET is set.
	 *        	or NULL if not OFFSET is set.
	 *
	 * @since 2.0
	 */
	public final int getOffset() {
	public final ClauseOffset getOffset() {
		return offset;
	}

	/**
	 * Tell whether an OFFSET is set in this query.
	 *
	 * @return	<code>true</code> if an OFFSET is set,
	 *        	<code>false</code> otherwise.
	 *
	 * @since 2.0
	 */
	public final boolean hasOffset() {
		return (offset > -1);
	}

	/**
	 * Remove the OFFSET value of this query.
	 *
	 * <p><i><b>Note:</b>
	 * 	The position of the query is erased.
	 * </i></p>.
	 *
	 * @since 2.0
	 */
	public void setNoOffset() {
		offset = -1;
		position = null;
	}

	/**
	 * Replaces its OFFSET value by the given one.
	 *
@@ -383,13 +357,12 @@ public class ADQLQuery implements ADQLObject {
	 * 	The position of the query is erased.
	 * </i></p>
	 *
	 * @param newOffset	The new OFFSET value.
	 *                 	<i><b>Note:</b> a negative value removes the OFFSET from
	 *                 	this query.</i>
	 * @param newOffset	The new OFFSET value,
	 *                 	or NULL to remove the current OFFSET.
	 *
	 * @since 2.0
	 */
	public void setOffset(final int newOffset) {
	public void setOffset(final ClauseOffset newOffset) {
		offset = newOffset;
		position = null;
	}
@@ -549,6 +522,9 @@ public class ADQLQuery implements ADQLObject {
					case 5:
						currentClause = orderBy;
						break;
					case 6:
						currentClause = null;
						return offset;
					default:
						throw new NoSuchElementException();
				}
@@ -557,7 +533,7 @@ public class ADQLQuery implements ADQLObject {

			@Override
			public boolean hasNext() {
				return index + 1 < 6;
				return index + 1 < 7;
			}

			@Override
@@ -606,6 +582,12 @@ public class ADQLQuery implements ADQLObject {
							else
								throw new UnsupportedOperationException("Impossible to replace a ClauseADQL (" + orderBy.toADQL() + ") by a " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!");
							break;
						case 6:
							if (replacer instanceof ClauseOffset)
								offset = (ClauseOffset)replacer;
							else
								throw new UnsupportedOperationException("Impossible to replace a ClauseOffset (" + offset.toADQL() + ") by a " + replacer.getClass().getName() + " (" + replacer.toADQL() + ")!");
							break;
					}
					position = null;
				}
@@ -618,7 +600,10 @@ public class ADQLQuery implements ADQLObject {

				if (index == 0 || index == 1)
					throw new UnsupportedOperationException("Impossible to remove a " + ((index == 0) ? "SELECT" : "FROM") + " clause from a query!");
				else {
				else if (index == 6) {
					offset = null;
					position = null;
				} else {
					currentClause.clear();
					position = null;
				}
@@ -643,8 +628,8 @@ public class ADQLQuery implements ADQLObject {
		if (!orderBy.isEmpty())
			adql.append('\n').append(orderBy.toADQL());

		if (hasOffset())
			adql.append("\nOFFSET ").append(offset);
		if (offset != null)
			adql.append('\n').append(offset.toADQL());

		return adql.toString();
	}
+113 −0
Original line number Diff line number Diff line
package adql.query;

import adql.parser.feature.LanguageFeature;

/**
 * Object representation of an OFFSET clause.
 *
 * <p>
 * 	This clause is special hence the fact it does not extend
 * 	{@link adql.query.ClauseADQL}. It contains only one value: the number of
 * 	rows removed from the query's result head.
 * </p>
 *
 * <p><i><b>Important note:</b>
 * 	The OFFSET value stored in this object MUST always be positive.
 * </i></p>
 *
 * @author Gr&eacute;gory Mantelet (CDS)
 * @version 2.0 (08/2019)
 * @since 2.0
 */
public class ClauseOffset implements ADQLObject {

	/** Description of this ADQL Feature. */
	public static final LanguageFeature FEATURE = new LanguageFeature(LanguageFeature.TYPE_ADQL_OFFSET, "OFFSET", true, "Remove the specified number of rows from the head of the query result.");

	/** Name of this ADQL object. */
	private static final String NAME = "OFFSET";

	/** Value of the query's OFFSET.
	 * <p><i><b>Important note:</b>
	 * 	This value can never be negative.
	 * </i></p> */
	protected int value;

	/** Position of this {@link ClauseOffset} in the original ADQL query
	 * string. */
	private TextPosition position = null;

	/**
	 * Create a clause OFFSET with the given offset value.
	 *
	 * @param offsetValue	Value of the query's result OFFSET.
	 *
	 * @throws IndexOutOfBoundsException	If the given value is negative.
	 */
	public ClauseOffset(final int offsetValue) throws IndexOutOfBoundsException {
		setValue(offsetValue);
	}

	/**
	 * Get the query's OFFSET.
	 *
	 * @return	Query's OFFSET. <i>Always positive.</i>
	 */
	public final int getValue() {
		return value;
	}

	/**
	 * Set the query's OFFSET.
	 *
	 * @param offsetValue	Value of the query's result OFFSET.
	 *
	 * @throws IndexOutOfBoundsException	If the given value is negative.
	 */
	public void setValue(final int offsetValue) throws IndexOutOfBoundsException {
		if (offsetValue < 0)
			throw new IndexOutOfBoundsException("Incorrect OFFSET value: \"" + offsetValue + "\"! It must be a positive value.");
		this.value = offsetValue;
	}

	@Override
	public ADQLObject getCopy() throws Exception {
		return new ClauseOffset(value);
	}

	@Override
	public final String getName() {
		return NAME;
	}

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

	@Override
	public final TextPosition getPosition() {
		return position;
	}

	/**
	 * Sets the position at which this {@link ClauseOffset} has been found in
	 * the original ADQL query string.
	 *
	 * @param position	Position of this {@link ClauseOffset}.
	 */
	public final void setPosition(final TextPosition newPosition) {
		position = newPosition;
	}

	@Override
	public ADQLIterator adqlIterator() {
		return new NullADQLIterator();
	}

	@Override
	public String toADQL() {
		return "OFFSET " + value;
	}

}
Loading