Commit 8b1c7efd authored by gmantele's avatar gmantele
Browse files

[ADQL] Fix merge side-effects (e.g. '' were not translated any more as a...

[ADQL] Fix merge side-effects (e.g. '' were not translated any more as a single ' ; NullPointerExceptions when building positions) + transform the test main class for positions into a JUnit test case + Fix some position mistakes.
(note: a tabulation character seems to be interpreted by JavaCC as 8 characters)
parent 55670a30
Loading
Loading
Loading
Loading
+589 −1146

File changed.

Preview size limit exceeded, changes collapsed.

+32 −20
Original line number Diff line number Diff line
@@ -854,7 +854,7 @@ void Having(): {ClauseConstraints having = query.getHaving(); Token start;} {
void OrderBy(): {ClauseADQL<ADQLOrder> orderBy = query.getOrderBy(); ADQLOrder order = null; Token start;} {
	start=<ORDER_BY> order=OrderItem() {orderBy.add(order);}
	( <COMMA> order=OrderItem() {orderBy.add(order);} )*
	{ orderBy.setPosition(new TextPosition(start.beginLine, start.beginColumn, order.getPosition().endLine, order.getPosition().endColumn)); }
	{ orderBy.setPosition(new TextPosition(start, token)); }
}

/* *************************** */
@@ -1034,13 +1034,18 @@ ADQLJoin JoinSpecification(FromContent leftTable): { boolean natural = false; Jo
/* ****** */
/* STRING */
/* ****** */
StringConstant String(): {Token t; String str=""; StringConstant cst;} {
	(t=<STRING_LITERAL> {str += t.image;})+
StringConstant String(): {Token t, start=null; String str=""; StringConstant cst;} {
	(t=<STRING_LITERAL>
	 {
	   	str += t.image.substring(1, t.image.length()-1).replaceAll("''", "'");
	   	if (start == null)
	   		start = t;
	 }
	)+
	{
		try{
		  str = (str!=null)?str.substring(1,str.length()-1):str;
		  cst = queryFactory.createStringConstant(str);
		  cst.setPosition(new TextPosition(t));
		  cst.setPosition(new TextPosition(start, t));
		  return cst;
		}catch(Exception ex){
			throw generateParseException(ex);
@@ -1113,24 +1118,24 @@ ADQLOperand NumericValueExpressionPrimary(): {String expr; ADQLColumn column; AD
	}
}

ADQLOperand StringValueExpressionPrimary(): {StringConstant expr; ADQLColumn column; ADQLOperand op;} {
ADQLOperand StringValueExpressionPrimary(): {StringConstant expr; ADQLColumn column; ADQLOperand op; Token left, right;} {
	try{
		(// string
		  expr=String() {return expr;}
		// column_reference
		| column=Column() {column.setExpectedType('S'); return column;}
		// LEFT_PAR value_expression RIGHT_PAR
		| (<LEFT_PAR> (op=StringExpression()) <RIGHT_PAR>) {return queryFactory.createWrappedOperand(op);})
		| (left=<LEFT_PAR> (op=StringExpression()) right=<RIGHT_PAR>) { WrappedOperand wop = queryFactory.createWrappedOperand(op); wop.setPosition(new TextPosition(left, right)); return wop; })
	}catch(Exception ex){
		throw generateParseException(ex);
	}
}

ADQLOperand ValueExpression(): {ADQLOperand valueExpr = null; } {
ADQLOperand ValueExpression(): {ADQLOperand valueExpr = null; Token left, right; } {
	try{
		(LOOKAHEAD((<PLUS>|<MINUS>) | (Factor() (<PLUS>|<MINUS>|<ASTERISK>|<DIVIDE>))) valueExpr=NumericExpression()
		| LOOKAHEAD(<COORDSYS> | (StringFactor() <CONCAT>)) valueExpr=StringExpression()
		| LOOKAHEAD(<LEFT_PAR>) <LEFT_PAR> valueExpr=ValueExpression() <RIGHT_PAR> { valueExpr = queryFactory.createWrappedOperand(valueExpr); }
		| LOOKAHEAD(<LEFT_PAR>) left=<LEFT_PAR> valueExpr=ValueExpression() right=<RIGHT_PAR> { valueExpr = queryFactory.createWrappedOperand(valueExpr); ((WrappedOperand)valueExpr).setPosition(new TextPosition(left, right)); }
		| LOOKAHEAD(<REGULAR_IDENTIFIER> <LEFT_PAR>) valueExpr=UserDefinedFunction()
		| valueExpr=GeometryValueFunction()
		| LOOKAHEAD(Column()) valueExpr=Column()
@@ -1178,16 +1183,20 @@ ADQLOperand NumericTerm(): {Token sign=null; ADQLOperand leftOp, rightOp=null;}

ADQLOperand Factor(): {boolean negative = false; Token minusSign = null; ADQLOperand op;} {
	(
		(<PLUS> | (<MINUS> {negative = true;}))?
		(<PLUS> | (minusSign=<MINUS> {negative = true;}))?
		(LOOKAHEAD(2) op=NumericFunction() | op=NumericValueExpressionPrimary())
	)
	
	{
		if (negative){
			try{
			  	TextPosition position = op.getPosition();
				op = queryFactory.createNegativeOperand(op);
				NegativeOperand negativeOp = (NegativeOperand)op;
				negativeOp.setPosition(new TextPosition(minusSign.beginLine, minusSign.beginColumn, negativeOp.getPosition().endLine, negativeOp.getPosition().endColumn));
				if (minusSign != null)
					negativeOp.setPosition(new TextPosition(minusSign.beginLine, minusSign.beginColumn, position.endLine, position.endColumn));
				else
					negativeOp.setPosition(position);
			}catch(Exception ex){
				throw generateParseException(ex);
			}
@@ -1290,7 +1299,7 @@ ClauseConstraints ConditionsList(ClauseConstraints clause): {ADQLConstraint cons
}

ADQLConstraint Constraint(): {ADQLConstraint constraint =  null; Token start, end;} {
	(LOOKAHEAD(Predicate()) constraint=Predicate()
	(LOOKAHEAD(<EXISTS> | ValueExpression()) constraint=Predicate()
	| (
		start=<LEFT_PAR>
		{
@@ -1310,12 +1319,14 @@ ADQLConstraint Constraint(): {ADQLConstraint constraint = null; Token start, en
ADQLConstraint Predicate(): {ADQLQuery q=null; ADQLColumn column=null; ADQLOperand strExpr1=null, strExpr2=null; ADQLOperand op; Token start, notToken = null, end; ADQLConstraint constraint = null;} {
	try{
		// exists_predicate
		((start=<EXISTS> q=SubQueryExpression())
		(
		  (start=<EXISTS> q=SubQueryExpression()
			{
			  Exists e = queryFactory.createExists(q);
			  e.setPosition(new TextPosition(start.beginLine, start.beginColumn, q.getPosition().endLine, q.getPosition().endColumn));
			  return e;
			}
		  )
		// null_predicate
		| LOOKAHEAD(Column() <IS>)(column=Column() <IS> [notToken=<NOT>] end=<NULL>
		    {
@@ -1340,7 +1351,8 @@ ADQLConstraint Predicate(): {ADQLQuery q=null; ADQLColumn column=null; ADQLOpera
			// in_predicate
			| constraint=InEnd(op)
			)
		))
		  )
		)
	}catch(Exception ex){
		throw generateParseException(ex);
	}
+143 −0
Original line number Diff line number Diff line
package adql;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;

import adql.parser.ADQLParser;
import adql.parser.ParseException;
import adql.query.ADQLObject;
import adql.query.ADQLQuery;
import adql.query.TextPosition;
import adql.query.constraint.Comparison;
import adql.query.from.ADQLJoin;
import adql.query.from.ADQLTable;
import adql.query.operand.ADQLColumn;
import adql.query.operand.ADQLOperand;
import adql.query.operand.function.ADQLFunction;
import adql.search.SimpleSearchHandler;

public class TestADQLObjectPosition {

	private ADQLParser parser = new ADQLParser();

	@Before
	public void setUp(){

	}

	@Test
	public void testPositionInAllClauses(){
		try{
			ADQLQuery query = parser.parseQuery("SELECT truc, bidule.machin, toto(truc, chose) AS \"super\" FROM foo JOIN bidule USING(id) WHERE truc > 12.5 AND bidule.machin < 5 GROUP BY chose HAVING try > 0 ORDER BY chouetteAlors");

			Iterator<ADQLObject> results = query.search(new SimpleSearchHandler(true){
				@Override
				protected boolean match(ADQLObject obj){
					return obj.getPosition() == null;
				}
			});
			if (results.hasNext()){
				System.err.println("OBJECT WITH NO DEFINED POSITION:");
				while(results.hasNext())
					System.err.println("    * " + results.next().toADQL());
				fail("At least one item of the generated ADQL tree does not have a position information! (see System.err for more details)");
			}
		}catch(ParseException pe){
			pe.printStackTrace();
			fail("No error should have occured here: the ADQL query is syntactically correct!");
		}
	}

	private void assertEquality(final TextPosition expected, final TextPosition realPos){
		assertEquals(expected.beginLine, realPos.beginLine);
		assertEquals(expected.beginColumn, realPos.beginColumn);
		assertEquals(expected.endLine, realPos.endLine);
		assertEquals(expected.endColumn, realPos.endColumn);
	}

	@Test
	public void testPositionAccuracy(){
		try{
			ADQLQuery query = parser.parseQuery("SELECT TOP 1000 oid FROM foo JOIN bar USING(oid)\nWHERE foo || toto = 'truc'\n      AND 2 > 1+0 GROUP BY oid HAVING COUNT(oid) > 10\n\tORDER BY 1 DESC");
			// Test SELECT
			assertEquality(new TextPosition(1, 1, 1, 20), query.getSelect().getPosition());
			// Test ADQLColumn (here: "oid")
			assertEquality(new TextPosition(1, 17, 1, 20), query.getSelect().get(0).getPosition());
			// Test FROM & ADQLJoin
			/* NB: The clause FROM is the only one which is not a list but a single item of type FromContent (JOIN or table).
			 *     That's why, it is not possible to get its exact starting position ('FROM') ; the starting position is
			 *     the one of the first table of the clause FROM. */
			assertEquality(new TextPosition(1, 26, 1, 49), query.getFrom().getPosition());
			// Test ADQLTable
			ArrayList<ADQLTable> tables = query.getFrom().getTables();
			assertEquality(new TextPosition(1, 26, 1, 29), tables.get(0).getPosition());
			assertEquality(new TextPosition(1, 35, 1, 38), tables.get(1).getPosition());
			// Test the join condition:
			Iterator<ADQLColumn> itCol = ((ADQLJoin)query.getFrom()).getJoinedColumns();
			assertEquality(new TextPosition(1, 45, 1, 48), itCol.next().getPosition());
			// Test WHERE
			assertEquality(new TextPosition(2, 1, 3, 18), query.getWhere().getPosition());
			// Test COMPARISON = CONSTRAINT
			Comparison comp = (Comparison)(query.getWhere().get(0));
			assertEquality(new TextPosition(2, 7, 2, 27), comp.getPosition());
			// Test left operand = concatenation:
			ADQLOperand operand = comp.getLeftOperand();
			assertEquality(new TextPosition(2, 7, 2, 18), operand.getPosition());
			Iterator<ADQLObject> itObj = operand.adqlIterator();
			// foo
			assertEquality(new TextPosition(2, 7, 2, 10), itObj.next().getPosition());
			// toto
			assertEquality(new TextPosition(2, 14, 2, 18), itObj.next().getPosition());
			// Test right operand = string:
			operand = comp.getRightOperand();
			assertEquality(new TextPosition(2, 21, 2, 27), operand.getPosition());
			// Test COMPARISON > CONSTRAINT:
			comp = (Comparison)(query.getWhere().get(1));
			assertEquality(new TextPosition(3, 11, 3, 18), comp.getPosition());
			// Test left operand = numeric:
			operand = comp.getLeftOperand();
			assertEquality(new TextPosition(3, 11, 3, 12), operand.getPosition());
			// Test right operand = operation:
			operand = comp.getRightOperand();
			assertEquality(new TextPosition(3, 15, 3, 18), operand.getPosition());
			itObj = operand.adqlIterator();
			// 1
			assertEquality(new TextPosition(3, 15, 3, 16), itObj.next().getPosition());
			// 0
			assertEquality(new TextPosition(3, 17, 3, 18), itObj.next().getPosition());
			// Test GROUP BY
			assertEquality(new TextPosition(3, 19, 3, 31), query.getGroupBy().getPosition());
			// oid
			assertEquality(new TextPosition(3, 28, 3, 31), query.getGroupBy().get(0).getPosition());
			// Test HAVING
			assertEquality(new TextPosition(3, 32, 3, 54), query.getHaving().getPosition());
			// Test COMPARISON > CONSTRAINT:
			comp = (Comparison)(query.getHaving().get(0));
			assertEquality(new TextPosition(3, 39, 3, 54), comp.getPosition());
			// Test left operand = COUNT function:
			operand = comp.getLeftOperand();
			assertEquality(new TextPosition(3, 39, 3, 49), operand.getPosition());
			// Test parameter = ADQLColumn oid:
			assertEquality(new TextPosition(3, 45, 3, 48), ((ADQLFunction)operand).getParameter(0).getPosition());
			// Test right operand = operation:
			operand = comp.getRightOperand();
			assertEquality(new TextPosition(3, 52, 3, 54), operand.getPosition());
			// Test ORDER BY
			assertEquality(new TextPosition(4, 9, 4, 24), query.getOrderBy().getPosition());
			// Test column index:
			assertEquality(new TextPosition(4, 18, 4, 19), query.getOrderBy().get(0).getPosition());

		}catch(ParseException pe){
			System.err.println("ERROR IN THE ADQL QUERY AT " + pe.getPosition());
			pe.printStackTrace();
			fail("No error should have occured here: the ADQL query is syntactically correct!");
		}
	}

}
+0 −27
Original line number Diff line number Diff line
package adql;

import java.util.Iterator;

import adql.parser.ADQLParser;
import adql.query.ADQLObject;
import adql.query.ADQLQuery;
import adql.search.SimpleSearchHandler;

public class TestGetPositionInAllADQLObject {

	public static void main(String[] args) throws Throwable{
		ADQLParser parser = new ADQLParser();
		ADQLQuery query = parser.parseQuery("SELECT truc, bidule.machin FROM foo JOIN bidule USING(id) WHERE truc > 12.5 AND bidule.machin < 5 GROUP BY chose HAVING try > 0 ORDER BY chouetteAlors");

		System.out.println("\nOBJECT WITH NO DEFINED POSITION:");
		Iterator<ADQLObject> results = query.search(new SimpleSearchHandler(true){
			@Override
			protected boolean match(ADQLObject obj){
				return /*(obj instanceof ADQLList<?> && ((ADQLList<?>)obj).size() > 0) &&*/obj.getPosition() == null;
			}
		});
		while(results.hasNext())
			System.out.println("    * " + results.next().toADQL());
	}

}