View Javadoc

1   package org.apache.ojb.broker.accesslayer;
2   
3   /* Copyright 2002-2005 The Apache Software Foundation
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  import java.sql.CallableStatement;
19  import java.sql.PreparedStatement;
20  import java.sql.ResultSet;
21  import java.sql.SQLException;
22  import java.sql.Statement;
23  import java.sql.Types;
24  import java.util.Collection;
25  import java.util.Enumeration;
26  import java.util.Iterator;
27  
28  import org.apache.ojb.broker.Identity;
29  import org.apache.ojb.broker.PersistenceBroker;
30  import org.apache.ojb.broker.PersistenceBrokerException;
31  import org.apache.ojb.broker.PersistenceBrokerSQLException;
32  import org.apache.ojb.broker.core.ValueContainer;
33  import org.apache.ojb.broker.metadata.ArgumentDescriptor;
34  import org.apache.ojb.broker.metadata.ClassDescriptor;
35  import org.apache.ojb.broker.metadata.FieldDescriptor;
36  import org.apache.ojb.broker.metadata.ProcedureDescriptor;
37  import org.apache.ojb.broker.platforms.Platform;
38  import org.apache.ojb.broker.platforms.PlatformException;
39  import org.apache.ojb.broker.platforms.PlatformFactory;
40  import org.apache.ojb.broker.query.BetweenCriteria;
41  import org.apache.ojb.broker.query.Criteria;
42  import org.apache.ojb.broker.query.ExistsCriteria;
43  import org.apache.ojb.broker.query.FieldCriteria;
44  import org.apache.ojb.broker.query.InCriteria;
45  import org.apache.ojb.broker.query.NullCriteria;
46  import org.apache.ojb.broker.query.Query;
47  import org.apache.ojb.broker.query.SelectionCriteria;
48  import org.apache.ojb.broker.query.SqlCriteria;
49  import org.apache.ojb.broker.util.logging.Logger;
50  import org.apache.ojb.broker.util.logging.LoggerFactory;
51  
52  /**
53   * manages JDBC Connection and Statement resources.
54   *
55   * @author Thomas Mahler
56   * @author <a href="mailto:rburt3@mchsi.com">Randall Burt</a>
57   * @version $Id: StatementManager.java,v 1.1 2007-08-24 22:17:30 ewestfal Exp $
58   */
59  public class StatementManager implements StatementManagerIF
60  {
61      private Logger m_log = LoggerFactory.getLogger(StatementManager.class);
62  
63      /** the associated broker */
64      private final PersistenceBroker m_broker;
65      private Platform m_platform;
66      /**
67       * Used when OJB run in JBoss
68       * TODO: Find a better solution to handle OJB within JBoss
69       * --> the JCA implementation should solve this problem
70       *
71       * arminw:
72       * Seems with JBoss 3.2.2 or higher the problem is gone, so we
73       * can deprecate this attribute sooner or later
74       */
75      private boolean m_eagerRelease;
76      private ConnectionManagerIF m_conMan;
77  
78      public StatementManager(final PersistenceBroker pBroker)
79      {
80          this.m_broker = pBroker;
81          this.m_conMan = m_broker.serviceConnectionManager();
82          m_eagerRelease = m_conMan.getConnectionDescriptor().getEagerRelease();
83          m_platform = PlatformFactory.getPlatformFor(m_conMan.getConnectionDescriptor());
84      }
85  
86      public void closeResources(Statement stmt, ResultSet rs)
87      {
88          if (m_log.isDebugEnabled())
89              m_log.debug("closeResources was called");
90          try
91          {
92              m_platform.beforeStatementClose(stmt, rs);
93              //close statement on wrapped statement class, or real statement
94              if (stmt != null)
95              {
96                  //log.info("## close: "+stmt);
97                  stmt.close();
98  
99                  /*
100                 *********************************************
101                 special stuff for OJB within JBoss
102                 ********************************************
103                 */
104                 if (m_eagerRelease)
105                 {
106                     m_conMan.releaseConnection();
107                 }
108 
109             }
110             m_platform.afterStatementClose(stmt, rs);
111         }
112         catch (PlatformException e)
113         {
114             m_log.error("Platform dependent operation failed", e);
115         }
116         catch (SQLException ignored)
117         {
118             if (m_log.isDebugEnabled())
119                 m_log.debug("Statement closing failed", ignored);
120         }
121     }
122 
123     /**
124      * binds the Identities Primary key values to the statement
125      */
126     public void bindDelete(PreparedStatement stmt, Identity oid, ClassDescriptor cld) throws SQLException
127     {
128         Object[] pkValues = oid.getPrimaryKeyValues();
129         FieldDescriptor[] pkFields = cld.getPkFields();
130         int i = 0;
131         try
132         {
133             for (; i < pkValues.length; i++)
134             {
135                 setObjectForStatement(stmt, i + 1, pkValues[i], pkFields[i].getJdbcType().getType());
136             }
137         }
138         catch (SQLException e)
139         {
140             m_log.error("bindDelete failed for: " + oid.toString() + ", while set value '" +
141                     pkValues[i] + "' for column " + pkFields[i].getColumnName());
142             throw e;
143         }
144     }
145 
146     /**
147      * binds the objects primary key and locking values to the statement, BRJ
148      */
149     public void bindDelete(PreparedStatement stmt, ClassDescriptor cld, Object obj) throws SQLException
150     {
151         if (cld.getDeleteProcedure() != null)
152         {
153             this.bindProcedure(stmt, cld, obj, cld.getDeleteProcedure());
154         }
155         else
156         {
157             int index = 1;
158             ValueContainer[] values, currentLockingValues;
159 
160             currentLockingValues = cld.getCurrentLockingValues(obj);
161             // parameters for WHERE-clause pk
162             values = getKeyValues(m_broker, cld, obj);
163             for (int i = 0; i < values.length; i++)
164             {
165                 setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
166                 index++;
167             }
168 
169             // parameters for WHERE-clause locking
170             values = currentLockingValues;
171             for (int i = 0; i < values.length; i++)
172             {
173                 setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
174                 index++;
175             }
176         }
177     }
178 
179     /**
180      * bind attribute and value
181      * @param stmt
182      * @param index
183      * @param attributeOrQuery
184      * @param value
185      * @param cld
186      * @return
187      * @throws SQLException
188      */
189     private int bindStatementValue(PreparedStatement stmt, int index, Object attributeOrQuery, Object value, ClassDescriptor cld)
190             throws SQLException
191     {
192         FieldDescriptor fld = null;
193         // if value is a subQuery bind it
194         if (value instanceof Query)
195         {
196             Query subQuery = (Query) value;
197             return bindStatement(stmt, subQuery, cld.getRepository().getDescriptorFor(subQuery.getSearchClass()), index);
198         }
199 
200         // if attribute is a subQuery bind it
201         if (attributeOrQuery instanceof Query)
202         {
203             Query subQuery = (Query) attributeOrQuery;
204             bindStatement(stmt, subQuery, cld.getRepository().getDescriptorFor(subQuery.getSearchClass()), index);
205         }
206         else
207         {
208             fld = cld.getFieldDescriptorForPath((String) attributeOrQuery);
209         }
210 
211         if (fld != null)
212         {
213             // BRJ: use field conversions and platform
214             if (value != null)
215             {
216                 m_platform.setObjectForStatement(stmt, index, fld.getFieldConversion().javaToSql(value), fld.getJdbcType().getType());
217             }
218             else
219             {
220                 m_platform.setNullForStatement(stmt, index, fld.getJdbcType().getType());
221             }
222         }
223         else
224         {
225             if (value != null)
226             {
227                 stmt.setObject(index, value);
228             }
229             else
230             {
231                 stmt.setNull(index, Types.NULL);
232             }
233         }
234 
235         return ++index; // increment before return
236     }
237 
238     /**
239      * bind SelectionCriteria
240      * @param stmt the PreparedStatement
241      * @param index the position of the parameter to bind
242      * @param crit the Criteria containing the parameter
243      * @param cld the ClassDescriptor
244      * @return next index for PreparedStatement
245      */
246     private int bindStatement(PreparedStatement stmt, int index, SelectionCriteria crit, ClassDescriptor cld) throws SQLException
247     {
248         return bindStatementValue(stmt, index, crit.getAttribute(), crit.getValue(), cld);
249     }
250 
251     /**
252      * bind NullCriteria
253      * @param stmt the PreparedStatement
254      * @param index the position of the parameter to bind
255      * @param crit the Criteria containing the parameter
256      * @return next index for PreparedStatement
257      */
258     private int bindStatement(PreparedStatement stmt, int index, NullCriteria crit)
259     {
260         return index;
261     }
262 
263     /**
264      * bind FieldCriteria
265      * @param stmt , the PreparedStatement
266      * @param index , the position of the parameter to bind
267      * @param crit , the Criteria containing the parameter
268      * @return next index for PreparedStatement
269      */
270     private int bindStatement(PreparedStatement stmt, int index, FieldCriteria crit)
271     {
272         return index;
273     }
274 
275     /**
276      * bind SqlCriteria
277      * @param stmt the PreparedStatement
278      * @param index the position of the parameter to bind
279      * @param crit the Criteria containing the parameter
280      * @return next index for PreparedStatement
281      */
282     private int bindStatement(PreparedStatement stmt, int index, SqlCriteria crit)
283     {
284         return index;
285     }
286 
287     /**
288      * bind BetweenCriteria
289      * @param stmt the PreparedStatement
290      * @param index the position of the parameter to bind
291      * @param crit the Criteria containing the parameter
292      * @param cld the ClassDescriptor
293      * @return next index for PreparedStatement
294      */
295     private int bindStatement(PreparedStatement stmt, int index, BetweenCriteria crit, ClassDescriptor cld) throws SQLException
296     {
297         index = bindStatementValue(stmt, index, crit.getAttribute(), crit.getValue(), cld);
298 
299         return bindStatementValue(stmt, index, crit.getAttribute(), crit.getValue2(), cld);
300     }
301 
302     /**
303      * bind InCriteria
304      * @param stmt the PreparedStatement
305      * @param index the position of the parameter to bind
306      * @param crit the Criteria containing the parameter
307      * @param cld the ClassDescriptor
308      * @return next index for PreparedStatement
309      */
310     private int bindStatement(PreparedStatement stmt, int index, InCriteria crit, ClassDescriptor cld) throws SQLException
311     {
312         if (crit.getValue() instanceof Collection)
313         {
314             Collection values = (Collection) crit.getValue();
315             Iterator iter = values.iterator();
316 
317             while (iter.hasNext())
318             {
319                 index = bindStatementValue(stmt, index, crit.getAttribute(), iter.next(), cld);
320             }
321         }
322         else
323         {
324             index = bindStatementValue(stmt, index, crit.getAttribute(), crit.getValue(), cld);
325         }
326         return index;
327     }
328 
329     /**
330      * bind ExistsCriteria
331      * @param stmt the PreparedStatement
332      * @param index the position of the parameter to bind
333      * @param crit the Criteria containing the parameter
334      * @param cld the ClassDescriptor
335      * @return next index for PreparedStatement
336      */
337     private int bindStatement(PreparedStatement stmt, int index, ExistsCriteria crit, ClassDescriptor cld) throws SQLException
338     {
339         Query subQuery = (Query) crit.getValue();
340 
341         // if query has criteria, bind them
342         if (subQuery.getCriteria() != null && !subQuery.getCriteria().isEmpty())
343         {
344             return bindStatement(stmt, subQuery.getCriteria(), cld.getRepository().getDescriptorFor(subQuery.getSearchClass()), index);
345 
346             // otherwise, just ignore it
347         }
348         else
349         {
350             return index;
351         }
352     }
353 
354     /**
355      * bind a Query based Select Statement
356      */
357     public int bindStatement(PreparedStatement stmt, Query query, ClassDescriptor cld, int param) throws SQLException
358     {
359         int result;
360 
361         result = bindStatement(stmt, query.getCriteria(), cld, param);
362         result = bindStatement(stmt, query.getHavingCriteria(), cld, result);
363 
364         return result;
365     }
366 
367     /**
368      * bind a Query based Select Statement
369      */
370     protected int bindStatement(PreparedStatement stmt, Criteria crit, ClassDescriptor cld, int param) throws SQLException
371     {
372         if (crit != null)
373         {
374             Enumeration e = crit.getElements();
375 
376             while (e.hasMoreElements())
377             {
378                 Object o = e.nextElement();
379                 if (o instanceof Criteria)
380                 {
381                     Criteria pc = (Criteria) o;
382                     param = bindStatement(stmt, pc, cld, param);
383                 }
384                 else
385                 {
386                     SelectionCriteria c = (SelectionCriteria) o;
387                     // BRJ : bind once for the criterion's main class
388                     param = bindSelectionCriteria(stmt, param, c, cld);
389 
390                     // BRJ : and once for each extent
391                     for (int i = 0; i < c.getNumberOfExtentsToBind(); i++)
392                     {
393                         param = bindSelectionCriteria(stmt, param, c, cld);
394                     }
395                 }
396             }
397         }
398         return param;
399     }
400 
401     /**
402      * bind SelectionCriteria
403      * @param stmt the PreparedStatement
404      * @param index the position of the parameter to bind
405      * @param crit the Criteria containing the parameter
406      * @param cld the ClassDescriptor
407      * @return next index for PreparedStatement
408      */
409     private int bindSelectionCriteria(PreparedStatement stmt, int index, SelectionCriteria crit, ClassDescriptor cld) throws SQLException
410     {
411         if (crit instanceof NullCriteria)
412             index = bindStatement(stmt, index, (NullCriteria) crit);
413         else if (crit instanceof BetweenCriteria)
414             index = bindStatement(stmt, index, (BetweenCriteria) crit, cld);
415         else if (crit instanceof InCriteria)
416             index = bindStatement(stmt, index, (InCriteria) crit, cld);
417         else if (crit instanceof SqlCriteria)
418             index = bindStatement(stmt, index, (SqlCriteria) crit);
419         else if (crit instanceof FieldCriteria)
420             index = bindStatement(stmt, index, (FieldCriteria) crit);
421         else if (crit instanceof ExistsCriteria)
422             index = bindStatement(stmt, index, (ExistsCriteria) crit, cld);
423         else
424             index = bindStatement(stmt, index, crit, cld);
425 
426         return index;
427     }
428 
429     /**
430      * binds the values of the object obj to the statements parameters
431      */
432     public void bindInsert(PreparedStatement stmt, ClassDescriptor cld, Object obj) throws java.sql.SQLException
433     {
434         ValueContainer[] values;
435         cld.updateLockingValues(obj); // BRJ : provide useful defaults for locking fields
436 
437         if (cld.getInsertProcedure() != null)
438         {
439             this.bindProcedure(stmt, cld, obj, cld.getInsertProcedure());
440         }
441         else
442         {
443             values = getAllValues(cld, obj);
444             for (int i = 0; i < values.length; i++)
445             {
446                 setObjectForStatement(stmt, i + 1, values[i].getValue(), values[i].getJdbcType().getType());
447             }
448         }
449     }
450 
451     /**
452      * Binds the Identities Primary key values to the statement.
453      */
454     public void bindSelect(PreparedStatement stmt, Identity oid, ClassDescriptor cld, boolean callableStmt) throws SQLException
455     {
456         ValueContainer[] values = null;
457         int i = 0;
458         int j = 0;
459 
460         if (cld == null)
461         {
462             cld = m_broker.getClassDescriptor(oid.getObjectsRealClass());
463         }
464         try
465         {
466             if(callableStmt)
467             {
468                 // First argument is the result set
469                 m_platform.registerOutResultSet((CallableStatement) stmt, 1);
470                 j++;
471             }
472 
473             values = getKeyValues(m_broker, cld, oid);
474             for (/*void*/; i < values.length; i++, j++)
475             {
476                 setObjectForStatement(stmt, j + 1, values[i].getValue(), values[i].getJdbcType().getType());
477             }
478         }
479         catch (SQLException e)
480         {
481             m_log.error("bindSelect failed for: " + oid.toString() + ", PK: " + i + ", value: " + values[i]);
482             throw e;
483         }
484     }
485 
486     /**
487      * binds the values of the object obj to the statements parameters
488      */
489     public void bindUpdate(PreparedStatement stmt, ClassDescriptor cld, Object obj) throws java.sql.SQLException
490     {
491         if (cld.getUpdateProcedure() != null)
492         {
493             this.bindProcedure(stmt, cld, obj, cld.getUpdateProcedure());
494         }
495         else
496         {
497             int index = 1;
498             ValueContainer[] values, valuesSnapshot;
499             // first take a snapshot of current locking values
500             valuesSnapshot = cld.getCurrentLockingValues(obj);
501             cld.updateLockingValues(obj); // BRJ
502             values = getNonKeyValues(m_broker, cld, obj);
503 
504             // parameters for SET-clause
505             for (int i = 0; i < values.length; i++)
506             {
507                 setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
508                 index++;
509             }
510             // parameters for WHERE-clause pk
511             values = getKeyValues(m_broker, cld, obj);
512             for (int i = 0; i < values.length; i++)
513             {
514                 setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
515                 index++;
516             }
517             // parameters for WHERE-clause locking
518             // take old locking values
519             values = valuesSnapshot;
520             for (int i = 0; i < values.length; i++)
521             {
522                 setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
523                 index++;
524             }
525         }
526     }
527 
528     /**
529      * binds the given array of values (if not null) starting from the given
530      * parameter index
531      * @return the next parameter index
532      */
533     public int bindValues(PreparedStatement stmt, ValueContainer[] values, int index) throws SQLException
534     {
535         if (values != null)
536         {
537             for (int i = 0; i < values.length; i++)
538             {
539                 setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
540                 index++;
541             }
542         }
543         return index;
544     }
545 
546     /**
547      * return a prepared DELETE Statement fitting for the given ClassDescriptor
548      */
549     public PreparedStatement getDeleteStatement(ClassDescriptor cld) throws PersistenceBrokerSQLException, PersistenceBrokerException
550     {
551         try
552         {
553             return cld.getStatementsForClass(m_conMan).getDeleteStmt(m_conMan.getConnection());
554         }
555         catch (SQLException e)
556         {
557             throw new PersistenceBrokerSQLException("Could not build statement ask for", e);
558         }
559         catch (LookupException e)
560         {
561             throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
562         }
563     }
564 
565     /**
566      * return a generic Statement for the given ClassDescriptor.
567      * Never use this method for UPDATE/INSERT/DELETE if you want to use the batch mode.
568      */
569     public Statement getGenericStatement(ClassDescriptor cds, boolean scrollable) throws PersistenceBrokerException
570     {
571         try
572         {
573             return cds.getStatementsForClass(m_conMan).getGenericStmt(m_conMan.getConnection(), scrollable);
574         }
575         catch (LookupException e)
576         {
577             throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
578         }
579     }
580 
581     /**
582      * return a prepared Insert Statement fitting for the given ClassDescriptor
583      */
584     public PreparedStatement getInsertStatement(ClassDescriptor cds) throws PersistenceBrokerSQLException, PersistenceBrokerException
585     {
586         try
587         {
588             return cds.getStatementsForClass(m_conMan).getInsertStmt(m_conMan.getConnection());
589         }
590         catch (SQLException e)
591         {
592             throw new PersistenceBrokerSQLException("Could not build statement ask for", e);
593         }
594         catch (LookupException e)
595         {
596             throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
597         }
598     }
599 
600     /**
601      * return a generic Statement for the given ClassDescriptor
602      */
603     public PreparedStatement getPreparedStatement(ClassDescriptor cds, String sql,
604                                                   boolean scrollable, int explicitFetchSizeHint, boolean callableStmt)
605             throws PersistenceBrokerException
606     {
607         try
608         {
609             return cds.getStatementsForClass(m_conMan).getPreparedStmt(m_conMan.getConnection(), sql, scrollable, explicitFetchSizeHint, callableStmt);
610         }
611         catch (LookupException e)
612         {
613             throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
614         }
615     }
616 
617     /**
618      * return a prepared Select Statement for the given ClassDescriptor
619      */
620     public PreparedStatement getSelectByPKStatement(ClassDescriptor cds) throws PersistenceBrokerSQLException, PersistenceBrokerException
621     {
622         try
623         {
624             return cds.getStatementsForClass(m_conMan).getSelectByPKStmt(m_conMan.getConnection());
625         }
626         catch (SQLException e)
627         {
628             throw new PersistenceBrokerSQLException("Could not build statement ask for", e);
629         }
630         catch (LookupException e)
631         {
632             throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
633         }
634     }
635 
636     /**
637      * return a prepared Update Statement fitting to the given ClassDescriptor
638      */
639     public PreparedStatement getUpdateStatement(ClassDescriptor cds) throws PersistenceBrokerSQLException, PersistenceBrokerException
640     {
641         try
642         {
643             return cds.getStatementsForClass(m_conMan).getUpdateStmt(m_conMan.getConnection());
644         }
645         catch (SQLException e)
646         {
647             throw new PersistenceBrokerSQLException("Could not build statement ask for", e);
648         }
649         catch (LookupException e)
650         {
651             throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
652         }
653     }
654 
655     /**
656      * returns an array containing values for all the Objects attribute
657      * @throws PersistenceBrokerException if there is an erros accessing obj field values
658      */
659     protected ValueContainer[] getAllValues(ClassDescriptor cld, Object obj) throws PersistenceBrokerException
660     {
661         return m_broker.serviceBrokerHelper().getAllRwValues(cld, obj);
662     }
663 
664     /**
665      * returns an Array with an Objects PK VALUES
666      * @throws PersistenceBrokerException if there is an erros accessing o field values
667      */
668     protected ValueContainer[] getKeyValues(PersistenceBroker broker, ClassDescriptor cld, Object obj) throws PersistenceBrokerException
669     {
670         return broker.serviceBrokerHelper().getKeyValues(cld, obj);
671     }
672 
673     /**
674      * returns an Array with an Identities PK VALUES
675      * @throws PersistenceBrokerException if there is an erros accessing o field values
676      */
677     protected ValueContainer[] getKeyValues(PersistenceBroker broker, ClassDescriptor cld, Identity oid) throws PersistenceBrokerException
678     {
679         return broker.serviceBrokerHelper().getKeyValues(cld, oid);
680     }
681 
682     /**
683      * returns an Array with an Objects NON-PK VALUES
684      * @throws PersistenceBrokerException if there is an erros accessing o field values
685      */
686     protected ValueContainer[] getNonKeyValues(PersistenceBroker broker, ClassDescriptor cld, Object obj) throws PersistenceBrokerException
687     {
688         return broker.serviceBrokerHelper().getNonKeyRwValues(cld, obj);
689     }
690 
691     /**
692      * Bind a prepared statment that represents a call to a procedure or
693      * user-defined function.
694      *
695      * @param stmt the statement to bind.
696      * @param cld the class descriptor of the object that triggered the
697      *        invocation of the procedure or user-defined function.
698      * @param obj the object that triggered the invocation of the procedure
699      *        or user-defined function.
700      * @param proc the procedure descriptor that provides information about
701      *        the arguments that shoudl be passed to the procedure or
702      *        user-defined function
703      */
704     private void bindProcedure(PreparedStatement stmt, ClassDescriptor cld, Object obj, ProcedureDescriptor proc)
705             throws SQLException
706     {
707         int valueSub = 0;
708 
709         // Figure out if we are using a callable statement.  If we are, then we
710         // will need to register one or more output parameters.
711         CallableStatement callable = null;
712         try
713         {
714             callable = (CallableStatement) stmt;
715         }
716         catch(Exception e)
717         {
718             m_log.error("Error while bind values for class '" + (cld != null ? cld.getClassNameOfObject() : null)
719                     + "', using stored procedure: "+ proc, e);
720             if(e instanceof SQLException)
721             {
722                 throw (SQLException) e;
723             }
724             else
725             {
726                 throw new PersistenceBrokerException("Unexpected error while bind values for class '"
727                         + (cld != null ? cld.getClassNameOfObject() : null) + "', using stored procedure: "+ proc);
728             }
729         }
730 
731         // If we have a return value, then register it.
732         if ((proc.hasReturnValue()) && (callable != null))
733         {
734             int jdbcType = proc.getReturnValueFieldRef().getJdbcType().getType();
735             m_platform.setNullForStatement(stmt, valueSub + 1, jdbcType);
736             callable.registerOutParameter(valueSub + 1, jdbcType);
737             valueSub++;
738         }
739 
740         // Process all of the arguments.
741         Iterator iterator = proc.getArguments().iterator();
742         while (iterator.hasNext())
743         {
744             ArgumentDescriptor arg = (ArgumentDescriptor) iterator.next();
745             Object val = arg.getValue(obj);
746             int jdbcType = arg.getJdbcType();
747             setObjectForStatement(stmt, valueSub + 1, val, jdbcType);
748             if ((arg.getIsReturnedByProcedure()) && (callable != null))
749             {
750                 callable.registerOutParameter(valueSub + 1, jdbcType);
751             }
752             valueSub++;
753         }
754     }
755 
756     /**
757      * Sets object for statement at specific index, adhering to platform- and null-rules.
758      * @param stmt the statement
759      * @param index the current parameter index
760      * @param value the value to set
761      * @param sqlType the JDBC SQL-type of the value
762      * @throws SQLException on platform error
763      */
764     private void setObjectForStatement(PreparedStatement stmt, int index, Object value, int sqlType)
765             throws SQLException
766     {
767         if (value == null)
768         {
769             m_platform.setNullForStatement(stmt, index, sqlType);
770         }
771         else
772         {
773             m_platform.setObjectForStatement(stmt, index, value, sqlType);
774         }
775     }
776 
777 }