Author: ppoddar
Date: Tue Apr 30 00:41:14 2013
New Revision: 1477430

URL: http://svn.apache.org/r1477430
Log:
support Stored Procedure

Added:
    
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
   (with props)
Removed:
    
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/StoredProcedure.java
Modified:
    
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java
    
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java
    
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/AbstractProcedureList.java
    
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java
    
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/ProcedureList.java

Modified: 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java
URL: 
http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java?rev=1477430&r1=1477429&r2=1477430&view=diff
==============================================================================
--- 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java
 (original)
+++ 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java
 Tue Apr 30 00:41:14 2013
@@ -30,6 +30,7 @@ import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.StringTokenizer;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.openjpa.jdbc.meta.ClassMapping;
@@ -39,7 +40,9 @@ import org.apache.openjpa.jdbc.sql.DBDic
 import org.apache.openjpa.jdbc.sql.ResultSetResult;
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
 import org.apache.openjpa.jdbc.sql.SQLExceptions;
+import org.apache.openjpa.jdbc.sql.StoredProcedure;
 import org.apache.openjpa.kernel.AbstractStoreQuery;
+import org.apache.openjpa.kernel.Query;
 import org.apache.openjpa.kernel.QueryContext;
 import org.apache.openjpa.kernel.StoreQuery;
 import org.apache.openjpa.lib.rop.RangeResultObjectProvider;
@@ -58,8 +61,7 @@ import org.apache.openjpa.util.UserExcep
 public class SQLStoreQuery
     extends AbstractStoreQuery {
 
-    private static final Localizer _loc = Localizer.forPackage
-        (SQLStoreQuery.class);
+    private static final Localizer _loc = 
Localizer.forPackage(SQLStoreQuery.class);
 
     private transient final JDBCStore _store;
 
@@ -102,8 +104,8 @@ public class SQLStoreQuery
         extends AbstractExecutor {
 
         private final ClassMetaData _meta;
-        private final boolean _select;
-        private final boolean _call;   // native call stored procedure
+        private boolean _select;
+        private boolean _call;   // native call stored procedure
         private final QueryResultMapping _resultMapping;
 
         public SQLExecutor(SQLStoreQuery q, ClassMetaData candidate) {
@@ -116,19 +118,42 @@ public class SQLStoreQuery
                 MappingRepository repos = q.getStore().getConfiguration().
                     getMappingRepositoryInstance();
                 _resultMapping = repos.getQueryResultMapping
-                    (ctx.getResultMappingScope(), resultMapping, envLoader,
-                        true);
+                    (ctx.getResultMappingScope(), resultMapping, envLoader, 
true);
             }
             _meta = candidate;
 
             String sql = StringUtils.trimToNull(ctx.getQueryString());
             if (sql == null)
                 throw new UserException(_loc.get("no-sql"));
-            _select = q.getStore().getDBDictionary().isSelect(sql);
-            _call = sql.length() > 4
-                && sql.substring(0, 4).equalsIgnoreCase("call");
+            DBDictionary dict = q.getStore().getDBDictionary();
+            _select = dict.isSelect(sql);
+            if (!_select) {
+               String verb = getSQLVerb(sql);
+               
+               _call = "call".equalsIgnoreCase(verb);
+               if (!_call && !("drop".equalsIgnoreCase(verb) || 
"create".equalsIgnoreCase(verb))) {
+                       
+                       Connection conn = q.getStore().getConnection();
+                       try {
+                               StoredProcedure sp = 
dict.getStoredProcedure(conn.getMetaData(), null, null, 
+                                               
q.getContext().getQueryString());
+                               q.setQuery(sp.getCallSQL()); 
+                               _call = sp != null;
+                               
((Query)q.getContext()).setQuery(sp.getCallSQL());
+                               System.err.println("Call [" + sp.getCallSQL() + 
"]");
+                       } catch (SQLException ex) {
+                               throw new RuntimeException(ex);
+                       } finally {
+                               try {
+                                       conn.close();
+                               } catch (SQLException ex) {
+                                       
+                               }
+                       }
+                }
+            }
         }
-
+        
         public int getOperation(StoreQuery q) {
            return _select ? OP_SELECT : 
                 (q.getContext().getCandidateType() != null
@@ -141,16 +166,15 @@ public class SQLStoreQuery
         public Number executeUpdate(StoreQuery q, Object[] params) {
             JDBCStore store = ((SQLStoreQuery) q).getStore();
             DBDictionary dict = store.getDBDictionary();
+            // we need to make sure we have an active store connection
+            store.getContext().beginStore();
+            Connection conn = store.getConnection();
             String sql = q.getContext().getQueryString();
-
+            
             List paramList = new ArrayList(Arrays.asList(params));
             SQLBuffer buf = new SQLBuffer(dict).append(sql);
             
-            // we need to make sure we have an active store connection
-            store.getContext().beginStore();
-            Connection conn = store.getConnection();
-            JDBCFetchConfiguration fetch = (JDBCFetchConfiguration)
-                q.getContext().getFetchConfiguration();
+            JDBCFetchConfiguration fetch = 
(JDBCFetchConfiguration)q.getContext().getFetchConfiguration();
 
             PreparedStatement stmnt = null;
             try {
@@ -162,7 +186,7 @@ public class SQLStoreQuery
                 buf.setParameters(paramList);
                 if (stmnt != null)
                     buf.setParameters(stmnt);
-
+                
                 dict.setTimeouts(stmnt, fetch, true);
                 
                 int count = executeUpdate(store, conn, stmnt, buf);  
@@ -252,6 +276,7 @@ public class SQLStoreQuery
             return q.getContext().getCandidateType() == null;
         }
         
+        
         /**
          * This method is to provide override for non-JDBC or JDBC-like 
          * implementation of preparing call statement.
@@ -344,16 +369,22 @@ public class SQLStoreQuery
             int idx = 0;
             for (Integer key : paramOrder) {
                 if (!userParams.containsKey(key)) 
-                    throw new UserException(_loc.get("uparam-missing", 
-                        key, sql, userParams));
+                    throw new UserException(_loc.get("uparam-missing", key, 
sql, userParams));
                 result[idx++] = userParams.get(key);
             }
             // modify original JPA-style SQL to proper SQL
             q.getContext().getQuery().setQuery(sql);
             return result;
         }
+        
+        String getSQLVerb(String s) {
+               if (s == null || s.trim().isEmpty()) 
+                       throw new RuntimeException("No SQL verb in [" + s + 
"]");
+               return new StringTokenizer(s).nextToken();
+        }
     }
-    
+    private static final char SINGLE_QUOTE = '\'';
+    private static final char QUESTION_MARK = '?';
     /**
      * Utility method to substitute '?num' for parameters in the given SQL
      * statement, and fill-in the order of the parameter tokens
@@ -362,25 +393,24 @@ public class SQLStoreQuery
             throws IOException {
             // if there's no "?" parameter marker, then we don't need to
             // perform the parsing process
-            if (sql.indexOf("?") == -1)
+            if (sql.indexOf(QUESTION_MARK) == -1)
                 return sql;
 
             paramOrder.clear();
             StreamTokenizer tok = new StreamTokenizer(new StringReader(sql));
             tok.resetSyntax();
-            tok.quoteChar('\'');
+            tok.quoteChar(SINGLE_QUOTE);
             tok.wordChars('0', '9');
-            tok.wordChars('?', '?');
+            tok.wordChars(QUESTION_MARK, QUESTION_MARK);
 
             StringBuilder buf = new StringBuilder(sql.length());
-            for (int ttype; (ttype = tok.nextToken()) !=
-                    StreamTokenizer.TT_EOF;) {
+            for (int ttype; (ttype = tok.nextToken()) != 
StreamTokenizer.TT_EOF;) {
                 switch (ttype) {
                     case StreamTokenizer.TT_WORD:
                         // a token is a positional parameter if it starts with
                         // a "?" and the rest of the token are all numbers
-                        if (tok.sval.startsWith("?")) {
-                            buf.append("?");
+                        if (tok.sval.startsWith(""+QUESTION_MARK)) {
+                            buf.append(QUESTION_MARK);
                             String pIndex = tok.sval.substring(1);
                             if (pIndex.length() > 0) {
                                 paramOrder.add(Integer.valueOf(pIndex));
@@ -390,11 +420,11 @@ public class SQLStoreQuery
                         } else
                             buf.append(tok.sval);
                         break;
-                    case'\'':
-                        buf.append('\'');
+                    case '\'':
+                        buf.append(SINGLE_QUOTE);
                         if (tok.sval != null) {
                             buf.append(tok.sval);
-                            buf.append('\'');
+                            buf.append(SINGLE_QUOTE);
                         }
                         break;
                     default:

Modified: 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java
URL: 
http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java?rev=1477430&r1=1477429&r2=1477430&view=diff
==============================================================================
--- 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java
 (original)
+++ 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java
 Tue Apr 30 00:41:14 2013
@@ -62,6 +62,9 @@ public class Column
     private DBIdentifier _typeName = DBIdentifier.NULL;
     private int _javaType = JavaTypes.OBJECT;
     private int _size = 0;
+    private int _precision = -1;
+    private int _scale     = -1;
+    private int _radix     = 10;
     private int _decimals = 0;
     private String _defaultStr = null;
     private Object _default = null;
@@ -376,6 +379,29 @@ public class Column
     public void setDecimalDigits(int digits) {
         _decimals = digits;
     }
+    
+    public int getPrecision() {
+       return _precision;
+    }
+    
+    public void setPrecision(int p) {
+       _precision = p;
+    }
+    
+    public int getScale() {
+       return _scale;
+    }
+    
+    public void setScale(int s) {
+       _scale = s;
+    }
+    public int getRadix() {
+       return _radix;
+    }
+    
+    public void setRadix(int r) {
+       _radix = r;
+    }
 
     /**
      * Return the default value set for the column, if any.
@@ -490,6 +516,22 @@ public class Column
     public boolean isNotNullExplicit() {
         return _notNull != null;
     }
+    
+    /**
+     * Sets nullability of this receiver by the given flag.
+     * @param flag one of the JDBC nullability flag namely
+     * <LI> {@link DatabaseMetaData#columnNullableUnknown} : not known if the 
column can be set to null value
+     * <LI> {@link DatabaseMetaData#columnNullable} : the column can be set to 
null value
+     * <LI> {@link DatabaseMetaData#columnNoNulls} : the column can not be set 
to null value
+     */
+    public void setNullability(short flag) {
+       switch (flag) {
+               case DatabaseMetaData.columnNullableUnknown : _notNull = null; 
break;
+               case DatabaseMetaData.columnNullable : _notNull = false; break;
+               case DatabaseMetaData.columnNoNulls : _notNull = true; break;
+               
+       }
+    }
 
     /**
      * Whether this column is auto-assigned a value on insert.
@@ -788,6 +830,12 @@ public class Column
             setSize(from.getSize());
         if (getDecimalDigits() == 0)
             setDecimalDigits(from.getDecimalDigits());
+        if (getScale() == 0) 
+               setScale(from.getScale());
+        if (getPrecision() == 0) 
+               setPrecision(from.getPrecision());
+        if (getRadix() == 10) 
+               setRadix(from.getRadix());
         if (getDefaultString() == null)
             setDefaultString(from.getDefaultString());
         if (!isNotNullExplicit() && from.isNotNullExplicit())

Modified: 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=1477430&r1=1477429&r2=1477430&view=diff
==============================================================================
--- 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
 (original)
+++ 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
 Tue Apr 30 00:41:14 2013
@@ -61,6 +61,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 
 import javax.sql.DataSource;
 
@@ -4657,6 +4658,54 @@ public class DBDictionary
     protected String getGeneratedKeySequenceName(Column col) {
         return toDBName(namingUtil.getGeneratedKeySequenceName(col, 
maxAutoAssignNameLength));
     }
+    
+    // Stored Procedures
+//    public void getStoredProcedures(DatabaseMetaData meta, DBIdentifier 
catalog, DBIdentifier schema)
+//     throws SQLException {
+//     ResultSet rs = meta.getProcedures(
+//                     getCatalogNameForMetadata(catalog), 
+//                     getSchemaNameForMetadata(schema), 
+//                     null);
+//     while (rs.next()) {
+//             String procName = rs.getString(3);
+//             ResultSet rs2 = meta.getProcedureColumns(
+//                             getCatalogNameForMetadata(catalog), 
+//                             getSchemaNameForMetadata(schema), 
+//                             procName, 
+//                             null);
+//             StoredProcedureMetaData sp = new StoredProcedureMetaData(rs2);
+//             
+//     }
+//    }
+    protected Map<String, StoredProcedure> _procs = new TreeMap<String, 
StoredProcedure>();
+    
+    /**
+     * Gets the metadata of the stored procedure by the given name either from 
the cached version or
+     * by enquiring the database.
+     * @param meta the database meta data
+     * @param catalog the catalog name or null
+     * @param schema the schema name or null
+     * @param procedure the procedure name
+     * @return metadata about the named procedure or null
+     * @throws SQLException when metadata query goes wrong
+     */
+    public StoredProcedure getStoredProcedure(DatabaseMetaData meta, 
DBIdentifier catalog, DBIdentifier schema, 
+               String procedure) throws SQLException {
+       if (_procs.containsKey(procedure)) {
+               return _procs.get(procedure);
+       }
+       ResultSet rs = meta.getProcedureColumns(
+                               getCatalogNameForMetadata(catalog), 
+                               getSchemaNameForMetadata(schema), 
+                               procedure, 
+                               null);
+       StoredProcedure sp = null;
+       if (rs.next()) {
+               sp = new StoredProcedure(rs);
+       }
+       _procs.put(procedure, sp);
+       return sp;
+    }
 
     ///////////////////////////////
     // Configurable implementation

Added: 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
URL: 
http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java?rev=1477430&view=auto
==============================================================================
--- 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
 (added)
+++ 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
 Tue Apr 30 00:41:14 2013
@@ -0,0 +1,315 @@
+/*
+ * 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.openjpa.jdbc.sql;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.openjpa.jdbc.identifier.DBIdentifier;
+import org.apache.openjpa.jdbc.identifier.DBIdentifier.DBIdentifierType;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.Schemas;
+/**
+ * Holds metadata about a Stored Procedure.
+ * <br>
+ * An instance of this class can be constructed either by reading from 
database meta data
+ * or by programatic assignment. If an instance if created programmatically, 
then
+ * its SQL body or parameters can be added.
+ * <br>
+ * This class can generate the SQL statement to create, drop or delete this 
procedure.
+ * 
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class StoredProcedure {
+       private DBIdentifier _catalog;
+       private DBIdentifier _schema;
+       private DBIdentifier _name;
+       private List<Column> _cols = new ArrayList<Column>();
+       private List<String> _params = new ArrayList<String>();
+       
+       
+       private List<String> _sql = new ArrayList<String>();
+       private final boolean _fromDatabase;
+       
+       private static enum Action {CREATE, DROP, CALL};
+
+       /**
+        * An enumeration on type of parameter for a Stored Procedure.
+        * The enumerted values has the same ordinal numbers as found
+        * in corresponding integer values in {@link DatabaseMetaData}.
+        */
+       public static enum PARAM {UNKNOW, IN, INOUT, RESULT, OUT, RETURN}
+       
+       public static enum SQL {NONE,MODIFY,READ, CONTAINS};
+       
+       /**
+        * Create a procedure of the given name.
+        */
+       public StoredProcedure(String name) {
+               _name = DBIdentifier.newProcedure(name);
+               _fromDatabase = false;
+       }
+       
+       /**
+        * <pre>
+        * 
+        *      1. PROCEDURE_CAT - String - the procedure catalog name 
+        *      2. PROCEDURE_SCHEM - String - the procedure schema name 
(possibly null) 
+        *      3. PROCEDURE_NAME - String - the procedure name 
+        *      4. COLUMN_NAME - String - the name of the column 
+        *      5. COLUMN_TYPE - short - the kind of column or parameter, as 
follows: 
+        *                      DatabaseMetaData.procedureColumnUnknown - type 
unknown 
+        *                      DatabaseMetaData.procedureColumnIn - an IN 
parameter 
+        *                      DatabaseMetaData.procedureColumnInOut - an 
INOUT parameter 
+        *                      DatabaseMetaData.procedureColumnOut - an OUT 
parameter 
+        *                      DatabaseMetaData.procedureColumnReturn - a 
return value 
+        *                      DatabaseMetaData.procedureReturnsResult - a 
result column in a result set 
+        *      6. DATA_TYPE - int - the SQL type of the data, as in 
java.sql.Types 
+        *      7. TYPE_NAME - String - the SQL type name, for a UDT it is 
fully qualified 
+        *      8. PRECISION - int - the precision 
+        *      9. LENGTH - int - the length of the data in bytes 
+        *      10.SCALE - short - the scale for numeric types 
+        *      11.RADIX - short - the Radix for numeric data (typically 2 or 
10) 
+        *      12.NULLABLE - short - can the data contain null: 
+        *                      DatabaseMetaData.procedureNoNulls - NULLs not 
permitted 
+        *                      DatabaseMetaData.procedureNullable - NULLs are 
permitted 
+        *                      DatabaseMetaData.procedureNullableUnknown - 
NULL status unknown 
+        *      13.REMARKS - String - an explanatory comment about the data item
+        * </pre>
+        **/
+
+       public StoredProcedure(ResultSet rs) throws SQLException {
+               _fromDatabase = true;
+               int i = 0;
+               do {
+                       if (i == 0) {
+                               // get stored procedure metadata
+                               _catalog = 
DBIdentifier.newCatalog(rs.getString(1));
+                               _schema = 
DBIdentifier.newSchema(rs.getString(2));
+                               _name = 
DBIdentifier.newIdentifier(rs.getString(3), DBIdentifierType.PROCEDURE, false);
+                       }
+                       Column col = new Column();
+                       _cols.add(col);
+                       
col.setIdentifier(DBIdentifier.newColumn(rs.getString(4)));
+                       col.setFlag(rs.getShort(5), true);
+                       col.setType(rs.getInt(6));
+                       
col.setTypeIdentifier(DBIdentifier.newConstant(rs.getString(7)));
+                       col.setPrecision(rs.getInt(8));
+                       col.setSize(rs.getInt(9));
+                       col.setScale(rs.getInt(10));
+                       col.setRadix(rs.getShort(11));
+                       col.setNullability(rs.getShort(12));
+                       col.setComment(rs.getString(13));
+                       _params.add(col.getIdentifier().getName() + " " + 
col.getTypeIdentifier().getName());
+                       i++;
+               } while (rs.next());
+       }
+       
+       public Column[] getInColumns() {
+               return getColumns((short)DatabaseMetaData.procedureColumnIn);
+       }
+       
+       public Column[] getInOutColumns() {
+               return getColumns((short)DatabaseMetaData.procedureColumnInOut);
+       }
+       
+       public Column[] getOutColumns() {
+               return getColumns((short)DatabaseMetaData.procedureColumnOut);
+       }
+       
+       /**
+        * Counts the number of columns with the given flag.
+        * @param flag
+        * @return
+        */
+       int countColumn(short flag) {
+               int count = 0;
+               for (Column col : _cols) {
+                       if (col.getFlag(flag)) count++;
+               }
+               return count;
+       }
+       
+       Column[] getColumns(short flag) {
+               List<Column> cols = null;
+               for (Column col : _cols) {
+                       if (col.getFlag(flag)) {
+                               if (cols == null) cols = new 
ArrayList<Column>();
+                               cols.add(col);
+                       }
+               }
+               return cols == null ? Schemas.EMPTY_COLUMNS : cols.toArray(new 
Column[cols.size()]);
+       }
+       
+       
+       /**
+        * Gets the name of this procedure.
+        */
+       public String getName() {
+               return _name.getName();
+       }
+       
+       /**
+        * Adds an {@code IN} parameter of the given name and type.
+        * @param var name of the variable
+        * @param typeName name of the SQL type e.g. {@code VARCAR(32)}
+        * @return this procedure instance
+        */
+       public StoredProcedure addParameter(String var, String typeName) {
+               return addParameter(PARAM.IN, var, typeName);
+       }
+       /**
+        * Adds the given parameter declaration.
+        * 
+        * @param param type of parameter. 
+        * @param var name of the variable
+        * @param typeName name of the SQL type e.g. {@code VARCAR(32)}
+        * @return this procedure instance
+        */
+       public StoredProcedure addParameter(PARAM param, String var, String 
typeName) {
+               assertMutable();
+               
+               _params.add(param + " " + var + " " + typeName);
+               return this;
+       }
+       
+       public StoredProcedure setLanguage(String language) {
+               _sql.add("LANGUAGE " + language);
+               return this;
+       }
+       
+       /**
+        * Gets the SQL for creating this procedure.
+        */
+       public String getCreateSQL() {
+               StringBuilder buf = new StringBuilder();
+               buf.append("CREATE PROCEDURE ");
+               buf.append(_name); 
+               buf.append(" (");
+               for (Iterator<String> p = _params.iterator(); p.hasNext();) {
+                               buf.append(p.next());
+                               buf.append(p.hasNext() ? "," : "");
+               }
+               buf.append(") ");
+               //buf.append("(");
+               for (String s : _sql) buf.append(s).append(" ");
+               //buf.append(")");
+               
+               return buf.toString().trim();
+       }
+       
+       /**
+        * Gets the SQL for dropping this procedure.
+        */
+       public String getDropSQL() {
+               return "DROP PROCEDURE " + _name;
+       }
+       
+       /**
+        * Gets the SQL for calling this procedure.
+        */
+       public String getCallSQL() {
+               StringBuilder buf = new StringBuilder();
+               buf.append("CALL ");
+               buf.append(_name); buf.append(" (");
+               for (Iterator<String> p = _params.iterator(); p.hasNext();) {
+                   p.next();
+                       buf.append("?");
+                       if (p.hasNext()) buf.append(",");
+               }
+               buf.append(")");
+               return buf.toString().trim();
+       }
+       
+       /**
+        * Adds a read SQL statement via an external method.
+        * @param i number of result sets to be read
+        * @param cls the owning classof the method
+        * @param method name of the static method
+        * @param paramTypes argument type of the method
+        * @return
+        */
+       public StoredProcedure setSQL(SQL sql) {
+               switch (sql) {
+               case CONTAINS : _sql.add("CONTAINS SQL"); break;
+               case NONE     : _sql.add("NO SQL"); break;
+               case MODIFY   : _sql.add("MODIFIES SQL DATA"); break;
+               case READ     : _sql.add("READS SQL DATA"); break;
+               }
+               return this;
+       }
+       
+       /**
+        * Sets the language whose parameter passing convention will be used to 
pass paramater values. 
+        * @param lang
+        * @return
+        */
+       public StoredProcedure setParameterStyle(String lang) {
+               _sql.add("PARAMETER STYLE " + lang);
+               return this;
+       }
+       
+       public StoredProcedure setExternalName(Class<?> cls, String method, 
Class<?>... paramTypes) {
+               assertStaticMethod(cls, method, paramTypes);
+               _sql.add("EXTERNAL NAME '" + cls.getName() + '.' + method + 
"'");
+               return this;
+       }
+       
+       public StoredProcedure setResult(int i) {
+               return setResult(i, false);
+       }
+       
+       public StoredProcedure setResult(int i, boolean dynamic) {
+               assertMutable();
+               _sql.add((dynamic ? "DYNAMIC " : "") + "RESULT SETS " + i);
+               return this;
+       }
+       
+       private void assertStaticMethod(Class<?> cls, String method, 
Class<?>...paramTypes) {
+               try {
+                       Method m = cls.getMethod(method, paramTypes);
+                       if (m == null || !Modifier.isStatic(m.getModifiers())) {
+                               throw new RuntimeException("No static method " 
+ method + " with arguments " 
+                                               + Arrays.toString(paramTypes) + 
" in " + cls);
+                       }
+               } catch (Exception ex) {
+                       throw new RuntimeException("No static method " + method 
+ " with arguments " 
+                                       + Arrays.toString(paramTypes) + " in " 
+ cls, ex);
+               }
+       }
+       
+       private void assertMutable() {
+               if (_fromDatabase) {
+                       throw new IllegalStateException(this + " is not 
mutable");
+               }
+       }
+       
+       public String toString() {
+               return getName();
+       }
+}

Propchange: 
openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/AbstractProcedureList.java
URL: 
http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/AbstractProcedureList.java?rev=1477430&r1=1477429&r2=1477430&view=diff
==============================================================================
--- 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/AbstractProcedureList.java
 (original)
+++ 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/AbstractProcedureList.java
 Tue Apr 30 00:41:14 2013
@@ -22,6 +22,8 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.openjpa.jdbc.sql.StoredProcedure;
+
 /*
  * holds the stored procedures that will be used by test cases
  */

Modified: 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java
URL: 
http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java?rev=1477430&r1=1477429&r2=1477430&view=diff
==============================================================================
--- 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java
 (original)
+++ 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java
 Tue Apr 30 00:41:14 2013
@@ -23,6 +23,8 @@ import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 
+import org.apache.openjpa.jdbc.sql.StoredProcedure;
+
 /*
  * holds the stored procedures that will be used by test cases
  */
@@ -30,33 +32,54 @@ public class DerbyProcedureList extends 
     
     public DerbyProcedureList() {
        put(new StoredProcedure("ADD_X_TO_CHARLIE")
-                       .styleSQL("JAVA")
-               .updateSQL(this.getClass(), "addXToCharlie", (Class<?>[])null));
+                       .setLanguage("JAVA")
+                       .setParameterStyle("JAVA")
+                       .setSQL(StoredProcedure.SQL.MODIFY)
+               .setExternalName(this.getClass(), "addXToCharlie", 
(Class<?>[])null));
+       
         put(new StoredProcedure("ADD_SUFFIX_TO_NAME")
-                .addParameter("NAME VARCHAR(128)")
-                .addParameter("SUFFIX VARCHAR(128)")
-                       .styleSQL("JAVA")
-                               .updateSQL(this.getClass(), "addSuffixToName", 
String.class, String.class));
+                .addParameter("NAME", "VARCHAR(128)")
+                .addParameter("SUFFIX", "VARCHAR(128)")
+                       .setLanguage("JAVA")
+                       .setParameterStyle("JAVA")
+                               .setExternalName(this.getClass(), 
"addSuffixToName", String.class, String.class));
+        
         put(new StoredProcedure("GET_ALL_APPLICANTS")
-                       .styleSQL("JAVA")
-                .readSQL(1, this.getClass(), "getAllApplicants", 
ResultSet[].class));
+                       .setLanguage("JAVA")
+                       .setParameterStyle("JAVA")
+                       .setSQL(StoredProcedure.SQL.READ)
+                       .setResult(1)
+                       .setExternalName(this.getClass(), "getAllApplicants", 
ResultSet[].class));
+        
         put(new StoredProcedure("GET_TWO_APPLICANTS")
-                       .addParameter("NAME VARCHAR(128)")
-                .addParameter("SUFFIX VARCHAR(128)")
-                       .styleSQL("JAVA")
-                .readSQL(1, this.getClass(), "getTwoApplicants", String.class, 
String.class, ResultSet[].class));
+                       .addParameter("NAME", "VARCHAR(128)")
+                .addParameter("SUFFIX", "VARCHAR(128)")
+                       .setLanguage("JAVA")
+                       .setParameterStyle("JAVA")
+                       .setResult(1)
+                .setExternalName(this.getClass(), "getTwoApplicants", 
String.class, String.class, ResultSet[].class));
+        
         put(new StoredProcedure("GET_ALL_APPLICANTS_AND_GAMES")
-                      .styleSQL("JAVA")
-               .readSQL(2, this.getClass(), "getAllApplicantsAndGames", 
ResultSet[].class, ResultSet[].class));
+                       .setLanguage("JAVA")
+                       .setParameterStyle("JAVA")
+                       .setResult(2)
+                .setExternalName(this.getClass(), "getAllApplicantsAndGames", 
ResultSet[].class, ResultSet[].class));
+        
         put(new StoredProcedure("GET_TWO_APPLICANTS_AND_GAMES")
-                       .addParameter("NAME VARCHAR(128)")
-                       .addParameter("SUFFIX VARCHAR(128)")
-                       .styleSQL("JAVA")
-                       .readSQL(2, this.getClass(), 
"getTwoApplicantsAndGames", String.class,String.class,
+                       .addParameter("NAME", "VARCHAR(128)")
+                       .addParameter("SUFFIX", "VARCHAR(128)")
+                       .setLanguage("JAVA")
+                       .setParameterStyle("JAVA")
+                       .setResult(2)
+                       .setExternalName(this.getClass(), 
"getTwoApplicantsAndGames", String.class,String.class,
                                        ResultSet[].class, ResultSet[].class));
     }
 
-
+    /**
+     * This stored procedure accepts no input parameter and produces no return 
result.
+     * It updates Applicant's whose name is 'Charlie' to 'CharlieX' 
+     * @throws Exception
+     */
     public static void addXToCharlie() throws Exception {
         Connection conn =  
DriverManager.getConnection("jdbc:default:connection");
         PreparedStatement ps1 = conn.prepareStatement("update APPLICANT set 
name = 'Charliex' " 
@@ -66,6 +89,12 @@ public class DerbyProcedureList extends 
         conn.close();
     }
 
+    /**
+     * This  stored procedure accepts one input parameter and produces no 
return result.
+     * It updates Applicant's whose name is <N> to <N>+<suffix> where both
+     * <N> and <suffix> are input parameters. 
+     * @throws Exception
+     */
     public static void addSuffixToName(String name, String suffix)
         throws Exception {
         Connection conn = 
DriverManager.getConnection("jdbc:default:connection");

Modified: 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/ProcedureList.java
URL: 
http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/ProcedureList.java?rev=1477430&r1=1477429&r2=1477430&view=diff
==============================================================================
--- 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/ProcedureList.java
 (original)
+++ 
openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/ProcedureList.java
 Tue Apr 30 00:41:14 2013
@@ -20,6 +20,8 @@ package org.apache.openjpa.persistence.j
 
 import java.util.Collection;
 
+import org.apache.openjpa.jdbc.sql.StoredProcedure;
+
 /**
  * Provides a collection of stored procedure definitions
  * to be tested.


Reply via email to