You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2018/02/09 07:47:06 UTC

[camel] 01/02: CAMEL-12212 sql-stored: support INOUT parameters

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 2f08dab593599c1428bae9b17be3616961735cb4
Author: Brett Meyer <br...@3riverdev.com>
AuthorDate: Wed Feb 7 16:09:50 2018 -0500

    CAMEL-12212 sql-stored: support INOUT parameters
---
 .../BatchCallableStatementCreatorFactory.java      |   6 +-
 .../sql/stored/CallableStatementWrapper.java       |   4 +-
 .../sql/stored/TemplateStoredProcedure.java        |  32 +-
 .../sql/stored/template/TemplateParser.java        |   5 +-
 .../{InputParameter.java => InOutParameter.java}   |  41 +-
 .../ast/{InputParameter.java => InParameter.java}  |  21 +-
 .../stored/template/generated/ParseException.java  | 315 ++++----
 .../sql/stored/template/generated/SSPTParser.java  |  90 ++-
 .../template/generated/SSPTParserConstants.java    |  29 +-
 .../template/generated/SSPTParserTokenManager.java | 176 +++--
 .../template/generated/SimpleCharStream.java       | 854 +++++++++++----------
 .../sql/stored/template/generated/Token.java       | 228 +++---
 .../stored/template/generated/TokenMgrError.java   | 241 +++---
 .../component/sql/stored/template/grammar/sspt.jj  |  30 +-
 .../camel/component/sql/stored/ParserTest.java     |  61 +-
 .../component/sql/stored/ProducerInOutTest.java    |  85 ++
 .../component/sql/stored/TestStoredProcedure.java  |   7 +-
 .../src/test/resources/sql/storedProcedureTest.sql |   6 +
 18 files changed, 1257 insertions(+), 974 deletions(-)

diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/BatchCallableStatementCreatorFactory.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/BatchCallableStatementCreatorFactory.java
index 24d087a..59c4e17 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/BatchCallableStatementCreatorFactory.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/BatchCallableStatementCreatorFactory.java
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.camel.component.sql.stored.template.ast.InputParameter;
+import org.apache.camel.component.sql.stored.template.ast.InParameter;
 import org.apache.camel.component.sql.stored.template.ast.Template;
 import org.springframework.jdbc.core.CallableStatementCreator;
 import org.springframework.jdbc.core.CallableStatementCreatorFactory;
@@ -73,8 +73,8 @@ public class BatchCallableStatementCreatorFactory {
         List<SqlParameter> params = new ArrayList<>();
 
         for (Object parameter : template.getParameterList()) {
-            if (parameter instanceof InputParameter) {
-                InputParameter inputParameter = (InputParameter) parameter;
+            if (parameter instanceof InParameter) {
+                InParameter inputParameter = (InParameter) parameter;
 
                 SqlParameter sqlParameter;
                 if (inputParameter.getScale() != null) {
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapper.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapper.java
index 2693b0a..be13a0b 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapper.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapper.java
@@ -26,7 +26,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.Exchange;
-import org.apache.camel.component.sql.stored.template.ast.InputParameter;
+import org.apache.camel.component.sql.stored.template.ast.InParameter;
 import org.springframework.dao.DataAccessException;
 import org.springframework.jdbc.core.CallableStatementCallback;
 import org.springframework.jdbc.core.CallableStatementCreator;
@@ -116,7 +116,7 @@ public class CallableStatementWrapper implements StatementWrapper {
         Map<String, Object> batchValues = new HashMap<>();
         //only IN-parameters supported by template
         for (Object param : this.batchFactory.getTemplate().getParameterList()) {
-            InputParameter inputParameter = (InputParameter) param;
+            InParameter inputParameter = (InParameter) param;
             Object paramValue = inputParameter.getValueExtractor().eval(exchange, value);
             batchValues.put(inputParameter.getName(), paramValue);
         }
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/TemplateStoredProcedure.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/TemplateStoredProcedure.java
index 3ee4614..cc15041 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/TemplateStoredProcedure.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/TemplateStoredProcedure.java
@@ -22,12 +22,14 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.Exchange;
-import org.apache.camel.component.sql.stored.template.ast.InputParameter;
+import org.apache.camel.component.sql.stored.template.ast.InOutParameter;
+import org.apache.camel.component.sql.stored.template.ast.InParameter;
 import org.apache.camel.component.sql.stored.template.ast.OutParameter;
 import org.apache.camel.component.sql.stored.template.ast.Template;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.SqlInOutParameter;
 import org.springframework.jdbc.core.SqlOutParameter;
 import org.springframework.jdbc.core.SqlParameter;
 import org.springframework.jdbc.object.StoredProcedure;
@@ -38,7 +40,8 @@ public class TemplateStoredProcedure extends StoredProcedure {
 
     private final Template template;
 
-    private List<InputParameter> inputParameterList = new ArrayList<>();
+    private List<InParameter> inParameterList = new ArrayList<>();
+    private List<InOutParameter> inOutParameterList = new ArrayList<>();
 
     public TemplateStoredProcedure(JdbcTemplate jdbcTemplate, Template template, boolean function) {
         this.template = template;
@@ -48,8 +51,8 @@ public class TemplateStoredProcedure extends StoredProcedure {
         setSql(template.getProcedureName());
 
         for (Object parameter : template.getParameterList()) {
-            if (parameter instanceof InputParameter) {
-                InputParameter inputParameter = (InputParameter) parameter;
+            if (parameter instanceof InParameter) {
+                InParameter inputParameter = (InParameter) parameter;
                 SqlParameter sqlParameter;
                 if (inputParameter.getScale() != null) {
                     sqlParameter = new SqlParameter(inputParameter.getName(), inputParameter.getSqlType(), inputParameter.getScale());
@@ -60,8 +63,20 @@ public class TemplateStoredProcedure extends StoredProcedure {
                 }
 
                 declareParameter(sqlParameter);
-                inputParameterList.add(inputParameter);
+                inParameterList.add(inputParameter);
+            } else if (parameter instanceof InOutParameter) {
+                InOutParameter inOutParameter = (InOutParameter) parameter;
+                SqlInOutParameter sqlInOutParameter;
+                if (inOutParameter.getScale() != null) {
+                    sqlInOutParameter = new SqlInOutParameter(inOutParameter.getOutValueMapKey(), inOutParameter.getSqlType(), inOutParameter.getScale());
+                } else if (inOutParameter.getTypeName() != null) {
+                    sqlInOutParameter = new SqlInOutParameter(inOutParameter.getOutValueMapKey(), inOutParameter.getSqlType(), inOutParameter.getTypeName());
+                } else {
+                    sqlInOutParameter = new SqlInOutParameter(inOutParameter.getOutValueMapKey(), inOutParameter.getSqlType());
+                }
 
+                declareParameter(sqlInOutParameter);
+                inOutParameterList.add(inOutParameter);
             } else if (parameter instanceof OutParameter) {
                 OutParameter outParameter = (OutParameter) parameter;
                 SqlOutParameter sqlOutParameter;
@@ -84,8 +99,11 @@ public class TemplateStoredProcedure extends StoredProcedure {
     public Map execute(Exchange exchange, Object rowData) {
         Map<String, Object> params = new HashMap<>();
 
-        for (InputParameter inputParameter : inputParameterList) {
-            params.put(inputParameter.getName(), inputParameter.getValueExtractor().eval(exchange, rowData));
+        for (InParameter inParameter : inParameterList) {
+            params.put(inParameter.getName(), inParameter.getValueExtractor().eval(exchange, rowData));
+        }
+        for (InOutParameter inOutParameter : inOutParameterList) {
+            params.put(inOutParameter.getOutValueMapKey(), inOutParameter.getValueExtractor().eval(exchange, rowData));
         }
 
         LOG.debug("Invoking stored procedure: {}", template.getProcedureName());
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateParser.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateParser.java
index f5632ad..727513a 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateParser.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateParser.java
@@ -18,7 +18,6 @@ package org.apache.camel.component.sql.stored.template;
 
 import java.io.StringReader;
 
-import org.apache.camel.CamelContext;
 import org.apache.camel.component.sql.stored.template.ast.ParseRuntimeException;
 import org.apache.camel.component.sql.stored.template.ast.Template;
 import org.apache.camel.component.sql.stored.template.generated.ParseException;
@@ -38,9 +37,7 @@ public class TemplateParser {
     public Template parseTemplate(String template) {
         try {
             SSPTParser parser = new SSPTParser(new StringReader(template), classResolver);
-            Template ret = validate(parser.parse());
-
-            return ret;
+            return validate(parser.parse());
 
         } catch (ParseException parseException) {
             throw new ParseRuntimeException(parseException);
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InOutParameter.java
similarity index 74%
copy from components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
copy to components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InOutParameter.java
index 2fcbff0..2028902 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InOutParameter.java
@@ -18,26 +18,25 @@ package org.apache.camel.component.sql.stored.template.ast;
 
 import java.util.Map;
 
-import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.builder.ExpressionBuilder;
 import org.apache.camel.component.sql.stored.template.generated.SSPTParserConstants;
 import org.apache.camel.component.sql.stored.template.generated.Token;
 
-public class InputParameter {
+public class InOutParameter {
 
-    private final String name;
     private final String typeName;
     private final int sqlType;
     private final Integer scale;
     private ValueExtractor valueExtractor;
+    private String outValueMapKey;
 
-    public InputParameter(String name, int sqlType, Token valueSrcToken, Integer scale, String typeName) {
-        this.name = name;
+    public InOutParameter(int sqlType, Token valueSrcToken, Integer scale, String typeName, String outValueMapKey) {
         this.sqlType = sqlType;
         parseValueExpression(valueSrcToken);
         this.scale = scale;
         this.typeName = typeName;
+        this.outValueMapKey = outValueMapKey;
 
         if (this.scale != null && this.typeName != null) {
             throw new ParseRuntimeException(String.format("Both scale=%s and typeName=%s cannot be set", this.scale, this.typeName));
@@ -47,34 +46,14 @@ public class InputParameter {
     private void parseValueExpression(Token valueSrcToken) {
         if (SSPTParserConstants.SIMPLE_EXP_TOKEN == valueSrcToken.kind) {
             final Expression exp = ExpressionBuilder.simpleExpression(valueSrcToken.toString());
-            this.valueExtractor = new ValueExtractor() {
-
-                @Override
-                public Object eval(Exchange exchange, Object container) {
-                    return exp.evaluate(exchange, Object.class);
-                }
-            };
+            this.valueExtractor = (exchange, container) -> exp.evaluate(exchange, Object.class);
         } else if (SSPTParserConstants.PARAMETER_POS_TOKEN == valueSrcToken.kind) {
-
             //remove leading :#
             final String mapKey = valueSrcToken.toString().substring(2);
-            this.valueExtractor = new ValueExtractor() {
-                @Override
-                public Object eval(Exchange exchange, Object container) {
-                    return ((Map) container).get(mapKey);
-                }
-            };
+            this.valueExtractor = (exchange, container) -> ((Map) container).get(mapKey);
         }
     }
 
-    public Integer getScale() {
-        return scale;
-    }
-
-    public String getName() {
-        return name;
-    }
-
     public String getTypeName() {
         return typeName;
     }
@@ -83,7 +62,15 @@ public class InputParameter {
         return sqlType;
     }
 
+    public Integer getScale() {
+        return scale;
+    }
+
     public ValueExtractor getValueExtractor() {
         return valueExtractor;
     }
+
+    public String getOutValueMapKey() {
+        return outValueMapKey;
+    }
 }
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InParameter.java
similarity index 78%
rename from components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
rename to components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InParameter.java
index 2fcbff0..62e123b 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InParameter.java
@@ -18,13 +18,12 @@ package org.apache.camel.component.sql.stored.template.ast;
 
 import java.util.Map;
 
-import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.builder.ExpressionBuilder;
 import org.apache.camel.component.sql.stored.template.generated.SSPTParserConstants;
 import org.apache.camel.component.sql.stored.template.generated.Token;
 
-public class InputParameter {
+public class InParameter {
 
     private final String name;
     private final String typeName;
@@ -32,7 +31,7 @@ public class InputParameter {
     private final Integer scale;
     private ValueExtractor valueExtractor;
 
-    public InputParameter(String name, int sqlType, Token valueSrcToken, Integer scale, String typeName) {
+    public InParameter(String name, int sqlType, Token valueSrcToken, Integer scale, String typeName) {
         this.name = name;
         this.sqlType = sqlType;
         parseValueExpression(valueSrcToken);
@@ -47,23 +46,11 @@ public class InputParameter {
     private void parseValueExpression(Token valueSrcToken) {
         if (SSPTParserConstants.SIMPLE_EXP_TOKEN == valueSrcToken.kind) {
             final Expression exp = ExpressionBuilder.simpleExpression(valueSrcToken.toString());
-            this.valueExtractor = new ValueExtractor() {
-
-                @Override
-                public Object eval(Exchange exchange, Object container) {
-                    return exp.evaluate(exchange, Object.class);
-                }
-            };
+            this.valueExtractor = (exchange, container) -> exp.evaluate(exchange, Object.class);
         } else if (SSPTParserConstants.PARAMETER_POS_TOKEN == valueSrcToken.kind) {
-
             //remove leading :#
             final String mapKey = valueSrcToken.toString().substring(2);
-            this.valueExtractor = new ValueExtractor() {
-                @Override
-                public Object eval(Exchange exchange, Object container) {
-                    return ((Map) container).get(mapKey);
-                }
-            };
+            this.valueExtractor = (exchange, container) -> ((Map) container).get(mapKey);
         }
     }
 
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java
index 5e1fe55..30e4737 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java
@@ -13,168 +13,175 @@ package org.apache.camel.component.sql.stored.template.generated;
  */
 public class ParseException extends Exception {
 
-    /**
-     * The version identifier for this Serializable class.
-     * Increment only if the <i>serialized</i> form of the
-     * class changes.
-     */
-    private static final long serialVersionUID = 1L;
-    /**
-     * This is the last token that has been consumed successfully.  If
-     * this object has been created due to a parse error, the token
-     * followng this token will (therefore) be the first error token.
-     */
-    public Token currentToken;
-    /**
-     * Each entry in this array is an array of integers.  Each array
-     * of integers represents a sequence of tokens (by their ordinal
-     * values) that is expected at this point of the parse.
-     */
-    public int[][] expectedTokenSequences;
-    /**
-     * This is a reference to the "tokenImage" array of the generated
-     * parser within which the parse error occurred.  This array is
-     * defined in the generated ...Constants interface.
-     */
-    public String[] tokenImage;
-    /**
-     * The end of line string for this machine.
-     */
-    protected String eol = System.getProperty("line.separator", "\n");
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
 
-    /**
-     * This constructor is used by the method "generateParseException"
-     * in the generated parser.  Calling this constructor generates
-     * a new object of this type with the fields "currentToken",
-     * "expectedTokenSequences", and "tokenImage" set.
-     */
-    public ParseException(Token currentTokenVal,
-                          int[][] expectedTokenSequencesVal,
-                          String[] tokenImageVal
-    ) {
-        super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
-        currentToken = currentTokenVal;
-        expectedTokenSequences = expectedTokenSequencesVal;
-        tokenImage = tokenImageVal;
-    }
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
 
-    /**
-     * The following constructors are for use by you for whatever
-     * purpose you can think of.  Constructing the exception in this
-     * manner makes the exception behave in the normal way - i.e., as
-     * documented in the class "Throwable".  The fields "errorToken",
-     * "expectedTokenSequences", and "tokenImage" do not contain
-     * relevant information.  The JavaCC generated code does not use
-     * these constructors.
-     */
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
 
-    public ParseException() {
-        super();
-    }
+  public ParseException() {
+    super();
+  }
 
-    /** Constructor with message. */
-    public ParseException(String message) {
-        super(message);
-    }
+  /** Constructor with message. */
+  public ParseException(String message) {
+    super(message);
+  }
 
-    /**
-     * It uses "currentToken" and "expectedTokenSequences" to generate a parse
-     * error message and returns it.  If this object has been created
-     * due to a parse error, and you do not catch it (it gets thrown
-     * from the parser) the correct error message
-     * gets displayed.
-     */
-    private static String initialise(Token currentToken,
-                                     int[][] expectedTokenSequences,
-                                     String[] tokenImage) {
-        String eol = System.getProperty("line.separator", "\n");
-        StringBuffer expected = new StringBuffer();
-        int maxSize = 0;
-        for (int[] expectedTokenSequence : expectedTokenSequences) {
-            if (maxSize < expectedTokenSequence.length) {
-                maxSize = expectedTokenSequence.length;
-            }
-            for (int j = 0; j < expectedTokenSequence.length; j++) {
-                expected.append(tokenImage[expectedTokenSequence[j]]).append(' ');
-            }
-            if (expectedTokenSequence[expectedTokenSequence.length - 1] != 0) {
-                expected.append("...");
-            }
-            expected.append(eol).append("    ");
-        }
-        StringBuilder retval = new StringBuilder("Encountered \"");
-        Token tok = currentToken.next;
-        for (int i = 0; i < maxSize; i++) {
-            if (i != 0) retval.append(" ");
-            if (tok.kind == 0) {
-                retval.append(tokenImage[0]);
-                break;
-            }
-            retval.append(" ").append(tokenImage[tok.kind]);
-            retval.append(" \"");
-            retval.append(add_escapes(tok.image));
-            retval.append(" \"");
-            tok = tok.next;
-        }
-        retval.append("\" at line ").append(currentToken.next.beginLine).append(", column ").append(currentToken.next.beginColumn);
-        retval.append(".").append(eol);
-        if (expectedTokenSequences.length == 1) {
-            retval.append("Was expecting:").append(eol).append("    ");
-        } else {
-            retval.append("Was expecting one of:").append(eol).append("    ");
-        }
-        retval.append(expected.toString());
-        return retval.toString();
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * It uses "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser) the correct error message
+   * gets displayed.
+   */
+  private static String initialise(Token currentToken,
+                           int[][] expectedTokenSequences,
+                           String[] tokenImage) {
+    String eol = System.getProperty("line.separator", "\n");
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += " " + tokenImage[tok.kind];
+      retval += " \"";
+      retval += add_escapes(tok.image);
+      retval += " \"";
+      tok = tok.next;
     }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
 
-    /**
-     * Used to convert raw characters to their escaped version
-     * when these raw version cannot be used as part of an ASCII
-     * string literal.
-     */
-    static String add_escapes(String str) {
-        StringBuffer retval = new StringBuffer();
-        char ch;
-        for (int i = 0; i < str.length(); i++) {
-            switch (str.charAt(i)) {
-                case 0:
-                    continue;
-                case '\b':
-                    retval.append("\\b");
-                    continue;
-                case '\t':
-                    retval.append("\\t");
-                    continue;
-                case '\n':
-                    retval.append("\\n");
-                    continue;
-                case '\f':
-                    retval.append("\\f");
-                    continue;
-                case '\r':
-                    retval.append("\\r");
-                    continue;
-                case '\"':
-                    retval.append("\\\"");
-                    continue;
-                case '\'':
-                    retval.append("\\\'");
-                    continue;
-                case '\\':
-                    retval.append("\\\\");
-                    continue;
-                default:
-                    if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
-                        String s = "0000" + Integer.toString(ch, 16);
-                        retval.append("\\u" + s.substring(s.length() - 4, s.length()));
-                    } else {
-                        retval.append(ch);
-                    }
-                    continue;
-            }
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  static String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
         }
-        return retval.toString();
-    }
+      }
+      return retval.toString();
+   }
 
 }
 /* JavaCC - OriginalChecksum=5189b93605d5a3d3833ed059f46e94c9 (do not edit this line) */
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParser.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParser.java
index 92bbf21..30f0258 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParser.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParser.java
@@ -1,10 +1,14 @@
 /* Generated By:JavaCC: Do not edit this line. SSPTParser.java */
 package org.apache.camel.component.sql.stored.template.generated;
 
-import java.io.Reader;
-
+import org.apache.camel.component.sql.stored.template.ast.InOutParameter;
+import org.apache.camel.component.sql.stored.template.ast.InParameter;
+import org.apache.camel.component.sql.stored.template.ast.OutParameter;
+import org.apache.camel.component.sql.stored.template.ast.ParseHelper;
+import org.apache.camel.component.sql.stored.template.ast.Template;
 import org.apache.camel.spi.ClassResolver;
-import org.apache.camel.component.sql.stored.template.ast.*;
+
+import java.io.Reader;
 
 public class SSPTParser implements SSPTParserConstants {
    int parameterNameCounter = 0;
@@ -28,6 +32,7 @@ public class SSPTParser implements SSPTParserConstants {
     jj_consume_token(PROCEDURE_BEGIN);
     switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
     case 2:
+    case 3:
     case NUMBER:
     case PARAMETER_NAME:
     case IDENTIFIER:
@@ -65,12 +70,16 @@ public class SSPTParser implements SSPTParserConstants {
     case NUMBER:
     case PARAMETER_NAME:
     case IDENTIFIER:
-      param = InputParameter();
-                                {if (true) return param;}
+      param = InParameter();
+                             {if (true) return param;}
       break;
     case 2:
       param = OutParameter();
-                                                                          {if (true) return param;}
+                                                                       {if (true) return param;}
+      break;
+    case 3:
+      param = InOutParameter();
+                                                                                                                   {if (true) return param;}
       break;
     default:
       jj_la1[2] = jj_gen;
@@ -80,7 +89,7 @@ public class SSPTParser implements SSPTParserConstants {
     throw new Error("Missing return statement in function");
   }
 
-  final public InputParameter InputParameter() throws ParseException {
+  final public InParameter InParameter() throws ParseException {
      Token sqlTypeToken;
      String name = null;
      Token valueSrcToken;
@@ -114,10 +123,10 @@ public class SSPTParser implements SSPTParserConstants {
       jj_la1[5] = jj_gen;
       ;
     }
-    valueSrcToken = InputParameterSrc();
+    valueSrcToken = InParameterSrc();
         int sqlType = ParseHelper.parseSqlType(sqlTypeToken, classResolver);
 
-        {if (true) return new InputParameter(name == null ? createNextParameterName() : name, sqlType, valueSrcToken, scale, typeName);}
+        {if (true) return new InParameter(name == null ? createNextParameterName() : name, sqlType, valueSrcToken, scale, typeName);}
     throw new Error("Missing return statement in function");
   }
 
@@ -151,6 +160,41 @@ public class SSPTParser implements SSPTParserConstants {
     throw new Error("Missing return statement in function");
   }
 
+  final public InOutParameter InOutParameter() throws ParseException {
+     Token sqlTypeToken;
+     Token valueSrcToken;
+     Integer scale = null;
+     String typeName = null;
+     String outValueMapKey;
+    jj_consume_token(3);
+    sqlTypeToken = ParameterSqlType();
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case SCALE:
+      scale = Scale();
+      break;
+    default:
+      jj_la1[8] = jj_gen;
+      ;
+    }
+    jj_consume_token(1);
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case PARAMETER_NAME:
+      typeName = ParameterName();
+      jj_consume_token(1);
+      break;
+    default:
+      jj_la1[9] = jj_gen;
+      ;
+    }
+    valueSrcToken = InParameterSrc();
+    jj_consume_token(1);
+    outValueMapKey = OutHeader();
+        int sqlType = ParseHelper.parseSqlType(sqlTypeToken, classResolver);
+
+        {if (true) return new InOutParameter(sqlType, valueSrcToken, scale, typeName, outValueMapKey);}
+    throw new Error("Missing return statement in function");
+  }
+
   final public String ParameterName() throws ParseException {
     Token t = null;
     t = jj_consume_token(PARAMETER_NAME);
@@ -176,7 +220,7 @@ public class SSPTParser implements SSPTParserConstants {
       t = jj_consume_token(IDENTIFIER);
       break;
     default:
-      jj_la1[8] = jj_gen;
+      jj_la1[10] = jj_gen;
       jj_consume_token(-1);
       throw new ParseException();
     }
@@ -191,7 +235,7 @@ public class SSPTParser implements SSPTParserConstants {
     throw new Error("Missing return statement in function");
   }
 
-  final public Token InputParameterSrc() throws ParseException {
+  final public Token InParameterSrc() throws ParseException {
     Token ret = null;
     switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
     case SIMPLE_EXP_TOKEN:
@@ -203,7 +247,7 @@ public class SSPTParser implements SSPTParserConstants {
             {if (true) return ret;}
       break;
     default:
-      jj_la1[9] = jj_gen;
+      jj_la1[11] = jj_gen;
       jj_consume_token(-1);
       throw new ParseException();
     }
@@ -219,13 +263,13 @@ public class SSPTParser implements SSPTParserConstants {
   public Token jj_nt;
   private int jj_ntk;
   private int jj_gen;
-  final private int[] jj_la1 = new int[10];
+  final private int[] jj_la1 = new int[12];
   static private int[] jj_la1_0;
   static {
       jj_la1_init_0();
    }
    private static void jj_la1_init_0() {
-      jj_la1_0 = new int[] {0x400,0x18014,0x18014,0x8000,0x8,0x8000,0x8,0x8000,0x10010,0x6000,};
+      jj_la1_0 = new int[] {0x800,0x3002c,0x3002c,0x10000,0x10,0x10000,0x10,0x10000,0x10,0x10000,0x20020,0xc000,};
    }
 
   /** Constructor with InputStream. */
@@ -239,7 +283,7 @@ public class SSPTParser implements SSPTParserConstants {
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 10; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -253,7 +297,7 @@ public class SSPTParser implements SSPTParserConstants {
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 10; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
   }
 
   /** Constructor. */
@@ -263,7 +307,7 @@ public class SSPTParser implements SSPTParserConstants {
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 10; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -273,7 +317,7 @@ public class SSPTParser implements SSPTParserConstants {
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 10; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
   }
 
   /** Constructor with generated Token Manager. */
@@ -282,7 +326,7 @@ public class SSPTParser implements SSPTParserConstants {
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 10; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -291,7 +335,7 @@ public class SSPTParser implements SSPTParserConstants {
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 10; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
   }
 
   private Token jj_consume_token(int kind) throws ParseException {
@@ -342,12 +386,12 @@ public class SSPTParser implements SSPTParserConstants {
   /** Generate ParseException. */
   public ParseException generateParseException() {
     jj_expentries.clear();
-    boolean[] la1tokens = new boolean[17];
+    boolean[] la1tokens = new boolean[18];
     if (jj_kind >= 0) {
       la1tokens[jj_kind] = true;
       jj_kind = -1;
     }
-    for (int i = 0; i < 10; i++) {
+    for (int i = 0; i < 12; i++) {
       if (jj_la1[i] == jj_gen) {
         for (int j = 0; j < 32; j++) {
           if ((jj_la1_0[i] & (1<<j)) != 0) {
@@ -356,7 +400,7 @@ public class SSPTParser implements SSPTParserConstants {
         }
       }
     }
-    for (int i = 0; i < 17; i++) {
+    for (int i = 0; i < 18; i++) {
       if (la1tokens[i]) {
         jj_expentry = new int[1];
         jj_expentry[0] = i;
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParserConstants.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParserConstants.java
index e047cc8..f48d31d 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParserConstants.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParserConstants.java
@@ -11,33 +11,33 @@ public interface SSPTParserConstants {
   /** End of File. */
   int EOF = 0;
   /** RegularExpression Id. */
-  int SCALE = 3;
+  int SCALE = 4;
   /** RegularExpression Id. */
-  int NUMBER = 4;
+  int NUMBER = 5;
   /** RegularExpression Id. */
-  int DIGIT = 5;
+  int DIGIT = 6;
   /** RegularExpression Id. */
-  int LETTER = 6;
+  int LETTER = 7;
   /** RegularExpression Id. */
-  int SPECIAL = 7;
+  int SPECIAL = 8;
   /** RegularExpression Id. */
-  int WHITESPACE = 8;
+  int WHITESPACE = 9;
   /** RegularExpression Id. */
-  int COMMA = 9;
+  int COMMA = 10;
   /** RegularExpression Id. */
-  int SEPARATOR = 10;
+  int SEPARATOR = 11;
   /** RegularExpression Id. */
-  int PROCEDURE_BEGIN = 11;
+  int PROCEDURE_BEGIN = 12;
   /** RegularExpression Id. */
-  int PROCEDURE_END = 12;
+  int PROCEDURE_END = 13;
   /** RegularExpression Id. */
-  int SIMPLE_EXP_TOKEN = 13;
+  int SIMPLE_EXP_TOKEN = 14;
   /** RegularExpression Id. */
-  int PARAMETER_POS_TOKEN = 14;
+  int PARAMETER_POS_TOKEN = 15;
   /** RegularExpression Id. */
-  int PARAMETER_NAME = 15;
+  int PARAMETER_NAME = 16;
   /** RegularExpression Id. */
-  int IDENTIFIER = 16;
+  int IDENTIFIER = 17;
 
   /** Lexical state. */
   int DEFAULT = 0;
@@ -47,6 +47,7 @@ public interface SSPTParserConstants {
     "<EOF>",
     "\" \"",
     "\"OUT \"",
+    "\"INOUT \"",
     "<SCALE>",
     "<NUMBER>",
     "<DIGIT>",
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParserTokenManager.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParserTokenManager.java
index 6598fe0..ba002be 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParserTokenManager.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SSPTParserTokenManager.java
@@ -17,30 +17,46 @@ private final int jjStopStringLiteralDfa_0(int pos, long active0)
    switch (pos)
    {
       case 0:
-         if ((active0 & 0x4L) != 0L)
+         if ((active0 & 0xcL) != 0L)
          {
-            jjmatchedKind = 16;
+            jjmatchedKind = 17;
             return 15;
          }
          if ((active0 & 0x2L) != 0L)
             return 25;
          return -1;
       case 1:
-         if ((active0 & 0x4L) != 0L)
+         if ((active0 & 0xcL) != 0L)
          {
-            jjmatchedKind = 16;
+            jjmatchedKind = 17;
             jjmatchedPos = 1;
             return 15;
          }
          return -1;
       case 2:
-         if ((active0 & 0x4L) != 0L)
+         if ((active0 & 0xcL) != 0L)
          {
-            jjmatchedKind = 16;
+            jjmatchedKind = 17;
             jjmatchedPos = 2;
             return 15;
          }
          return -1;
+      case 3:
+         if ((active0 & 0x8L) != 0L)
+         {
+            jjmatchedKind = 17;
+            jjmatchedPos = 3;
+            return 15;
+         }
+         return -1;
+      case 4:
+         if ((active0 & 0x8L) != 0L)
+         {
+            jjmatchedKind = 17;
+            jjmatchedPos = 4;
+            return 15;
+         }
+         return -1;
       default :
          return -1;
    }
@@ -61,6 +77,8 @@ private int jjMoveStringLiteralDfa0_0()
    {
       case 32:
          return jjStartNfaWithStates_0(0, 1, 25);
+      case 73:
+         return jjMoveStringLiteralDfa1_0(0x8L);
       case 79:
          return jjMoveStringLiteralDfa1_0(0x4L);
       default :
@@ -76,6 +94,8 @@ private int jjMoveStringLiteralDfa1_0(long active0)
    }
    switch(curChar)
    {
+      case 78:
+         return jjMoveStringLiteralDfa2_0(active0, 0x8L);
       case 85:
          return jjMoveStringLiteralDfa2_0(active0, 0x4L);
       default :
@@ -94,6 +114,8 @@ private int jjMoveStringLiteralDfa2_0(long old0, long active0)
    }
    switch(curChar)
    {
+      case 79:
+         return jjMoveStringLiteralDfa3_0(active0, 0x8L);
       case 84:
          return jjMoveStringLiteralDfa3_0(active0, 0x4L);
       default :
@@ -116,11 +138,51 @@ private int jjMoveStringLiteralDfa3_0(long old0, long active0)
          if ((active0 & 0x4L) != 0L)
             return jjStopAtPos(3, 2);
          break;
+      case 85:
+         return jjMoveStringLiteralDfa4_0(active0, 0x8L);
       default :
          break;
    }
    return jjStartNfa_0(2, active0);
 }
+private int jjMoveStringLiteralDfa4_0(long old0, long active0)
+{
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(2, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(3, active0);
+      return 4;
+   }
+   switch(curChar)
+   {
+      case 84:
+         return jjMoveStringLiteralDfa5_0(active0, 0x8L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(3, active0);
+}
+private int jjMoveStringLiteralDfa5_0(long old0, long active0)
+{
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(3, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(4, active0);
+      return 5;
+   }
+   switch(curChar)
+   {
+      case 32:
+         if ((active0 & 0x8L) != 0L)
+            return jjStopAtPos(5, 3);
+         break;
+      default :
+         break;
+   }
+   return jjStartNfa_0(4, active0);
+}
 private int jjStartNfaWithStates_0(int pos, int kind, int state)
 {
    jjmatchedKind = kind;
@@ -150,38 +212,38 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 8:
                   if ((0x7ff609c00000000L & l) != 0L)
                   {
-                     if (kind > 16)
-                        kind = 16;
+                     if (kind > 17)
+                        kind = 17;
                      jjCheckNAdd(15);
                   }
                   else if ((0x100002600L & l) != 0L)
                   {
-                     if (kind > 8)
-                        kind = 8;
+                     if (kind > 9)
+                        kind = 9;
                      jjCheckNAddStates(0, 5);
                   }
                   else if (curChar == 40)
                   {
-                     if (kind > 11)
-                        kind = 11;
+                     if (kind > 12)
+                        kind = 12;
                      jjCheckNAddTwoStates(17, 19);
                   }
                   else if (curChar == 41)
                   {
-                     if (kind > 12)
-                        kind = 12;
+                     if (kind > 13)
+                        kind = 13;
                      jjCheckNAdd(4);
                   }
                   else if (curChar == 44)
                   {
-                     if (kind > 10)
-                        kind = 10;
+                     if (kind > 11)
+                        kind = 11;
                      jjCheckNAdd(2);
                   }
                   if ((0x3ff200000000000L & l) != 0L)
                   {
-                     if (kind > 4)
-                        kind = 4;
+                     if (kind > 5)
+                        kind = 5;
                      jjCheckNAdd(0);
                   }
                   else if (curChar == 39)
@@ -196,20 +258,20 @@ private int jjMoveNfa_0(int startState, int curPos)
                      jjCheckNAddTwoStates(24, 3);
                   else if (curChar == 41)
                   {
-                     if (kind > 12)
-                        kind = 12;
+                     if (kind > 13)
+                        kind = 13;
                      jjCheckNAdd(4);
                   }
                   else if (curChar == 40)
                   {
-                     if (kind > 11)
-                        kind = 11;
+                     if (kind > 12)
+                        kind = 12;
                      jjCheckNAdd(19);
                   }
                   else if (curChar == 44)
                   {
-                     if (kind > 10)
-                        kind = 10;
+                     if (kind > 11)
+                        kind = 11;
                      jjCheckNAdd(2);
                   }
                   if ((0x100002600L & l) != 0L)
@@ -220,35 +282,35 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 0:
                   if ((0x3ff200000000000L & l) == 0L)
                      break;
-                  if (kind > 4)
-                     kind = 4;
+                  if (kind > 5)
+                     kind = 5;
                   jjCheckNAdd(0);
                   break;
                case 1:
                   if (curChar != 44)
                      break;
-                  kind = 10;
+                  kind = 11;
                   jjCheckNAdd(2);
                   break;
                case 2:
                   if ((0x100002600L & l) == 0L)
                      break;
-                  if (kind > 10)
-                     kind = 10;
+                  if (kind > 11)
+                     kind = 11;
                   jjCheckNAdd(2);
                   break;
                case 3:
                   if (curChar != 41)
                      break;
-                  if (kind > 12)
-                     kind = 12;
+                  if (kind > 13)
+                     kind = 13;
                   jjCheckNAdd(4);
                   break;
                case 4:
                   if ((0x100002600L & l) == 0L)
                      break;
-                  if (kind > 12)
-                     kind = 12;
+                  if (kind > 13)
+                     kind = 13;
                   jjCheckNAdd(4);
                   break;
                case 6:
@@ -262,8 +324,8 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 10:
                   if ((0x7ff609c00000000L & l) == 0L)
                      break;
-                  if (kind > 14)
-                     kind = 14;
+                  if (kind > 15)
+                     kind = 15;
                   jjCheckNAdd(10);
                   break;
                case 11:
@@ -279,21 +341,21 @@ private int jjMoveNfa_0(int startState, int curPos)
                      jjCheckNAddTwoStates(13, 14);
                   break;
                case 14:
-                  if (curChar == 39 && kind > 15)
-                     kind = 15;
+                  if (curChar == 39 && kind > 16)
+                     kind = 16;
                   break;
                case 15:
                   if ((0x7ff609c00000000L & l) == 0L)
                      break;
-                  if (kind > 16)
-                     kind = 16;
+                  if (kind > 17)
+                     kind = 17;
                   jjCheckNAdd(15);
                   break;
                case 16:
                   if (curChar != 40)
                      break;
-                  if (kind > 11)
-                     kind = 11;
+                  if (kind > 12)
+                     kind = 12;
                   jjCheckNAddTwoStates(17, 19);
                   break;
                case 17:
@@ -301,21 +363,21 @@ private int jjMoveNfa_0(int startState, int curPos)
                      jjCheckNAddTwoStates(17, 18);
                   break;
                case 18:
-                  if (curChar == 41 && kind > 3)
-                     kind = 3;
+                  if (curChar == 41 && kind > 4)
+                     kind = 4;
                   break;
                case 19:
                   if ((0x100002600L & l) == 0L)
                      break;
-                  if (kind > 11)
-                     kind = 11;
+                  if (kind > 12)
+                     kind = 12;
                   jjCheckNAdd(19);
                   break;
                case 20:
                   if ((0x100002600L & l) == 0L)
                      break;
-                  if (kind > 8)
-                     kind = 8;
+                  if (kind > 9)
+                     kind = 9;
                   jjCheckNAddStates(0, 5);
                   break;
                case 21:
@@ -329,8 +391,8 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 23:
                   if (curChar != 40)
                      break;
-                  if (kind > 11)
-                     kind = 11;
+                  if (kind > 12)
+                     kind = 12;
                   jjCheckNAdd(19);
                   break;
                case 24:
@@ -352,8 +414,8 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 15:
                   if ((0x2ffffffeaffffffeL & l) == 0L)
                      break;
-                  if (kind > 16)
-                     kind = 16;
+                  if (kind > 17)
+                     kind = 17;
                   jjCheckNAdd(15);
                   break;
                case 5:
@@ -365,14 +427,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                      jjCheckNAddTwoStates(6, 7);
                   break;
                case 7:
-                  if (curChar == 125 && kind > 13)
-                     kind = 13;
+                  if (curChar == 125 && kind > 14)
+                     kind = 14;
                   break;
                case 10:
                   if ((0x2ffffffeaffffffeL & l) == 0L)
                      break;
-                  if (kind > 14)
-                     kind = 14;
+                  if (kind > 15)
+                     kind = 15;
                   jjstateSet[jjnewStateCnt++] = 10;
                   break;
                case 13:
@@ -414,8 +476,8 @@ static final int[] jjnextStates = {
 
 /** Token literal values. */
 public static final String[] jjstrLiteralImages = {
-"", "\40", "\117\125\124\40", null, null, null, null, null, null, null, null, 
-null, null, null, null, null, null, };
+"", "\40", "\117\125\124\40", "\111\116\117\125\124\40", null, null, null, 
+null, null, null, null, null, null, null, null, null, null, null, };
 
 /** Lexer state names. */
 public static final String[] lexStateNames = {
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SimpleCharStream.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SimpleCharStream.java
index 482ba76..38d998e 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SimpleCharStream.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/SimpleCharStream.java
@@ -7,413 +7,465 @@ package org.apache.camel.component.sql.stored.template.generated;
  * contain only ASCII characters (without unicode processing).
  */
 
-public class SimpleCharStream {
-    /** Whether parser is static. */
-    public static final boolean staticFlag = false;
-    /** Position in buffer. */
-    public int bufpos = -1;
-    protected int bufline[];
-    protected int bufcolumn[];
-    protected int column = 0;
-    protected int line = 1;
-    protected boolean prevCharIsCR = false;
-    protected boolean prevCharIsLF = false;
-    protected java.io.Reader inputStream;
-    protected char[] buffer;
-    protected int maxNextCharInd = 0;
-    protected int inBuf = 0;
-    protected int tabSize = 8;
-    int bufsize;
-    int available;
-    int tokenBegin;
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.Reader dstream, int startline,
-                            int startcolumn, int buffersize) {
-        inputStream = dstream;
-        line = startline;
-        column = startcolumn - 1;
-
-        available = bufsize = buffersize;
-        buffer = new char[buffersize];
-        bufline = new int[buffersize];
-        bufcolumn = new int[buffersize];
-    }
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.Reader dstream, int startline,
-                            int startcolumn) {
-        this(dstream, startline, startcolumn, 4096);
-    }
-
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.Reader dstream) {
-        this(dstream, 1, 1, 4096);
-    }
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
-                            int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException {
-        this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
-    }
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.InputStream dstream, int startline,
-                            int startcolumn, int buffersize) {
-        this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
-    }
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
-                            int startcolumn) throws java.io.UnsupportedEncodingException {
-        this(dstream, encoding, startline, startcolumn, 4096);
-    }
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.InputStream dstream, int startline,
-                            int startcolumn) {
-        this(dstream, startline, startcolumn, 4096);
-    }
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException {
-        this(dstream, encoding, 1, 1, 4096);
-    }
-
-    /** Constructor. */
-    public SimpleCharStream(java.io.InputStream dstream) {
-        this(dstream, 1, 1, 4096);
-    }
-
-    protected void setTabSize(int i) {
-        tabSize = i;
-    }
-
-    protected int getTabSize(int i) {
-        return tabSize;
-    }
-
-    protected void ExpandBuff(boolean wrapAround) {
-        char[] newbuffer = new char[bufsize + 2048];
-        int newbufline[] = new int[bufsize + 2048];
-        int newbufcolumn[] = new int[bufsize + 2048];
-
-        try {
-            if (wrapAround) {
-                System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
-                System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
-                buffer = newbuffer;
-
-                System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
-                System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
-                bufline = newbufline;
-
-                System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
-                System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
-                bufcolumn = newbufcolumn;
-
-                maxNextCharInd = (bufpos += (bufsize - tokenBegin));
-            } else {
-                System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
-                buffer = newbuffer;
-
-                System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
-                bufline = newbufline;
-
-                System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
-                bufcolumn = newbufcolumn;
-
-                maxNextCharInd = (bufpos -= tokenBegin);
-            }
-        } catch (Throwable t) {
-            throw new Error(t.getMessage());
+public class SimpleCharStream
+{
+/** Whether parser is static. */
+  public static final boolean staticFlag = false;
+  int bufsize;
+  int available;
+  int tokenBegin;
+/** Position in buffer. */
+  public int bufpos = -1;
+  protected int bufline[];
+  protected int bufcolumn[];
+
+  protected int column = 0;
+  protected int line = 1;
+
+  protected boolean prevCharIsCR = false;
+  protected boolean prevCharIsLF = false;
+
+  protected java.io.Reader inputStream;
+
+  protected char[] buffer;
+  protected int maxNextCharInd = 0;
+  protected int inBuf = 0;
+  protected int tabSize = 8;
+
+  protected void setTabSize(int i) { tabSize = i; }
+  protected int getTabSize(int i) { return tabSize; }
+
+
+  protected void ExpandBuff(boolean wrapAround)
+  {
+    char[] newbuffer = new char[bufsize + 2048];
+    int newbufline[] = new int[bufsize + 2048];
+    int newbufcolumn[] = new int[bufsize + 2048];
+
+    try
+    {
+      if (wrapAround)
+      {
+        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+        System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+        buffer = newbuffer;
+
+        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+        System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+        bufline = newbufline;
+
+        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+        System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+        bufcolumn = newbufcolumn;
+
+        maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+      }
+      else
+      {
+        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+        buffer = newbuffer;
+
+        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+        bufline = newbufline;
+
+        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+        bufcolumn = newbufcolumn;
+
+        maxNextCharInd = (bufpos -= tokenBegin);
+      }
+    }
+    catch (Throwable t)
+    {
+      throw new Error(t.getMessage());
+    }
+
+
+    bufsize += 2048;
+    available = bufsize;
+    tokenBegin = 0;
+  }
+
+  protected void FillBuff() throws java.io.IOException
+  {
+    if (maxNextCharInd == available)
+    {
+      if (available == bufsize)
+      {
+        if (tokenBegin > 2048)
+        {
+          bufpos = maxNextCharInd = 0;
+          available = tokenBegin;
         }
-
-
-        bufsize += 2048;
+        else if (tokenBegin < 0)
+          bufpos = maxNextCharInd = 0;
+        else
+          ExpandBuff(false);
+      }
+      else if (available > tokenBegin)
         available = bufsize;
-        tokenBegin = 0;
-    }
-
-    protected void FillBuff() throws java.io.IOException {
-        if (maxNextCharInd == available) {
-            if (available == bufsize) {
-                if (tokenBegin > 2048) {
-                    bufpos = maxNextCharInd = 0;
-                    available = tokenBegin;
-                } else if (tokenBegin < 0)
-                    bufpos = maxNextCharInd = 0;
-                else
-                    ExpandBuff(false);
-            } else if (available > tokenBegin)
-                available = bufsize;
-            else if ((tokenBegin - available) < 2048)
-                ExpandBuff(true);
-            else
-                available = tokenBegin;
-        }
-
-        int i;
-        try {
-            if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) {
-                inputStream.close();
-                throw new java.io.IOException();
-            } else
-                maxNextCharInd += i;
-            return;
-        } catch (java.io.IOException e) {
-            --bufpos;
-            backup(0);
-            if (tokenBegin == -1)
-                tokenBegin = bufpos;
-            throw e;
-        }
-    }
-
-    /** Start. */
-    public char BeginToken() throws java.io.IOException {
-        tokenBegin = -1;
-        char c = readChar();
+      else if ((tokenBegin - available) < 2048)
+        ExpandBuff(true);
+      else
+        available = tokenBegin;
+    }
+
+    int i;
+    try {
+      if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+      {
+        inputStream.close();
+        throw new java.io.IOException();
+      }
+      else
+        maxNextCharInd += i;
+      return;
+    }
+    catch(java.io.IOException e) {
+      --bufpos;
+      backup(0);
+      if (tokenBegin == -1)
         tokenBegin = bufpos;
-
-        return c;
-    }
-
-    protected void UpdateLineColumn(char c) {
-        column++;
-
-        if (prevCharIsLF) {
-            prevCharIsLF = false;
-            line += (column = 1);
-        } else if (prevCharIsCR) {
-            prevCharIsCR = false;
-            if (c == '\n') {
-                prevCharIsLF = true;
-            } else
-                line += (column = 1);
-        }
-
-        switch (c) {
-            case '\r':
-                prevCharIsCR = true;
-                break;
-            case '\n':
-                prevCharIsLF = true;
-                break;
-            case '\t':
-                column--;
-                column += (tabSize - (column % tabSize));
-                break;
-            default:
-                break;
-        }
-
-        bufline[bufpos] = line;
-        bufcolumn[bufpos] = column;
-    }
-
-    /** Read a character. */
-    public char readChar() throws java.io.IOException {
-        if (inBuf > 0) {
-            --inBuf;
-
-            if (++bufpos == bufsize)
-                bufpos = 0;
-
-            return buffer[bufpos];
-        }
-
-        if (++bufpos >= maxNextCharInd)
-            FillBuff();
-
-        char c = buffer[bufpos];
-
-        UpdateLineColumn(c);
-        return c;
-    }
-
-    @Deprecated
-    /**
-     * @deprecated
-     * @see #getEndColumn
-     */
-
-    public int getColumn() {
-        return bufcolumn[bufpos];
-    }
-
-    @Deprecated
-    /**
-     * @deprecated
-     * @see #getEndLine
-     */
-
-    public int getLine() {
-        return bufline[bufpos];
-    }
-
-    /** Get token end column number. */
-    public int getEndColumn() {
-        return bufcolumn[bufpos];
-    }
-
-    /** Get token end line number. */
-    public int getEndLine() {
-        return bufline[bufpos];
-    }
-
-    /** Get token beginning column number. */
-    public int getBeginColumn() {
-        return bufcolumn[tokenBegin];
-    }
-
-    /** Get token beginning line number. */
-    public int getBeginLine() {
-        return bufline[tokenBegin];
-    }
-
-    /** Backup a number of characters. */
-    public void backup(int amount) {
-
-        inBuf += amount;
-        if ((bufpos -= amount) < 0)
-            bufpos += bufsize;
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.Reader dstream, int startline,
-                       int startcolumn, int buffersize) {
-        inputStream = dstream;
-        line = startline;
-        column = startcolumn - 1;
-
-        if (buffer == null || buffersize != buffer.length) {
-            available = bufsize = buffersize;
-            buffer = new char[buffersize];
-            bufline = new int[buffersize];
-            bufcolumn = new int[buffersize];
-        }
-        prevCharIsLF = prevCharIsCR = false;
-        tokenBegin = inBuf = maxNextCharInd = 0;
-        bufpos = -1;
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.Reader dstream, int startline,
-                       int startcolumn) {
-        ReInit(dstream, startline, startcolumn, 4096);
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.Reader dstream) {
-        ReInit(dstream, 1, 1, 4096);
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.InputStream dstream, String encoding, int startline,
-                       int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException {
-        ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.InputStream dstream, int startline,
-                       int startcolumn, int buffersize) {
-        ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException {
-        ReInit(dstream, encoding, 1, 1, 4096);
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.InputStream dstream) {
-        ReInit(dstream, 1, 1, 4096);
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.InputStream dstream, String encoding, int startline,
-                       int startcolumn) throws java.io.UnsupportedEncodingException {
-        ReInit(dstream, encoding, startline, startcolumn, 4096);
-    }
-
-    /** Reinitialise. */
-    public void ReInit(java.io.InputStream dstream, int startline,
-                       int startcolumn) {
-        ReInit(dstream, startline, startcolumn, 4096);
-    }
-
-    /** Get token literal value. */
-    public String GetImage() {
-        if (bufpos >= tokenBegin)
-            return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+      throw e;
+    }
+  }
+
+/** Start. */
+  public char BeginToken() throws java.io.IOException
+  {
+    tokenBegin = -1;
+    char c = readChar();
+    tokenBegin = bufpos;
+
+    return c;
+  }
+
+  protected void UpdateLineColumn(char c)
+  {
+    column++;
+
+    if (prevCharIsLF)
+    {
+      prevCharIsLF = false;
+      line += (column = 1);
+    }
+    else if (prevCharIsCR)
+    {
+      prevCharIsCR = false;
+      if (c == '\n')
+      {
+        prevCharIsLF = true;
+      }
+      else
+        line += (column = 1);
+    }
+
+    switch (c)
+    {
+      case '\r' :
+        prevCharIsCR = true;
+        break;
+      case '\n' :
+        prevCharIsLF = true;
+        break;
+      case '\t' :
+        column--;
+        column += (tabSize - (column % tabSize));
+        break;
+      default :
+        break;
+    }
+
+    bufline[bufpos] = line;
+    bufcolumn[bufpos] = column;
+  }
+
+/** Read a character. */
+  public char readChar() throws java.io.IOException
+  {
+    if (inBuf > 0)
+    {
+      --inBuf;
+
+      if (++bufpos == bufsize)
+        bufpos = 0;
+
+      return buffer[bufpos];
+    }
+
+    if (++bufpos >= maxNextCharInd)
+      FillBuff();
+
+    char c = buffer[bufpos];
+
+    UpdateLineColumn(c);
+    return c;
+  }
+
+  @Deprecated
+  /**
+   * @deprecated
+   * @see #getEndColumn
+   */
+
+  public int getColumn() {
+    return bufcolumn[bufpos];
+  }
+
+  @Deprecated
+  /**
+   * @deprecated
+   * @see #getEndLine
+   */
+
+  public int getLine() {
+    return bufline[bufpos];
+  }
+
+  /** Get token end column number. */
+  public int getEndColumn() {
+    return bufcolumn[bufpos];
+  }
+
+  /** Get token end line number. */
+  public int getEndLine() {
+     return bufline[bufpos];
+  }
+
+  /** Get token beginning column number. */
+  public int getBeginColumn() {
+    return bufcolumn[tokenBegin];
+  }
+
+  /** Get token beginning line number. */
+  public int getBeginLine() {
+    return bufline[tokenBegin];
+  }
+
+/** Backup a number of characters. */
+  public void backup(int amount) {
+
+    inBuf += amount;
+    if ((bufpos -= amount) < 0)
+      bufpos += bufsize;
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    available = bufsize = buffersize;
+    buffer = new char[buffersize];
+    bufline = new int[buffersize];
+    bufcolumn = new int[buffersize];
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.Reader dstream, int startline,
+                          int startcolumn)
+  {
+    this(dstream, startline, startcolumn, 4096);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.Reader dstream)
+  {
+    this(dstream, 1, 1, 4096);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    if (buffer == null || buffersize != buffer.length)
+    {
+      available = bufsize = buffersize;
+      buffer = new char[buffersize];
+      bufline = new int[buffersize];
+      bufcolumn = new int[buffersize];
+    }
+    prevCharIsLF = prevCharIsCR = false;
+    tokenBegin = inBuf = maxNextCharInd = 0;
+    bufpos = -1;
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.Reader dstream, int startline,
+                     int startcolumn)
+  {
+    ReInit(dstream, startline, startcolumn, 4096);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.Reader dstream)
+  {
+    ReInit(dstream, 1, 1, 4096);
+  }
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+  int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+  {
+    this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+                          int startcolumn) throws java.io.UnsupportedEncodingException
+  {
+    this(dstream, encoding, startline, startcolumn, 4096);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, int startline,
+                          int startcolumn)
+  {
+    this(dstream, startline, startcolumn, 4096);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+  {
+    this(dstream, encoding, 1, 1, 4096);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream)
+  {
+    this(dstream, 1, 1, 4096);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+                          int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+  {
+    ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, int startline,
+                          int startcolumn, int buffersize)
+  {
+    ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+  {
+    ReInit(dstream, encoding, 1, 1, 4096);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream)
+  {
+    ReInit(dstream, 1, 1, 4096);
+  }
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+                     int startcolumn) throws java.io.UnsupportedEncodingException
+  {
+    ReInit(dstream, encoding, startline, startcolumn, 4096);
+  }
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, int startline,
+                     int startcolumn)
+  {
+    ReInit(dstream, startline, startcolumn, 4096);
+  }
+  /** Get token literal value. */
+  public String GetImage()
+  {
+    if (bufpos >= tokenBegin)
+      return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+    else
+      return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+                            new String(buffer, 0, bufpos + 1);
+  }
+
+  /** Get the suffix. */
+  public char[] GetSuffix(int len)
+  {
+    char[] ret = new char[len];
+
+    if ((bufpos + 1) >= len)
+      System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+    else
+    {
+      System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+                                                        len - bufpos - 1);
+      System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+    }
+
+    return ret;
+  }
+
+  /** Reset buffer when finished. */
+  public void Done()
+  {
+    buffer = null;
+    bufline = null;
+    bufcolumn = null;
+  }
+
+  /**
+   * Method to adjust line and column numbers for the start of a token.
+   */
+  public void adjustBeginLineColumn(int newLine, int newCol)
+  {
+    int start = tokenBegin;
+    int len;
+
+    if (bufpos >= tokenBegin)
+    {
+      len = bufpos - tokenBegin + inBuf + 1;
+    }
+    else
+    {
+      len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+    }
+
+    int i = 0, j = 0, k = 0;
+    int nextColDiff = 0, columnDiff = 0;
+
+    while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+    {
+      bufline[j] = newLine;
+      nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+      bufcolumn[j] = newCol + columnDiff;
+      columnDiff = nextColDiff;
+      i++;
+    }
+
+    if (i < len)
+    {
+      bufline[j] = newLine++;
+      bufcolumn[j] = newCol + columnDiff;
+
+      while (i++ < len)
+      {
+        if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+          bufline[j] = newLine++;
         else
-            return new String(buffer, tokenBegin, bufsize - tokenBegin) +
-                    new String(buffer, 0, bufpos + 1);
+          bufline[j] = newLine;
+      }
     }
 
-    /** Get the suffix. */
-    public char[] GetSuffix(int len) {
-        char[] ret = new char[len];
-
-        if ((bufpos + 1) >= len)
-            System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
-        else {
-            System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
-                    len - bufpos - 1);
-            System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
-        }
-
-        return ret;
-    }
-
-    /** Reset buffer when finished. */
-    public void Done() {
-        buffer = null;
-        bufline = null;
-        bufcolumn = null;
-    }
-
-    /**
-     * Method to adjust line and column numbers for the start of a token.
-     */
-    public void adjustBeginLineColumn(int newLine, int newCol) {
-        int start = tokenBegin;
-        int len;
-
-        if (bufpos >= tokenBegin) {
-            len = bufpos - tokenBegin + inBuf + 1;
-        } else {
-            len = bufsize - tokenBegin + bufpos + 1 + inBuf;
-        }
-
-        int i = 0, j = 0, k = 0;
-        int nextColDiff = 0, columnDiff = 0;
-
-        while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) {
-            bufline[j] = newLine;
-            nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
-            bufcolumn[j] = newCol + columnDiff;
-            columnDiff = nextColDiff;
-            i++;
-        }
-
-        if (i < len) {
-            bufline[j] = newLine++;
-            bufcolumn[j] = newCol + columnDiff;
-
-            while (i++ < len) {
-                if (bufline[j = start % bufsize] != bufline[++start % bufsize])
-                    bufline[j] = newLine++;
-                else
-                    bufline[j] = newLine;
-            }
-        }
-
-        line = bufline[j];
-        column = bufcolumn[j];
-    }
+    line = bufline[j];
+    column = bufcolumn[j];
+  }
 
 }
 /* JavaCC - OriginalChecksum=78e981b5210775b82383fb6e32f1e767 (do not edit this line) */
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/Token.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/Token.java
index 22b3b65..c2d86e2 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/Token.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/Token.java
@@ -8,120 +8,124 @@ package org.apache.camel.component.sql.stored.template.generated;
 
 public class Token implements java.io.Serializable {
 
-    /**
-     * The version identifier for this Serializable class.
-     * Increment only if the <i>serialized</i> form of the
-     * class changes.
-     */
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * An integer that describes the kind of this token.  This numbering
-     * system is determined by JavaCCParser, and a table of these numbers is
-     * stored in the file ...Constants.java.
-     */
-    public int kind;
-
-    /** The line number of the first character of this Token. */
-    public int beginLine;
-    /** The column number of the first character of this Token. */
-    public int beginColumn;
-    /** The line number of the last character of this Token. */
-    public int endLine;
-    /** The column number of the last character of this Token. */
-    public int endColumn;
-
-    /**
-     * The string image of the token.
-     */
-    public String image;
-
-    /**
-     * A reference to the next regular (non-special) token from the input
-     * stream.  If this is the last token from the input stream, or if the
-     * token manager has not read tokens beyond this one, this field is
-     * set to null.  This is true only if this token is also a regular
-     * token.  Otherwise, see below for a description of the contents of
-     * this field.
-     */
-    public Token next;
-
-    /**
-     * This field is used to access special tokens that occur prior to this
-     * token, but after the immediately preceding regular (non-special) token.
-     * If there are no such special tokens, this field is set to null.
-     * When there are more than one such special token, this field refers
-     * to the last of these special tokens, which in turn refers to the next
-     * previous special token through its specialToken field, and so on
-     * until the first special token (whose specialToken field is null).
-     * The next fields of special tokens refer to other special tokens that
-     * immediately follow it (without an intervening regular token).  If there
-     * is no such token, this field is null.
-     */
-    public Token specialToken;
-
-    /**
-     * No-argument constructor
-     */
-    public Token() {
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * An integer that describes the kind of this token.  This numbering
+   * system is determined by JavaCCParser, and a table of these numbers is
+   * stored in the file ...Constants.java.
+   */
+  public int kind;
+
+  /** The line number of the first character of this Token. */
+  public int beginLine;
+  /** The column number of the first character of this Token. */
+  public int beginColumn;
+  /** The line number of the last character of this Token. */
+  public int endLine;
+  /** The column number of the last character of this Token. */
+  public int endColumn;
+
+  /**
+   * The string image of the token.
+   */
+  public String image;
+
+  /**
+   * A reference to the next regular (non-special) token from the input
+   * stream.  If this is the last token from the input stream, or if the
+   * token manager has not read tokens beyond this one, this field is
+   * set to null.  This is true only if this token is also a regular
+   * token.  Otherwise, see below for a description of the contents of
+   * this field.
+   */
+  public Token next;
+
+  /**
+   * This field is used to access special tokens that occur prior to this
+   * token, but after the immediately preceding regular (non-special) token.
+   * If there are no such special tokens, this field is set to null.
+   * When there are more than one such special token, this field refers
+   * to the last of these special tokens, which in turn refers to the next
+   * previous special token through its specialToken field, and so on
+   * until the first special token (whose specialToken field is null).
+   * The next fields of special tokens refer to other special tokens that
+   * immediately follow it (without an intervening regular token).  If there
+   * is no such token, this field is null.
+   */
+  public Token specialToken;
+
+  /**
+   * An optional attribute value of the Token.
+   * Tokens which are not used as syntactic sugar will often contain
+   * meaningful values that will be used later on by the compiler or
+   * interpreter. This attribute value is often different from the image.
+   * Any subclass of Token that actually wants to return a non-null value can
+   * override this method as appropriate.
+   */
+  public Object getValue() {
+    return null;
+  }
+
+  /**
+   * No-argument constructor
+   */
+  public Token() {}
+
+  /**
+   * Constructs a new token for the specified Image.
+   */
+  public Token(int kind)
+  {
+    this(kind, null);
+  }
+
+  /**
+   * Constructs a new token for the specified Image and Kind.
+   */
+  public Token(int kind, String image)
+  {
+    this.kind = kind;
+    this.image = image;
+  }
+
+  /**
+   * Returns the image.
+   */
+  public String toString()
+  {
+    return image;
+  }
+
+  /**
+   * Returns a new Token object, by default. However, if you want, you
+   * can create and return subclass objects based on the value of ofKind.
+   * Simply add the cases to the switch for all those special cases.
+   * For example, if you have a subclass of Token called IDToken that
+   * you want to create if ofKind is ID, simply add something like :
+   *
+   *    case MyParserConstants.ID : return new IDToken(ofKind, image);
+   *
+   * to the following switch statement. Then you can cast matchedToken
+   * variable to the appropriate type and use sit in your lexical actions.
+   */
+  public static Token newToken(int ofKind, String image)
+  {
+    switch(ofKind)
+    {
+      default : return new Token(ofKind, image);
     }
+  }
 
-    /**
-     * Constructs a new token for the specified Image.
-     */
-    public Token(int kind) {
-        this(kind, null);
-    }
-
-    /**
-     * Constructs a new token for the specified Image and Kind.
-     */
-    public Token(int kind, String image) {
-        this.kind = kind;
-        this.image = image;
-    }
-
-    /**
-     * Returns a new Token object, by default. However, if you want, you
-     * can create and return subclass objects based on the value of ofKind.
-     * Simply add the cases to the switch for all those special cases.
-     * For example, if you have a subclass of Token called IDToken that
-     * you want to create if ofKind is ID, simply add something like :
-     *
-     * case MyParserConstants.ID : return new IDToken(ofKind, image);
-     *
-     * to the following switch statement. Then you can cast matchedToken
-     * variable to the appropriate type and use sit in your lexical actions.
-     */
-    public static Token newToken(int ofKind, String image) {
-        switch (ofKind) {
-            default:
-                return new Token(ofKind, image);
-        }
-    }
-
-    public static Token newToken(int ofKind) {
-        return newToken(ofKind, null);
-    }
-
-    /**
-     * An optional attribute value of the Token.
-     * Tokens which are not used as syntactic sugar will often contain
-     * meaningful values that will be used later on by the compiler or
-     * interpreter. This attribute value is often different from the image.
-     * Any subclass of Token that actually wants to return a non-null value can
-     * override this method as appropriate.
-     */
-    public Object getValue() {
-        return null;
-    }
-
-    /**
-     * Returns the image.
-     */
-    public String toString() {
-        return image;
-    }
+  public static Token newToken(int ofKind)
+  {
+    return newToken(ofKind, null);
+  }
 
 }
 /* JavaCC - OriginalChecksum=7e8baa74d8a01b01496421112dcea294 (do not edit this line) */
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/TokenMgrError.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/TokenMgrError.java
index 13fd322..3689f73 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/TokenMgrError.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/TokenMgrError.java
@@ -3,138 +3,145 @@
 package org.apache.camel.component.sql.stored.template.generated;
 
 /** Token Manager Error. */
-public class TokenMgrError extends Error {
+public class TokenMgrError extends Error
+{
 
-    /**
-     * Lexical error occurred.
-     */
-    static final int LEXICAL_ERROR = 0;
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
 
   /*
    * Ordinals for various reasons why an Error of this type can be thrown.
    */
-    /**
-     * An attempt was made to create a second instance of a static token manager.
-     */
-    static final int STATIC_LEXER_ERROR = 1;
-    /**
-     * Tried to change to an invalid lexical state.
-     */
-    static final int INVALID_LEXICAL_STATE = 2;
-    /**
-     * Detected (and bailed out of) an infinite loop in the token manager.
-     */
-    static final int LOOP_DETECTED = 3;
-    /**
-     * The version identifier for this Serializable class.
-     * Increment only if the <i>serialized</i> form of the
-     * class changes.
-     */
-    private static final long serialVersionUID = 1L;
-    /**
-     * Indicates the reason why the exception is thrown. It will have
-     * one of the above 4 values.
-     */
-    int errorCode;
 
-    /** No arg constructor. */
-    public TokenMgrError() {
-    }
+  /**
+   * Lexical error occurred.
+   */
+  static final int LEXICAL_ERROR = 0;
 
-    /** Constructor with message and reason. */
-    public TokenMgrError(String message, int reason) {
-        super(message);
-        errorCode = reason;
-    }
+  /**
+   * An attempt was made to create a second instance of a static token manager.
+   */
+  static final int STATIC_LEXER_ERROR = 1;
 
-    /** Full Constructor. */
-    public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
-        this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+  /**
+   * Tried to change to an invalid lexical state.
+   */
+  static final int INVALID_LEXICAL_STATE = 2;
+
+  /**
+   * Detected (and bailed out of) an infinite loop in the token manager.
+   */
+  static final int LOOP_DETECTED = 3;
+
+  /**
+   * Indicates the reason why the exception is thrown. It will have
+   * one of the above 4 values.
+   */
+  int errorCode;
+
+  /**
+   * Replaces unprintable characters by their escaped (or unicode escaped)
+   * equivalents in the given string
+   */
+  protected static final String addEscapes(String str) {
+    StringBuffer retval = new StringBuffer();
+    char ch;
+    for (int i = 0; i < str.length(); i++) {
+      switch (str.charAt(i))
+      {
+        case 0 :
+          continue;
+        case '\b':
+          retval.append("\\b");
+          continue;
+        case '\t':
+          retval.append("\\t");
+          continue;
+        case '\n':
+          retval.append("\\n");
+          continue;
+        case '\f':
+          retval.append("\\f");
+          continue;
+        case '\r':
+          retval.append("\\r");
+          continue;
+        case '\"':
+          retval.append("\\\"");
+          continue;
+        case '\'':
+          retval.append("\\\'");
+          continue;
+        case '\\':
+          retval.append("\\\\");
+          continue;
+        default:
+          if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+            String s = "0000" + Integer.toString(ch, 16);
+            retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+          } else {
+            retval.append(ch);
+          }
+          continue;
+      }
     }
+    return retval.toString();
+  }
+
+  /**
+   * Returns a detailed message for the Error when it is thrown by the
+   * token manager to indicate a lexical error.
+   * Parameters :
+   *    EOFSeen     : indicates if EOF caused the lexical error
+   *    curLexState : lexical state in which this error occurred
+   *    errorLine   : line number when the error occurred
+   *    errorColumn : column number when the error occurred
+   *    errorAfter  : prefix that was seen before this error occurred
+   *    curchar     : the offending character
+   * Note: You can customize the lexical error message by modifying this method.
+   */
+  protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+    return("Lexical error at line " +
+          errorLine + ", column " +
+          errorColumn + ".  Encountered: " +
+          (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+          "after : \"" + addEscapes(errorAfter) + "\"");
+  }
+
+  /**
+   * You can also modify the body of this method to customize your error messages.
+   * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+   * of end-users concern, so you can return something like :
+   *
+   *     "Internal Error : Please file a bug report .... "
+   *
+   * from this method for such cases in the release version of your parser.
+   */
+  public String getMessage() {
+    return super.getMessage();
+  }
 
   /*
    * Constructors of various flavors follow.
    */
 
-    /**
-     * Replaces unprintable characters by their escaped (or unicode escaped)
-     * equivalents in the given string
-     */
-    protected static final String addEscapes(String str) {
-        StringBuffer retval = new StringBuffer();
-        char ch;
-        for (int i = 0; i < str.length(); i++) {
-            switch (str.charAt(i)) {
-                case 0:
-                    continue;
-                case '\b':
-                    retval.append("\\b");
-                    continue;
-                case '\t':
-                    retval.append("\\t");
-                    continue;
-                case '\n':
-                    retval.append("\\n");
-                    continue;
-                case '\f':
-                    retval.append("\\f");
-                    continue;
-                case '\r':
-                    retval.append("\\r");
-                    continue;
-                case '\"':
-                    retval.append("\\\"");
-                    continue;
-                case '\'':
-                    retval.append("\\\'");
-                    continue;
-                case '\\':
-                    retval.append("\\\\");
-                    continue;
-                default:
-                    if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
-                        String s = "0000" + Integer.toString(ch, 16);
-                        retval.append("\\u" + s.substring(s.length() - 4, s.length()));
-                    } else {
-                        retval.append(ch);
-                    }
-                    continue;
-            }
-        }
-        return retval.toString();
-    }
+  /** No arg constructor. */
+  public TokenMgrError() {
+  }
 
-    /**
-     * Returns a detailed message for the Error when it is thrown by the
-     * token manager to indicate a lexical error.
-     * Parameters :
-     * EOFSeen     : indicates if EOF caused the lexical error
-     * curLexState : lexical state in which this error occurred
-     * errorLine   : line number when the error occurred
-     * errorColumn : column number when the error occurred
-     * errorAfter  : prefix that was seen before this error occurred
-     * curchar     : the offending character
-     * Note: You can customize the lexical error message by modifying this method.
-     */
-    protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
-        return ("Lexical error at line " +
-                errorLine + ", column " +
-                errorColumn + ".  Encountered: " +
-                (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int) curChar + "), ") +
-                "after : \"" + addEscapes(errorAfter) + "\"");
-    }
+  /** Constructor with message and reason. */
+  public TokenMgrError(String message, int reason) {
+    super(message);
+    errorCode = reason;
+  }
 
-    /**
-     * You can also modify the body of this method to customize your error messages.
-     * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
-     * of end-users concern, so you can return something like :
-     *
-     * "Internal Error : Please file a bug report .... "
-     *
-     * from this method for such cases in the release version of your parser.
-     */
-    public String getMessage() {
-        return super.getMessage();
-    }
+  /** Full Constructor. */
+  public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+    this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+  }
 }
 /* JavaCC - OriginalChecksum=076ac52ededde06a2bcb85f2834da49c (do not edit this line) */
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/grammar/sspt.jj b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/grammar/sspt.jj
index 96256ee..1b054db 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/grammar/sspt.jj
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/grammar/sspt.jj
@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
-// Using some token definions from: http://kiwwito.com/build-a-lexical-analyzer-with-javacc/
+// Using some token definitions from: http://kiwwito.com/build-a-lexical-analyzer-with-javacc/
 
 options {
     STATIC = false;
@@ -69,10 +69,10 @@ Object Parameter() :
     Object param;
 }
 {
-     (param = InputParameter() {return param;}) | (param = OutParameter(){return param;})
+     (param = InParameter() {return param;}) | (param = OutParameter(){return param;}) | (param = InOutParameter(){return param;})
 }
 
-InputParameter InputParameter() :
+InParameter InParameter() :
 {
      Token sqlTypeToken;
      String name = null;
@@ -82,11 +82,11 @@ InputParameter InputParameter() :
 }
 {
     ((name = ParameterName() " ")? sqlTypeToken = ParameterSqlType() (scale = Scale())? " " (typeName = ParameterName() " ")? valueSrcToken =
-    InputParameterSrc())
+    InParameterSrc())
     {
         int sqlType = ParseHelper.parseSqlType(sqlTypeToken, classResolver);
 
-        return new InputParameter(name == null ? createNextParameterName() : name, sqlType, valueSrcToken, scale, typeName);
+        return new InParameter(name == null ? createNextParameterName() : name, sqlType, valueSrcToken, scale, typeName);
     }
 }
 
@@ -105,6 +105,24 @@ OutParameter OutParameter() :
     }
 }
 
+InOutParameter InOutParameter() :
+{
+     Token sqlTypeToken;
+     Token valueSrcToken;
+     Integer scale = null;
+     String typeName = null;
+     String outValueMapKey;
+}
+{
+    ("INOUT " sqlTypeToken = ParameterSqlType() (scale = Scale())? " "
+    (typeName = ParameterName() " ")? valueSrcToken = InParameterSrc() " " outValueMapKey = OutHeader())
+    {
+        int sqlType = ParseHelper.parseSqlType(sqlTypeToken, classResolver);
+
+        return new InOutParameter(sqlType, valueSrcToken, scale, typeName, outValueMapKey);
+    }
+}
+
 String ParameterName():
 {
     Token t = null;
@@ -152,7 +170,7 @@ String OutHeader():
         return token.toString();
     }
 }
-Token InputParameterSrc():
+Token InParameterSrc():
 {
     Token ret = null;
 }
diff --git a/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/ParserTest.java b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/ParserTest.java
index d55c8eb..01e7be4 100644
--- a/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/ParserTest.java
+++ b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/ParserTest.java
@@ -21,12 +21,11 @@ import java.sql.Types;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
-import org.apache.camel.RoutesBuilder;
 import org.apache.camel.component.properties.PropertiesComponent;
 import org.apache.camel.component.sql.stored.template.TemplateParser;
-import org.apache.camel.component.sql.stored.template.ast.InputParameter;
+import org.apache.camel.component.sql.stored.template.ast.InOutParameter;
+import org.apache.camel.component.sql.stored.template.ast.InParameter;
 import org.apache.camel.component.sql.stored.template.ast.OutParameter;
 import org.apache.camel.component.sql.stored.template.ast.ParseRuntimeException;
 import org.apache.camel.component.sql.stored.template.ast.Template;
@@ -38,8 +37,6 @@ public class ParserTest extends CamelTestSupport {
 
     TemplateParser parser;
 
-
-
     @Override
     protected void startCamelContext() throws Exception {
         super.startCamelContext();
@@ -48,35 +45,41 @@ public class ParserTest extends CamelTestSupport {
 
     @Test
     public void shouldParseOk() {
-        Template template = parser.parseTemplate("addnumbers(INTEGER ${header.header1},"
-                + "VARCHAR ${property.property1},BIGINT ${header.header2},OUT INTEGER header1)");
+        Template template = parser.parseTemplate("addnumbers(INTEGER ${header.header1},VARCHAR ${property.property1},"
+                + "BIGINT ${header.header2},INOUT INTEGER ${header.header3} inout1,OUT INTEGER out1)");
 
         Assert.assertEquals("addnumbers", template.getProcedureName());
-        Assert.assertEquals(4, template.getParameterList().size());
+        Assert.assertEquals(5, template.getParameterList().size());
 
         Exchange exchange = createExchangeWithBody(null);
         exchange.getIn().setHeader("header1", 1);
         exchange.setProperty("property1", "constant string");
         exchange.getIn().setHeader("header2", BigInteger.valueOf(2));
+        exchange.getIn().setHeader("header3", BigInteger.valueOf(3));
 
-        InputParameter param1 = (InputParameter) template.getParameterList().get(0);
+        InParameter param1 = (InParameter) template.getParameterList().get(0);
         Assert.assertEquals("_0", param1.getName());
         Assert.assertEquals(Types.INTEGER, param1.getSqlType());
         Assert.assertEquals(1, param1.getValueExtractor().eval(exchange, null));
 
-        InputParameter param2 = (InputParameter) template.getParameterList().get(1);
+        InParameter param2 = (InParameter) template.getParameterList().get(1);
         Assert.assertEquals("_1", param2.getName());
         Assert.assertEquals(Types.VARCHAR, param2.getSqlType());
         Assert.assertEquals("constant string", param2.getValueExtractor().eval(exchange, null));
 
-        InputParameter param3 = (InputParameter) template.getParameterList().get(2);
+        InParameter param3 = (InParameter) template.getParameterList().get(2);
         Assert.assertEquals("_2", param3.getName());
         Assert.assertEquals(Types.BIGINT, param3.getSqlType());
         Assert.assertEquals(BigInteger.valueOf(2L), param3.getValueExtractor().eval(exchange, null));
 
-        OutParameter sptpOutputNode = (OutParameter) template.getParameterList().get(3);
-        Assert.assertEquals(Types.INTEGER, sptpOutputNode.getSqlType());
-        Assert.assertEquals("header1", sptpOutputNode.getOutValueMapKey());
+        InOutParameter inOutNode = (InOutParameter) template.getParameterList().get(3);
+        Assert.assertEquals(Types.INTEGER, inOutNode.getSqlType());
+        Assert.assertEquals("inout1", inOutNode.getOutValueMapKey());
+        Assert.assertEquals(BigInteger.valueOf(3L), inOutNode.getValueExtractor().eval(exchange, null));
+
+        OutParameter outNode = (OutParameter) template.getParameterList().get(4);
+        Assert.assertEquals(Types.INTEGER, outNode.getSqlType());
+        Assert.assertEquals("out1", outNode.getOutValueMapKey());
     }
 
     @Test(expected = ParseRuntimeException.class)
@@ -97,20 +100,20 @@ public class ParserTest extends CamelTestSupport {
         exchange.getIn().setHeader("foo", 1);
         exchange.getIn().setHeader("bar", 3);
         Template template = parser.parseTemplate("ADDNUMBERS2(INTEGER ${header.foo},INTEGER ${header.bar})");
-        assertEquals(1, ((InputParameter) template.getParameterList().get(0)).getValueExtractor().eval(exchange, null));
-        assertEquals(3, ((InputParameter) template.getParameterList().get(1)).getValueExtractor().eval(exchange, null));
+        assertEquals(1, ((InParameter) template.getParameterList().get(0)).getValueExtractor().eval(exchange, null));
+        assertEquals(3, ((InParameter) template.getParameterList().get(1)).getValueExtractor().eval(exchange, null));
     }
 
     @Test
     public void vendorSpecificPositiveSqlType() {
         Template template = parser.parseTemplate("ADDNUMBERS2(1342 ${header.foo})");
-        assertEquals(1342, ((InputParameter) template.getParameterList().get(0)).getSqlType());
+        assertEquals(1342, ((InParameter) template.getParameterList().get(0)).getSqlType());
     }
 
     @Test
     public void vendorSpecificNegativeSqlType() {
         Template template = parser.parseTemplate("ADDNUMBERS2(-1342 ${header.foo})");
-        assertEquals(-1342, ((InputParameter) template.getParameterList().get(0)).getSqlType());
+        assertEquals(-1342, ((InParameter) template.getParameterList().get(0)).getSqlType());
     }
 
     @Test
@@ -120,7 +123,7 @@ public class ParserTest extends CamelTestSupport {
         Exchange exchange = createExchangeWithBody(1);
         Template template = parser.parseTemplate("ADDNUMBERS2(-1342 ${properties:java.naming.factory.initial})");
         assertEquals("org.apache.camel.util.jndi.CamelInitialContextFactory",
-            ((InputParameter) template.getParameterList().get(0)).getValueExtractor().eval(exchange, null));
+            ((InParameter) template.getParameterList().get(0)).getValueExtractor().eval(exchange, null));
     }
 
     @Test
@@ -130,7 +133,7 @@ public class ParserTest extends CamelTestSupport {
 
         Map container = new HashMap();
         container.put("a:", 1);
-        assertEquals(1, ((InputParameter) template.getParameterList().get(0)).getValueExtractor().eval(exchange, container));
+        assertEquals(1, ((InParameter) template.getParameterList().get(0)).getValueExtractor().eval(exchange, container));
     }
 
     @Test
@@ -150,7 +153,7 @@ public class ParserTest extends CamelTestSupport {
         Map<String, String> params = new HashMap<>();
         params.put("P_STR_IN", "a");
         Template template = parser.parseTemplate("IBS.\"Z$IMS_INTERFACE_WS\".TEST_STR(VARCHAR :#P_STR_IN,OUT VARCHAR P_STR_OUT)");
-        assertEquals("a", ((InputParameter) template.getParameterList().get(0)).getValueExtractor().eval(null, params));
+        assertEquals("a", ((InParameter) template.getParameterList().get(0)).getValueExtractor().eval(null, params));
         assertEquals("IBS.\"Z$IMS_INTERFACE_WS\".TEST_STR", template.getProcedureName());
     }
 
@@ -163,32 +166,34 @@ public class ParserTest extends CamelTestSupport {
     @Test
     public void testParameterNameGiven() {
         Template template = parser.parseTemplate("FOO('p_instance_id' INTEGER ${header.foo})");
-        assertEquals("p_instance_id", ((InputParameter) template.getParameterList().get(0)).getName());
+        assertEquals("p_instance_id", ((InParameter) template.getParameterList().get(0)).getName());
     }
 
     @Test
     public void testParameterVendor() {
         Template template = parser.parseTemplate("FOO('p_instance_id' org.apache.camel.component.sql.stored.CustomType.INTEGER ${header.foo})");
-        assertEquals(1, ((InputParameter) template.getParameterList().get(0)).getSqlType());
+        assertEquals(1, ((InParameter) template.getParameterList().get(0)).getSqlType());
     }
 
     @Test
     public void testParameterVendorType() {
         Template template = parser.parseTemplate("FOO('p_instance_id' 2 ${header.foo})");
-        assertEquals(2, ((InputParameter) template.getParameterList().get(0)).getSqlType());
+        assertEquals(2, ((InParameter) template.getParameterList().get(0)).getSqlType());
     }
 
     @Test
     public void testParameterTypeName() {
-        Template template = parser.parseTemplate("FOO('p_instance_id' 2 'p_2' ${header.foo})");
-        assertEquals("p_2", ((InputParameter) template.getParameterList().get(0)).getTypeName());
+        Template template = parser.parseTemplate("FOO('p_instance_1' 1 'p_1' ${header.foo1},"
+                + "INOUT 2 'p_2' ${header.foo2} p_out)");
+        assertEquals("p_1", ((InParameter) template.getParameterList().get(0)).getTypeName());
+        assertEquals("p_2", ((InOutParameter) template.getParameterList().get(1)).getTypeName());
     }
 
 
     @Test
     public void testParameterVendorTypeNegativ() {
         Template template = parser.parseTemplate("FOO('p_instance_id' -2 ${header.foo})");
-        assertEquals(-2, ((InputParameter) template.getParameterList().get(0)).getSqlType());
+        assertEquals(-2, ((InParameter) template.getParameterList().get(0)).getSqlType());
     }
 
     @Test
@@ -221,7 +226,7 @@ public class ParserTest extends CamelTestSupport {
     @Test
     public void testOracleTypesNumeric() {
         Template template = parser.parseTemplate("FOO('p_error_cd' org.apache.camel.component.sql.stored.CustomType.INTEGER(10) ${header.foo})");
-        assertEquals(Integer.valueOf(10), ((InputParameter) template.getParameterList().get(0)).getScale());
+        assertEquals(Integer.valueOf(10), ((InParameter) template.getParameterList().get(0)).getScale());
     }
 
     @Test
diff --git a/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/ProducerInOutTest.java b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/ProducerInOutTest.java
new file mode 100644
index 0000000..aa74d80
--- /dev/null
+++ b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/ProducerInOutTest.java
@@ -0,0 +1,85 @@
+/**
+ * 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.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+
+public class ProducerInOutTest extends CamelTestSupport {
+
+    EmbeddedDatabase db;
+
+    @Before
+    public void setUp() throws Exception {
+        db = new EmbeddedDatabaseBuilder()
+                .setType(EmbeddedDatabaseType.DERBY).addScript("sql/storedProcedureTest.sql").build();
+        super.setUp();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+        db.shutdown();
+    }
+
+    @Test
+    public void testInOutStoredProcedure() throws InterruptedException {
+        MockEndpoint mock = getMockEndpoint("mock:query");
+        mock.expectedMessageCount(1);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("in1", 0);
+        headers.put("in2", 0);
+        template.requestBodyAndHeaders("direct:query", null, headers);
+
+        assertMockEndpointsSatisfied();
+
+        Exchange exchange = mock.getExchanges().get(0);
+
+        Map results = exchange.getIn().getBody(Map.class);
+        assertEquals(1, results.get("out1"));
+        assertEquals(2, results.get("out2"));
+        assertNotNull(exchange.getIn().getHeader(SqlStoredConstants.SQL_STORED_UPDATE_COUNT));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // required for the sql component
+                getContext().getComponent("sql-stored", SqlStoredComponent.class).setDataSource(db);
+
+                from("direct:query")
+                    .to("sql-stored:INOUTDEMO(INTEGER ${headers.in1},INOUT INTEGER ${headers.in2} out1,OUT INTEGER out2)")
+                    .to("mock:query");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/TestStoredProcedure.java b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/TestStoredProcedure.java
index fea0d11..bc99d45 100644
--- a/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/TestStoredProcedure.java
+++ b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/TestStoredProcedure.java
@@ -36,7 +36,6 @@ public final class TestStoredProcedure {
         ret[0] = val1 - val2;
     }
 
-
     public static void batchfn(String val1) {
         LOG.info("calling batchfn:{}", val1);
         if (val1 == null) {
@@ -45,9 +44,13 @@ public final class TestStoredProcedure {
         BATCHFN_CALL_COUNTER.incrementAndGet();
     }
 
-
     public static void niladic() {
         LOG.info("nilacid called");
     }
 
+    public static void inoutdemo(int in1, int[] inout1, int[] out1) {
+        LOG.info("calling inoutdemo: {}, {}", inout1[0], out1[0]);
+        inout1[0] = 1;
+        out1[0] = 2;
+    }
 }
diff --git a/components/camel-sql/src/test/resources/sql/storedProcedureTest.sql b/components/camel-sql/src/test/resources/sql/storedProcedureTest.sql
index a1a0750..1cc9540 100644
--- a/components/camel-sql/src/test/resources/sql/storedProcedureTest.sql
+++ b/components/camel-sql/src/test/resources/sql/storedProcedureTest.sql
@@ -33,6 +33,12 @@ CREATE PROCEDURE BATCHFN(VALUE1 CHAR(10))
  EXTERNAL NAME
 'org.apache.camel.component.sql.stored.TestStoredProcedure.batchfn';
 
+CREATE PROCEDURE INOUTDEMO(IN1 INTEGER, INOUT IN2 INTEGER, OUT OUT1 INTEGER)
+ PARAMETER STYLE JAVA
+ LANGUAGE JAVA
+ EXTERNAL NAME
+'org.apache.camel.component.sql.stored.TestStoredProcedure.inoutdemo';
+
 CREATE FUNCTION SUBNUMBERS_FUNCTION(VALUE1 INTEGER, VALUE2 INTEGER)
  RETURNS INTEGER
  PARAMETER STYLE JAVA

-- 
To stop receiving notification emails like this one, please contact
davsclaus@apache.org.