This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch camel-2.23.x in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-2.23.x by this push: new 8d156e9 [CAMEL-13305] camel-sql cannot resolve nested simple expression 8d156e9 is described below commit 8d156e9371d2fe77447dee001bdb92a224fe91f3 Author: rnetuka <rnet...@redhat.com> AuthorDate: Tue Mar 5 14:35:52 2019 +0100 [CAMEL-13305] camel-sql cannot resolve nested simple expression --- .../sql/DefaultSqlPrepareStatementStrategy.java | 79 +++++++++++++++++++++- .../DefaultSqlPrepareStatementStrategyTest.java | 37 ++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlPrepareStatementStrategy.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlPrepareStatementStrategy.java index cc64fda..0e42b95 100644 --- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlPrepareStatementStrategy.java +++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlPrepareStatementStrategy.java @@ -82,7 +82,7 @@ public class DefaultSqlPrepareStatementStrategy implements SqlPrepareStatementSt } } // replace all :?word and :?${foo} with just ? - answer = REPLACE_PATTERN.matcher(query).replaceAll("\\?"); + answer = replaceParams(query); } else { answer = query; } @@ -91,6 +91,56 @@ public class DefaultSqlPrepareStatementStrategy implements SqlPrepareStatementSt return answer; } + private String replaceParams(String query) { + // nested parameters are not replaced properly just by the REPLACE_PATTERN + // for example ":?${array[${index}]}" + query = replaceBracketedParams(query); + return REPLACE_PATTERN.matcher(query).replaceAll("\\?"); + } + + private String replaceBracketedParams(String query) { + while (query.contains(":?${")) { + int i = query.indexOf(":?${"); + int j = findClosingBracket(query, i + 3); + + if (j == -1) { + throw new IllegalArgumentException("String doesn't have equal opening and closing brackets: " + query); + } + + query = query.substring(0, i) + "?" + query.substring(j + 1); + } + return query; + } + + /** + * Finds closing bracket in text for named parameter. + * + * @param text + * @param openPosition + * position of the opening bracket + * + * @return index of corresponding closing bracket, or -1, if none was found + */ + private static int findClosingBracket(String text, int openPosition) { + if (text.charAt(openPosition) != '{') { + throw new IllegalArgumentException("Character at specified position is not an open bracket"); + } + + int remainingClosingBrackets = 0; + + for (int i = openPosition; i < text.length(); i++) { + if (text.charAt(i) == '{') { + remainingClosingBrackets++; + } else if (text.charAt(i) == '}') { + remainingClosingBrackets--; + } + if (remainingClosingBrackets == 0) { + return i; + } + } + return -1; + } + @Override public Iterator<?> createPopulateIterator(final String query, final String preparedQuery, final int expectedParams, final Exchange exchange, final Object value) throws SQLException { @@ -166,15 +216,40 @@ public class DefaultSqlPrepareStatementStrategy implements SqlPrepareStatementSt private static final class NamedQueryParser { + private final String query; private final Matcher matcher; private NamedQueryParser(String query) { + this.query = query; this.matcher = NAME_PATTERN.matcher(query); } public String next() { if (matcher.find()) { - return matcher.group(1); + String param = matcher.group(1); + + int openingBrackets = 0; + int closingBrackets = 0; + for (int i = 0; i < param.length(); i++) { + if (param.charAt(i) == '{') { + openingBrackets++; + } + if (param.charAt(i) == '}') { + closingBrackets++; + } + } + if (openingBrackets != closingBrackets) { + // nested parameters are not found properly by the NAME_PATTERN + // for example param ":?${array[?${index}]}" + // is detected as "${array[?${index}" + // we have to find correct closing bracket manually + String querySubstring = query.substring(matcher.start()); + int i = querySubstring.indexOf('{'); + int j = findClosingBracket(querySubstring, i); + param = "$" + querySubstring.substring(i, j + 1); + } + + return param; } return null; diff --git a/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/DefaultSqlPrepareStatementStrategyTest.java b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/DefaultSqlPrepareStatementStrategyTest.java new file mode 100644 index 0000000..63318f0 --- /dev/null +++ b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/DefaultSqlPrepareStatementStrategyTest.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.sql.stored; + +import java.sql.SQLException; +import org.apache.camel.component.sql.DefaultSqlPrepareStatementStrategy; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class DefaultSqlPrepareStatementStrategyTest { + + @Test + public void testReplaceNestedExpressions() throws SQLException { + DefaultSqlPrepareStatementStrategy strategy = new DefaultSqlPrepareStatementStrategy(); + String sql = "INSERT INTO example VALUES (:?${array[${index}]})"; + + String expected = "INSERT INTO example VALUES (?)"; + String query = strategy.prepareQuery(sql, true, null); + assertEquals(expected, query); + } + +}