Skip to content
Snippets Groups Projects
Commit 1e903504 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Added OFFSET support for MySQL and PostgreSQL

parent 082f04b5
No related branches found
No related tags found
No related merge requests found
...@@ -1077,6 +1077,7 @@ TOKEN : { ...@@ -1077,6 +1077,7 @@ TOKEN : {
< SELECT: "SELECT" > < SELECT: "SELECT" >
| < QUANTIFIER: "DISTINCT" | "ALL" > | < QUANTIFIER: "DISTINCT" | "ALL" >
| < TOP: "TOP" > | < TOP: "TOP" >
| < OFFSET: "OFFSET" >
} }
/* ************* */ /* ************* */
...@@ -1300,12 +1301,22 @@ void Select(): {ClauseSelect select = query.getSelect(); SelectItem item=null; T ...@@ -1300,12 +1301,22 @@ void Select(): {ClauseSelect select = query.getSelect(); SelectItem item=null; T
} }
} }
] ]
[<OFFSET> t=<UNSIGNED_INTEGER>
{
try{
select.setOffset(Integer.parseInt(t.image));
}catch(NumberFormatException nfe){
throw new ParseException("[l."+t.beginLine+";c."+t.beginColumn+"] The OFFSET limit (\""+t.image+"\") isn't a regular unsigned integer !");
}
}
]
item=SelectItem() {select.add(item);} item=SelectItem() {select.add(item);}
(<COMMA> item=SelectItem() {select.add(item);})* (<COMMA> item=SelectItem() {select.add(item);})*
{ {
TextPosition lastItemPos = query.getSelect().get(query.getSelect().size()-1).getPosition(); TextPosition lastItemPos = query.getSelect().get(query.getSelect().size()-1).getPosition();
select.setPosition(new TextPosition(start.beginLine, start.beginColumn, lastItemPos.endLine, lastItemPos.endColumn)); } select.setPosition(new TextPosition(start.beginLine, start.beginColumn, lastItemPos.endLine, lastItemPos.endColumn));
}
} }
SelectItem SelectItem(): {IdentifierItems identifiers = new IdentifierItems(true); IdentifierItem id = null, label = null; ADQLOperand op = null; SelectItem item; Token starToken;} { SelectItem SelectItem(): {IdentifierItems identifiers = new IdentifierItems(true); IdentifierItem id = null, label = null; ADQLOperand op = null; SelectItem item; Token starToken;} {
...@@ -1349,7 +1360,8 @@ SelectItem SelectItem(): {IdentifierItems identifiers = new IdentifierItems(true ...@@ -1349,7 +1360,8 @@ SelectItem SelectItem(): {IdentifierItems identifiers = new IdentifierItems(true
if (label != null){ if (label != null){
item.setCaseSensitive(label.caseSensitivity); item.setCaseSensitive(label.caseSensitivity);
item.setPosition(new TextPosition(op.getPosition(), label.position)); item.setPosition(new TextPosition(op.getPosition(), label.position));
}else item.setPosition(new TextPosition(op.getPosition())); }else
item.setPosition(new TextPosition(op.getPosition()));
return item; return item;
}catch(Exception ex){ }catch(Exception ex){
throw generateParseException(ex); throw generateParseException(ex);
...@@ -1772,7 +1784,8 @@ ADQLOperand StringExpression(): {ADQLOperand leftOp; ADQLOperand rightOp = null; ...@@ -1772,7 +1784,8 @@ ADQLOperand StringExpression(): {ADQLOperand leftOp; ADQLOperand rightOp = null;
)* )*
{ {
if (leftOp instanceof Concatenation){ if (leftOp instanceof Concatenation){
Concatenation concat = (Concatenation)leftOp; concat.setPosition(new TextPosition(concat.get(0).getPosition(), concat.get(concat.size()-1).getPosition())); Concatenation concat = (Concatenation)leftOp;
concat.setPosition(new TextPosition(concat.get(0).getPosition(), concat.get(concat.size()-1).getPosition()));
} }
return leftOp; return leftOp;
} }
...@@ -1788,7 +1801,8 @@ ADQLOperand StringFactor(): {ADQLOperand op;} { ...@@ -1788,7 +1801,8 @@ ADQLOperand StringFactor(): {ADQLOperand op;} {
GeometryValue<GeometryFunction> GeometryExpression(): {ADQLColumn col = null; GeometryFunction gf = null;} { GeometryValue<GeometryFunction> GeometryExpression(): {ADQLColumn col = null; GeometryFunction gf = null;} {
(col=Column() | gf=GeometryValueFunction()) (col=Column() | gf=GeometryValueFunction())
{ {
if (col != null){ col.setExpectedType('G'); if (col != null){
col.setExpectedType('G');
return new GeometryValue<GeometryFunction>(col); return new GeometryValue<GeometryFunction>(col);
}else }else
return new GeometryValue<GeometryFunction>(gf); return new GeometryValue<GeometryFunction>(gf);
...@@ -1804,7 +1818,8 @@ ClauseConstraints ConditionsList(ClauseConstraints clause): {ADQLConstraint cons ...@@ -1804,7 +1818,8 @@ ClauseConstraints ConditionsList(ClauseConstraints clause): {ADQLConstraint cons
constraint=Constraint() constraint=Constraint()
{ {
if (notOp){ if (notOp){
TextPosition oldPos = constraint.getPosition(); constraint = queryFactory.createNot(constraint); TextPosition oldPos = constraint.getPosition();
constraint = queryFactory.createNot(constraint);
((NotConstraint)constraint).setPosition(new TextPosition(op.beginLine, op.beginColumn, oldPos.endLine, oldPos.endColumn)); ((NotConstraint)constraint).setPosition(new TextPosition(op.beginLine, op.beginColumn, oldPos.endLine, oldPos.endColumn));
} }
notOp = false; notOp = false;
...@@ -1836,7 +1851,8 @@ ClauseConstraints ConditionsList(ClauseConstraints clause): {ADQLConstraint cons ...@@ -1836,7 +1851,8 @@ ClauseConstraints ConditionsList(ClauseConstraints clause): {ADQLConstraint cons
throw generateParseException(ex); throw generateParseException(ex);
} }
{ {
if (!clause.isEmpty()){ TextPosition start = clause.get(0).getPosition(); if (!clause.isEmpty()){
TextPosition start = clause.get(0).getPosition();
TextPosition end = clause.get(clause.size()-1).getPosition(); TextPosition end = clause.get(clause.size()-1).getPosition();
clause.setPosition(new TextPosition(start, end)); clause.setPosition(new TextPosition(start, end));
} }
...@@ -2013,7 +2029,8 @@ GeometryFunction GeometryFunction(): {Token fct=null, end; GeometryValue<Geometr ...@@ -2013,7 +2029,8 @@ GeometryFunction GeometryFunction(): {Token fct=null, end; GeometryValue<Geometr
{ {
if (p1 != null) if (p1 != null)
gvp1 = new GeometryValue<PointFunction>(p1); gvp1 = new GeometryValue<PointFunction>(p1);
else{ col1.setExpectedType('G'); else{
col1.setExpectedType('G');
gvp1 = new GeometryValue<PointFunction>(col1); gvp1 = new GeometryValue<PointFunction>(col1);
} }
} }
...@@ -2022,7 +2039,8 @@ GeometryFunction GeometryFunction(): {Token fct=null, end; GeometryValue<Geometr ...@@ -2022,7 +2039,8 @@ GeometryFunction GeometryFunction(): {Token fct=null, end; GeometryValue<Geometr
{ {
if (p2 != null) if (p2 != null)
gvp2 = new GeometryValue<PointFunction>(p2); gvp2 = new GeometryValue<PointFunction>(p2);
else{ col2.setExpectedType('G'); else{
col2.setExpectedType('G');
gvp2 = new GeometryValue<PointFunction>(col2); gvp2 = new GeometryValue<PointFunction>(col2);
} }
} }
......
...@@ -43,6 +43,9 @@ public class ClauseSelect extends ClauseADQL<SelectItem> { ...@@ -43,6 +43,9 @@ public class ClauseSelect extends ClauseADQL<SelectItem> {
/** The maximum number of returned rows. */ /** The maximum number of returned rows. */
private int limit = -1; private int limit = -1;
/** The number of rows to skip before selection. */
private int offset = -1;
/** /**
* Builds an empty SELECT clause. * Builds an empty SELECT clause.
*/ */
...@@ -144,6 +147,40 @@ public class ClauseSelect extends ClauseADQL<SelectItem> { ...@@ -144,6 +147,40 @@ public class ClauseSelect extends ClauseADQL<SelectItem> {
this.limit = limit; this.limit = limit;
} }
/**
* Indicates whether this SELECT clause sets an offset.
*
* @return <i>true</i> this clause has an OFFSET flag, <i>false</i> otherwise.
*/
public final boolean hasOffset(){
return offset >= 0;
}
/**
* Gets the offset set by this SELECT clause.
*
* @return Number of rows the query must skip before selection (SELECT OFFSET offset).
*/
public final int getOffset(){
return offset;
}
/**
* Sets no offset (classic SELECT).
*/
public final void setNoOffset(){
offset = -1;
}
/**
* Changes the number of rows to skip this clause imposes.
*
* @param limit The number of rows to skip before selection (SELECT OFFSET offset).
*/
public final void setOffset(int newOffset){
this.offset = newOffset;
}
/** /**
* <p>Adds an operand to this SELECT clause.</p> * <p>Adds an operand to this SELECT clause.</p>
* *
......
...@@ -376,6 +376,9 @@ public abstract class JDBCTranslator implements ADQLTranslator { ...@@ -376,6 +376,9 @@ public abstract class JDBCTranslator implements ADQLTranslator {
if (query.getSelect().hasLimit()) if (query.getSelect().hasLimit())
sql.append("\nLimit ").append(query.getSelect().getLimit()); sql.append("\nLimit ").append(query.getSelect().getLimit());
if(query.getSelect().hasLimit() && query.getSelect().hasOffset())
sql.append(",").append(query.getSelect().getOffset());
return sql.toString(); return sql.toString();
} }
......
...@@ -4,6 +4,7 @@ import adql.db.DBType; ...@@ -4,6 +4,7 @@ import adql.db.DBType;
import adql.db.DBType.DBDatatype; import adql.db.DBType.DBDatatype;
import adql.db.STCS.Region; import adql.db.STCS.Region;
import adql.parser.ParseException; import adql.parser.ParseException;
import adql.query.ADQLQuery;
import adql.query.IdentifierField; import adql.query.IdentifierField;
import adql.query.operand.ADQLOperand; import adql.query.operand.ADQLOperand;
import adql.query.operand.Concatenation; import adql.query.operand.Concatenation;
...@@ -329,4 +330,32 @@ public class MySQLTranslator extends JDBCTranslator { ...@@ -329,4 +330,32 @@ public class MySQLTranslator extends JDBCTranslator {
return getDefaultADQLFunction(region); return getDefaultADQLFunction(region);
} }
@Override
public String translate(ADQLQuery query) throws TranslationException{
StringBuilder sql = new StringBuilder(translate(query.getSelect()));
sql.append("\nFROM ").append(translate(query.getFrom()));
if (!query.getWhere().isEmpty())
sql.append('\n').append(translate(query.getWhere()));
if (!query.getGroupBy().isEmpty())
sql.append('\n').append(translate(query.getGroupBy()));
if (!query.getHaving().isEmpty())
sql.append('\n').append(translate(query.getHaving()));
if (!query.getOrderBy().isEmpty())
sql.append('\n').append(translate(query.getOrderBy()));
if (query.getSelect().hasLimit()) {
sql.append("\n LIMIT ");
if(query.getSelect().hasOffset()) {
sql.append(query.getSelect().getOffset()).append(",");
}
sql.append(query.getSelect().getLimit());
}
return sql.toString();
}
} }
...@@ -24,6 +24,7 @@ import adql.db.DBType; ...@@ -24,6 +24,7 @@ import adql.db.DBType;
import adql.db.DBType.DBDatatype; import adql.db.DBType.DBDatatype;
import adql.db.STCS.Region; import adql.db.STCS.Region;
import adql.parser.ParseException; import adql.parser.ParseException;
import adql.query.ADQLQuery;
import adql.query.IdentifierField; import adql.query.IdentifierField;
import adql.query.operand.StringConstant; import adql.query.operand.StringConstant;
import adql.query.operand.function.ADQLFunction; import adql.query.operand.function.ADQLFunction;
...@@ -329,4 +330,30 @@ public class PostgreSQLTranslator extends JDBCTranslator { ...@@ -329,4 +330,30 @@ public class PostgreSQLTranslator extends JDBCTranslator {
throw new ParseException("Geometries can not be uploaded in the database in this implementation!"); throw new ParseException("Geometries can not be uploaded in the database in this implementation!");
} }
@Override
public String translate(ADQLQuery query) throws TranslationException{
StringBuffer sql = new StringBuffer(translate(query.getSelect()));
sql.append("\nFROM ").append(translate(query.getFrom()));
if (!query.getWhere().isEmpty())
sql.append('\n').append(translate(query.getWhere()));
if (!query.getGroupBy().isEmpty())
sql.append('\n').append(translate(query.getGroupBy()));
if (!query.getHaving().isEmpty())
sql.append('\n').append(translate(query.getHaving()));
if (!query.getOrderBy().isEmpty())
sql.append('\n').append(translate(query.getOrderBy()));
if (query.getSelect().hasLimit())
sql.append("\nLimit ").append(query.getSelect().getLimit());
if(query.getSelect().hasLimit() && query.getSelect().hasOffset())
sql.append(" offset ").append(query.getSelect().getOffset());
return sql.toString();
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment