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);
+    }
+
+}

Reply via email to