001 package org.apache.ojb.broker.accesslayer;
002
003 /* Copyright 2002-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import java.sql.CallableStatement;
019 import java.sql.PreparedStatement;
020 import java.sql.ResultSet;
021 import java.sql.SQLException;
022 import java.sql.Statement;
023 import java.sql.Types;
024 import java.util.Collection;
025 import java.util.Enumeration;
026 import java.util.Iterator;
027
028 import org.apache.ojb.broker.Identity;
029 import org.apache.ojb.broker.PersistenceBroker;
030 import org.apache.ojb.broker.PersistenceBrokerException;
031 import org.apache.ojb.broker.PersistenceBrokerSQLException;
032 import org.apache.ojb.broker.core.ValueContainer;
033 import org.apache.ojb.broker.metadata.ArgumentDescriptor;
034 import org.apache.ojb.broker.metadata.ClassDescriptor;
035 import org.apache.ojb.broker.metadata.FieldDescriptor;
036 import org.apache.ojb.broker.metadata.ProcedureDescriptor;
037 import org.apache.ojb.broker.platforms.Platform;
038 import org.apache.ojb.broker.platforms.PlatformException;
039 import org.apache.ojb.broker.platforms.PlatformFactory;
040 import org.apache.ojb.broker.query.BetweenCriteria;
041 import org.apache.ojb.broker.query.Criteria;
042 import org.apache.ojb.broker.query.ExistsCriteria;
043 import org.apache.ojb.broker.query.FieldCriteria;
044 import org.apache.ojb.broker.query.InCriteria;
045 import org.apache.ojb.broker.query.NullCriteria;
046 import org.apache.ojb.broker.query.Query;
047 import org.apache.ojb.broker.query.SelectionCriteria;
048 import org.apache.ojb.broker.query.SqlCriteria;
049 import org.apache.ojb.broker.util.logging.Logger;
050 import org.apache.ojb.broker.util.logging.LoggerFactory;
051
052 /**
053 * manages JDBC Connection and Statement resources.
054 *
055 * @author Thomas Mahler
056 * @author <a href="mailto:rburt3@mchsi.com">Randall Burt</a>
057 * @version $Id: StatementManager.java,v 1.1 2007-08-24 22:17:30 ewestfal Exp $
058 */
059 public class StatementManager implements StatementManagerIF
060 {
061 private Logger m_log = LoggerFactory.getLogger(StatementManager.class);
062
063 /** the associated broker */
064 private final PersistenceBroker m_broker;
065 private Platform m_platform;
066 /**
067 * Used when OJB run in JBoss
068 * TODO: Find a better solution to handle OJB within JBoss
069 * --> the JCA implementation should solve this problem
070 *
071 * arminw:
072 * Seems with JBoss 3.2.2 or higher the problem is gone, so we
073 * can deprecate this attribute sooner or later
074 */
075 private boolean m_eagerRelease;
076 private ConnectionManagerIF m_conMan;
077
078 public StatementManager(final PersistenceBroker pBroker)
079 {
080 this.m_broker = pBroker;
081 this.m_conMan = m_broker.serviceConnectionManager();
082 m_eagerRelease = m_conMan.getConnectionDescriptor().getEagerRelease();
083 m_platform = PlatformFactory.getPlatformFor(m_conMan.getConnectionDescriptor());
084 }
085
086 public void closeResources(Statement stmt, ResultSet rs)
087 {
088 if (m_log.isDebugEnabled())
089 m_log.debug("closeResources was called");
090 try
091 {
092 m_platform.beforeStatementClose(stmt, rs);
093 //close statement on wrapped statement class, or real statement
094 if (stmt != null)
095 {
096 //log.info("## close: "+stmt);
097 stmt.close();
098
099 /*
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 }