1 package org.apache.ojb.broker.accesslayer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
54
55
56
57
58
59 public class StatementManager implements StatementManagerIF
60 {
61 private Logger m_log = LoggerFactory.getLogger(StatementManager.class);
62
63
64 private final PersistenceBroker m_broker;
65 private Platform m_platform;
66
67
68
69
70
71
72
73
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
94 if (stmt != null)
95 {
96
97 stmt.close();
98
99
100
101
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
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
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
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
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
181
182
183
184
185
186
187
188
189 private int bindStatementValue(PreparedStatement stmt, int index, Object attributeOrQuery, Object value, ClassDescriptor cld)
190 throws SQLException
191 {
192 FieldDescriptor fld = null;
193
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
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
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;
236 }
237
238
239
240
241
242
243
244
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
253
254
255
256
257
258 private int bindStatement(PreparedStatement stmt, int index, NullCriteria crit)
259 {
260 return index;
261 }
262
263
264
265
266
267
268
269
270 private int bindStatement(PreparedStatement stmt, int index, FieldCriteria crit)
271 {
272 return index;
273 }
274
275
276
277
278
279
280
281
282 private int bindStatement(PreparedStatement stmt, int index, SqlCriteria crit)
283 {
284 return index;
285 }
286
287
288
289
290
291
292
293
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
304
305
306
307
308
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
331
332
333
334
335
336
337 private int bindStatement(PreparedStatement stmt, int index, ExistsCriteria crit, ClassDescriptor cld) throws SQLException
338 {
339 Query subQuery = (Query) crit.getValue();
340
341
342 if (subQuery.getCriteria() != null && !subQuery.getCriteria().isEmpty())
343 {
344 return bindStatement(stmt, subQuery.getCriteria(), cld.getRepository().getDescriptorFor(subQuery.getSearchClass()), index);
345
346
347 }
348 else
349 {
350 return index;
351 }
352 }
353
354
355
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
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
388 param = bindSelectionCriteria(stmt, param, c, cld);
389
390
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
403
404
405
406
407
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
431
432 public void bindInsert(PreparedStatement stmt, ClassDescriptor cld, Object obj) throws java.sql.SQLException
433 {
434 ValueContainer[] values;
435 cld.updateLockingValues(obj);
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
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
469 m_platform.registerOutResultSet((CallableStatement) stmt, 1);
470 j++;
471 }
472
473 values = getKeyValues(m_broker, cld, oid);
474 for (
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
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
500 valuesSnapshot = cld.getCurrentLockingValues(obj);
501 cld.updateLockingValues(obj);
502 values = getNonKeyValues(m_broker, cld, obj);
503
504
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
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
518
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
530
531
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
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
567
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
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
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
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
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
657
658
659 protected ValueContainer[] getAllValues(ClassDescriptor cld, Object obj) throws PersistenceBrokerException
660 {
661 return m_broker.serviceBrokerHelper().getAllRwValues(cld, obj);
662 }
663
664
665
666
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
675
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
684
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
693
694
695
696
697
698
699
700
701
702
703
704 private void bindProcedure(PreparedStatement stmt, ClassDescriptor cld, Object obj, ProcedureDescriptor proc)
705 throws SQLException
706 {
707 int valueSub = 0;
708
709
710
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
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
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
758
759
760
761
762
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 }