diff --git a/src/adql/search/SimpleReplaceHandler.java b/src/adql/search/SimpleReplaceHandler.java index 53ebc93daed3787390e0b60426ed38be4e5255c1..d35150ab075c275e48ab6e08b9256ecd470fe355 100644 --- a/src/adql/search/SimpleReplaceHandler.java +++ b/src/adql/search/SimpleReplaceHandler.java @@ -35,7 +35,7 @@ import adql.query.ADQLObject; * </ul> * * @author Grégory Mantelet (CDS;ARI) - * @version 1.4 (05/2016) + * @version 1.4 (06/2016) * * @see RemoveHandler */ @@ -134,29 +134,34 @@ public abstract class SimpleReplaceHandler extends SimpleSearchHandler implement addMatch(startObj, null); Stack<ADQLIterator> stackIt = new Stack<ADQLIterator>(); + Stack<ADQLObject> stackObj = new Stack<ADQLObject>(); ADQLObject obj = null; ADQLIterator it = startObj.adqlIterator(); while(!isFinished()){ + // Fetch the next ADQL object to test: do{ - if (it != null && it.hasNext()) + if (it != null && it.hasNext()){ + // Get the next object: obj = it.next(); - else if (!stackIt.isEmpty()) + // ...but continue the research inside it as long as it is possible: + if (obj != null && goInto(obj)){ + stackIt.push(it); + stackObj.push(obj); + it = obj.adqlIterator(); + obj = null; + } + }else if (!stackIt.isEmpty()){ it = stackIt.pop(); - else + obj = stackObj.pop(); + }else return; }while(obj == null); // Add the current object if it is matching: if (match(obj)) - obj = addMatchAndReplace(obj, it); - - // Continue the research inside the current object (or the new object if a replacement has been performed): - if (obj != null && goInto(obj)){ - stackIt.push(it); - it = obj.adqlIterator(); - } + addMatchAndReplace(obj, it); obj = null; } diff --git a/test/adql/search/TestSimpleReplaceHandler.java b/test/adql/search/TestSimpleReplaceHandler.java index 46bb27dc414acf309402386d43fda2473bf39ba0..785fddf2722de279eb315b0a2e65dcdaa7bc1b20 100644 --- a/test/adql/search/TestSimpleReplaceHandler.java +++ b/test/adql/search/TestSimpleReplaceHandler.java @@ -11,6 +11,7 @@ import adql.query.ADQLObject; import adql.query.ADQLQuery; import adql.query.operand.function.DefaultUDF; import adql.query.operand.function.MathFunction; +import adql.query.operand.function.MathFunctionType; public class TestSimpleReplaceHandler { @@ -64,4 +65,57 @@ public class TestSimpleReplaceHandler { } + @Test + public void testWrappingReplacement(){ + /* WHY THIS TEST? + * + * In case you just want to wrap a matched object, you replace it by the wrapping object initialized + * with the matched object. + * + * In a first version, the replacement was done and then the ReplaceHandler was going inside the new object to replace + * other matching objects. But of course, it will find again the first matched object and will wrap it again, and so on + * indefinitely => "nasty" infinite loop. + * + * So, the replacement of the matched objects should be always done after having looked inside it. + */ + + String testQuery = "SELECT foo(bar(123)) FROM myTable"; + try{ + // Parse the query: + ADQLQuery query = (new ADQLParser()).parseQuery(testQuery); + + // Check it is as expected, before the replacements: + assertEquals(testQuery, query.toADQL().replaceAll("\\n", " ")); + + // Create a replace handler: + SimpleReplaceHandler replaceHandler = new SimpleReplaceHandler(){ + @Override + protected boolean match(ADQLObject obj){ + return obj instanceof DefaultUDF && ((DefaultUDF)obj).getName().toLowerCase().matches("(foo|bar)"); + } + + @Override + protected ADQLObject getReplacer(ADQLObject objToReplace) throws UnsupportedOperationException{ + try{ + return new MathFunction(MathFunctionType.ROUND, (DefaultUDF)objToReplace); + }catch(Exception e){ + e.printStackTrace(System.err); + fail("No error should have occured here since nothing is wrong in the ADQL query used for the test. See the stack trace in the console for more details."); + return null; + } + } + }; + + // Apply the wrapping: + replaceHandler.searchAndReplace(query); + assertEquals(2, replaceHandler.getNbMatch()); + assertEquals(replaceHandler.getNbMatch(), replaceHandler.getNbReplacement()); + assertEquals("SELECT ROUND(foo(ROUND(bar(123)))) FROM myTable", query.toADQL().replaceAll("\\n", " ")); + + }catch(Exception ex){ + ex.printStackTrace(System.err); + fail("No error should have occured here since nothing is wrong in the ADQL query used for the test. See the stack trace in the console for more details."); + } + } + }