Skip to content
Snippets Groups Projects
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
No related branches found
No related tags found
No related merge requests found
......@@ -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);
}
}
......@@ -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.
......
......@@ -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);
}
}
}
......
......@@ -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();
}
......
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;
}
}
......@@ -377,8 +377,8 @@ public abstract class JDBCTranslator implements ADQLTranslator {
if (query.getSelect().hasLimit())
sql.append("\nLIMIT ").append(query.getSelect().getLimit());
if (query.hasOffset())
sql.append("\nOFFSET ").append(query.getOffset());
if (query.getOffset() != null)
sql.append("\nOFFSET ").append(query.getOffset().getValue());
return sql.toString();
}
......
......@@ -161,13 +161,13 @@ public class SQLServerTranslator extends JDBCTranslator {
sql.append('\n').append(translate(query.getOrderBy()));
if (query.getSelect().hasLimit()) {
if (query.hasOffset())
sql.append('\n').append("OFFSET ").append(query.getOffset()).append(" ROWS");
if (query.getOffset() != null)
sql.append('\n').append("OFFSET ").append(query.getOffset().getValue()).append(" ROWS");
else
sql.append('\n').append("OFFSET 0 ROWS");
sql.append(" FETCH NEXT ").append(query.getSelect().getLimit()).append(" ROWS ONLY");
} else if (query.hasOffset()) {
sql.append('\n').append("OFFSET ").append(query.getOffset()).append(" ROWS");
} else if (query.getOffset() != null) {
sql.append('\n').append("OFFSET ").append(query.getOffset().getValue()).append(" ROWS");
}
return sql.toString();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment