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.util.HashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25
26 import org.apache.ojb.broker.Identity;
27 import org.apache.ojb.broker.OptimisticLockException;
28 import org.apache.ojb.broker.PersistenceBroker;
29 import org.apache.ojb.broker.PersistenceBrokerException;
30 import org.apache.ojb.broker.PersistenceBrokerSQLException;
31 import org.apache.ojb.broker.accesslayer.sql.SelectStatement;
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.JdbcType;
37 import org.apache.ojb.broker.metadata.ProcedureDescriptor;
38 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
39 import org.apache.ojb.broker.platforms.Platform;
40 import org.apache.ojb.broker.query.Query;
41 import org.apache.ojb.broker.util.ExceptionHelper;
42 import org.apache.ojb.broker.util.logging.Logger;
43 import org.apache.ojb.broker.util.logging.LoggerFactory;
44 import org.apache.ojb.broker.util.sequence.SequenceManagerException;
45
46
47
48
49
50
51
52
53
54 public class JdbcAccessImpl implements JdbcAccess
55 {
56
57
58
59 protected Logger logger;
60
61
62
63
64 protected PersistenceBroker broker;
65
66
67
68
69
70 public JdbcAccessImpl(PersistenceBroker broker)
71 {
72 this.broker = broker;
73 logger = LoggerFactory.getLogger(this.getClass());
74 }
75
76
77
78
79
80
81 private Platform getPlatform()
82 {
83 return this.broker.serviceConnectionManager().getSupportedPlatform();
84 }
85
86
87
88
89
90
91 public void executeDelete(ClassDescriptor cld, Object obj) throws PersistenceBrokerException
92 {
93 if (logger.isDebugEnabled())
94 {
95 logger.debug("executeDelete: " + obj);
96 }
97
98 final StatementManagerIF sm = broker.serviceStatementManager();
99 PreparedStatement stmt = null;
100 try
101 {
102 stmt = sm.getDeleteStatement(cld);
103 if (stmt == null)
104 {
105 logger.error("getDeleteStatement returned a null statement");
106 throw new PersistenceBrokerException("JdbcAccessImpl: getDeleteStatement returned a null statement");
107 }
108
109 sm.bindDelete(stmt, cld, obj);
110 if (logger.isDebugEnabled())
111 logger.debug("executeDelete: " + stmt);
112
113
114
115
116
117 if (stmt.executeUpdate() == 0 && cld.isLocking())
118 {
119
120
121
122 String objToString = "";
123 try {
124 objToString = obj.toString();
125 } catch (Exception ex) {}
126 throw new OptimisticLockException("Object has been modified or deleted by someone else: " + objToString, obj);
127
128
129
130 }
131
132
133 harvestReturnValues(cld.getDeleteProcedure(), obj, stmt);
134 }
135 catch (OptimisticLockException e)
136 {
137
138 if (logger.isDebugEnabled())
139 logger.debug("OptimisticLockException during the execution of delete: "
140 + e.getMessage(), e);
141 throw e;
142 }
143 catch (PersistenceBrokerException e)
144 {
145 logger.error("PersistenceBrokerException during the execution of delete: "
146 + e.getMessage(), e);
147 throw e;
148 }
149 catch (SQLException e)
150 {
151 final String sql = broker.serviceSqlGenerator().getPreparedDeleteStatement(cld).getStatement();
152 throw ExceptionHelper.generateException(e, sql, cld, logger, obj);
153 }
154 finally
155 {
156 sm.closeResources(stmt, null);
157 }
158 }
159
160
161
162
163
164
165 public void executeDelete(Query query, ClassDescriptor cld) throws PersistenceBrokerException
166 {
167 if (logger.isDebugEnabled())
168 {
169 logger.debug("executeDelete (by Query): " + query);
170 }
171 final StatementManagerIF sm = broker.serviceStatementManager();
172 PreparedStatement stmt = null;
173 final String sql = this.broker.serviceSqlGenerator().getPreparedDeleteStatement(query, cld).getStatement();
174 try
175 {
176 stmt = sm.getPreparedStatement(cld, sql,
177 false, StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE, cld.getDeleteProcedure()!=null);
178
179 sm.bindStatement(stmt, query, cld, 1);
180 if (logger.isDebugEnabled())
181 logger.debug("executeDelete (by Query): " + stmt);
182
183 stmt.executeUpdate();
184 }
185 catch (SQLException e)
186 {
187 throw ExceptionHelper.generateException(e, sql, cld, null, logger);
188 }
189 finally
190 {
191 sm.closeResources(stmt, null);
192 }
193 }
194
195
196
197
198
199
200 public void executeInsert(ClassDescriptor cld, Object obj) throws PersistenceBrokerException
201 {
202 if (logger.isDebugEnabled())
203 {
204 logger.debug("executeInsert: " + obj);
205 }
206 final StatementManagerIF sm = broker.serviceStatementManager();
207 PreparedStatement stmt = null;
208 try
209 {
210 stmt = sm.getInsertStatement(cld);
211 if (stmt == null)
212 {
213 logger.error("getInsertStatement returned a null statement");
214 throw new PersistenceBrokerException("getInsertStatement returned a null statement");
215 }
216
217 assignAutoincrementSequences(cld, obj);
218 sm.bindInsert(stmt, cld, obj);
219 if (logger.isDebugEnabled())
220 logger.debug("executeInsert: " + stmt);
221 stmt.executeUpdate();
222
223 assignAutoincrementIdentityColumns(cld, obj);
224
225
226 harvestReturnValues(cld.getInsertProcedure(), obj, stmt);
227 }
228 catch (PersistenceBrokerException e)
229 {
230 logger.error("PersistenceBrokerException during the execution of the insert: " + e.getMessage(), e);
231 throw e;
232 }
233 catch(SequenceManagerException e)
234 {
235 throw new PersistenceBrokerException("Error while try to assign identity value", e);
236 }
237 catch (SQLException e)
238 {
239 final String sql = broker.serviceSqlGenerator().getPreparedInsertStatement(cld).getStatement();
240 throw ExceptionHelper.generateException(e, sql, cld, logger, obj);
241 }
242 finally
243 {
244 sm.closeResources(stmt, null);
245 }
246 }
247
248
249
250
251
252
253 public ResultSetAndStatement executeQuery(Query query, ClassDescriptor cld) throws PersistenceBrokerException
254 {
255 if (logger.isDebugEnabled())
256 {
257 logger.debug("executeQuery: " + query);
258 }
259
260
261
262
263 boolean scrollable = ((query.getStartAtIndex() > Query.NO_START_AT_INDEX) || (query.getEndAtIndex() > Query.NO_END_AT_INDEX));
264
265
266
267 if (query != null && query.getPrefetchedRelationships() != null && !query.getPrefetchedRelationships().isEmpty())
268 {
269 scrollable = true;
270 }
271 final StatementManagerIF sm = broker.serviceStatementManager();
272 final SelectStatement sql = broker.serviceSqlGenerator().getPreparedSelectStatement(query, cld);
273 PreparedStatement stmt = null;
274 ResultSet rs = null;
275 try
276 {
277 final int queryFetchSize = query.getFetchSize();
278 final boolean isStoredProcedure = isStoredProcedure(sql.getStatement());
279 stmt = sm.getPreparedStatement(cld, sql.getStatement() ,
280 scrollable, queryFetchSize, isStoredProcedure);
281 if (isStoredProcedure)
282 {
283
284
285 getPlatform().registerOutResultSet((CallableStatement) stmt, 1);
286 sm.bindStatement(stmt, query, cld, 2);
287
288 if (logger.isDebugEnabled())
289 logger.debug("executeQuery: " + stmt);
290
291 stmt.execute();
292 rs = (ResultSet) ((CallableStatement) stmt).getObject(1);
293 }
294 else
295 {
296 sm.bindStatement(stmt, query, cld, 1);
297
298 if (logger.isDebugEnabled())
299 logger.debug("executeQuery: " + stmt);
300
301 rs = stmt.executeQuery();
302 }
303
304 return new ResultSetAndStatement(sm, stmt, rs, sql);
305 }
306 catch (PersistenceBrokerException e)
307 {
308
309 sm.closeResources(stmt, rs);
310 logger.error("PersistenceBrokerException during the execution of the query: " + e.getMessage(), e);
311 throw e;
312 }
313 catch (SQLException e)
314 {
315
316 sm.closeResources(stmt, rs);
317 throw ExceptionHelper.generateException(e, sql.getStatement(), null, logger, null);
318 }
319 }
320
321 public ResultSetAndStatement executeSQL(
322 String sqlStatement,
323 ClassDescriptor cld,
324 boolean scrollable)
325 throws PersistenceBrokerException
326 {
327 return executeSQL(sqlStatement, cld, null, scrollable);
328 }
329
330
331
332
333
334
335 public ResultSetAndStatement executeSQL(
336 final String sql,
337 ClassDescriptor cld,
338 ValueContainer[] values,
339 boolean scrollable)
340 throws PersistenceBrokerException
341 {
342 if (logger.isDebugEnabled()) logger.debug("executeSQL: " + sql);
343 final boolean isStoredprocedure = isStoredProcedure(sql);
344 final StatementManagerIF sm = broker.serviceStatementManager();
345 PreparedStatement stmt = null;
346 ResultSet rs = null;
347 try
348 {
349 stmt = sm.getPreparedStatement(cld, sql,
350 scrollable, StatementManagerIF.FETCH_SIZE_NOT_EXPLICITLY_SET, isStoredprocedure);
351 if (isStoredprocedure)
352 {
353
354
355 getPlatform().registerOutResultSet((CallableStatement) stmt, 1);
356 sm.bindValues(stmt, values, 2);
357 stmt.execute();
358 rs = (ResultSet) ((CallableStatement) stmt).getObject(1);
359 }
360 else
361 {
362 sm.bindValues(stmt, values, 1);
363 rs = stmt.executeQuery();
364 }
365
366
367
368 return new ResultSetAndStatement(sm, stmt, rs, new SelectStatement()
369 {
370 public Query getQueryInstance()
371 {
372 return null;
373 }
374
375 public int getColumnIndex(FieldDescriptor fld)
376 {
377 return JdbcType.MIN_INT;
378 }
379
380 public String getStatement()
381 {
382 return sql;
383 }
384 });
385 }
386 catch (PersistenceBrokerException e)
387 {
388
389 sm.closeResources(stmt, rs);
390 logger.error("PersistenceBrokerException during the execution of the SQL query: " + e.getMessage(), e);
391 throw e;
392 }
393 catch (SQLException e)
394 {
395
396 sm.closeResources(stmt, rs);
397 throw ExceptionHelper.generateException(e, sql, cld, values, logger, null);
398 }
399 }
400
401 public int executeUpdateSQL(String sqlStatement, ClassDescriptor cld)
402 throws PersistenceBrokerException
403 {
404 return executeUpdateSQL(sqlStatement, cld, null, null);
405 }
406
407
408
409
410
411
412
413 public int executeUpdateSQL(
414 String sqlStatement,
415 ClassDescriptor cld,
416 ValueContainer[] values1,
417 ValueContainer[] values2)
418 throws PersistenceBrokerException
419 {
420 if (logger.isDebugEnabled())
421 logger.debug("executeUpdateSQL: " + sqlStatement);
422
423 int result;
424 int index;
425 PreparedStatement stmt = null;
426 final StatementManagerIF sm = broker.serviceStatementManager();
427 try
428 {
429 stmt = sm.getPreparedStatement(cld, sqlStatement,
430 Query.NOT_SCROLLABLE, StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE, isStoredProcedure(sqlStatement));
431 index = sm.bindValues(stmt, values1, 1);
432 sm.bindValues(stmt, values2, index);
433 result = stmt.executeUpdate();
434 }
435 catch (PersistenceBrokerException e)
436 {
437 logger.error("PersistenceBrokerException during the execution of the Update SQL query: " + e.getMessage(), e);
438 throw e;
439 }
440 catch (SQLException e)
441 {
442 ValueContainer[] tmp = addValues(values1, values2);
443 throw ExceptionHelper.generateException(e, sqlStatement, cld, tmp, logger, null);
444 }
445 finally
446 {
447 sm.closeResources(stmt, null);
448 }
449 return result;
450 }
451
452
453 private ValueContainer[] addValues(ValueContainer[] target, ValueContainer[] source)
454 {
455 ValueContainer[] newArray;
456 if(source != null && source.length > 0)
457 {
458 if(target != null)
459 {
460 newArray = new ValueContainer[target.length + source.length];
461 System.arraycopy(target, 0, newArray, 0, target.length);
462 System.arraycopy(source, 0, newArray, target.length, source.length);
463 }
464 else
465 {
466 newArray = source;
467 }
468 }
469 else
470 {
471 newArray = target;
472 }
473 return newArray;
474 }
475
476
477
478
479
480
481 public void executeUpdate(ClassDescriptor cld, Object obj) throws PersistenceBrokerException
482 {
483 if (logger.isDebugEnabled())
484 {
485 logger.debug("executeUpdate: " + obj);
486 }
487
488
489 if (cld.getNonPkRwFields().length == 0)
490 {
491 return;
492 }
493
494 final StatementManagerIF sm = broker.serviceStatementManager();
495 PreparedStatement stmt = null;
496
497
498 ValueContainer[] oldLockingValues;
499 oldLockingValues = cld.getCurrentLockingValues(obj);
500 try
501 {
502 stmt = sm.getUpdateStatement(cld);
503 if (stmt == null)
504 {
505 logger.error("getUpdateStatement returned a null statement");
506 throw new PersistenceBrokerException("getUpdateStatement returned a null statement");
507 }
508
509 sm.bindUpdate(stmt, cld, obj);
510 if (logger.isDebugEnabled())
511 logger.debug("executeUpdate: " + stmt);
512
513 if ((stmt.executeUpdate() == 0) && cld.isLocking())
514 {
515
516
517
518 String objToString = "";
519 try {
520 objToString = obj.toString();
521 } catch (Exception ex) {}
522 throw new OptimisticLockException("Object has been modified by someone else: " + objToString, obj);
523
524
525
526 }
527
528
529 harvestReturnValues(cld.getUpdateProcedure(), obj, stmt);
530 }
531 catch (OptimisticLockException e)
532 {
533
534 if (logger.isDebugEnabled())
535 logger.debug(
536 "OptimisticLockException during the execution of update: " + e.getMessage(),
537 e);
538 throw e;
539 }
540 catch (PersistenceBrokerException e)
541 {
542
543 setLockingValues(cld, obj, oldLockingValues);
544
545 logger.error(
546 "PersistenceBrokerException during the execution of the update: " + e.getMessage(),
547 e);
548 throw e;
549 }
550 catch (SQLException e)
551 {
552 final String sql = broker.serviceSqlGenerator().getPreparedUpdateStatement(cld).getStatement();
553 throw ExceptionHelper.generateException(e, sql, cld, logger, obj);
554 }
555 finally
556 {
557 sm.closeResources(stmt, null);
558 }
559 }
560
561
562
563
564
565
566
567
568
569
570 public Object materializeObject(ClassDescriptor cld, Identity oid)
571 throws PersistenceBrokerException
572 {
573 final StatementManagerIF sm = broker.serviceStatementManager();
574 final SelectStatement sql = broker.serviceSqlGenerator().getPreparedSelectByPkStatement(cld);
575 Object result = null;
576 PreparedStatement stmt = null;
577 ResultSet rs = null;
578 try
579 {
580 stmt = sm.getSelectByPKStatement(cld);
581 if (stmt == null)
582 {
583 logger.error("getSelectByPKStatement returned a null statement");
584 throw new PersistenceBrokerException("getSelectByPKStatement returned a null statement");
585 }
586
587
588
589
590 sm.bindSelect(stmt, oid, cld, false);
591 rs = stmt.executeQuery();
592
593 ResultSetAndStatement rs_stmt = new ResultSetAndStatement(broker.serviceStatementManager(), stmt, rs, sql);
594 if (rs.next())
595 {
596 Map row = new HashMap();
597 cld.getRowReader().readObjectArrayFrom(rs_stmt, row);
598 result = cld.getRowReader().readObjectFrom(row);
599 }
600
601 rs_stmt.close();
602 }
603 catch (PersistenceBrokerException e)
604 {
605
606 sm.closeResources(stmt, rs);
607 logger.error("PersistenceBrokerException during the execution of materializeObject: " + e.getMessage(), e);
608 throw e;
609 }
610 catch (SQLException e)
611 {
612
613 sm.closeResources(stmt, rs);
614 throw ExceptionHelper.generateException(e, sql.getStatement(), cld, logger, null);
615 }
616 return result;
617 }
618
619
620
621
622
623
624
625 private void setLockingValues(ClassDescriptor cld, Object obj, ValueContainer[] oldLockingValues)
626 {
627 FieldDescriptor fields[] = cld.getLockingFields();
628
629 for (int i=0; i<fields.length; i++)
630 {
631 PersistentField field = fields[i].getPersistentField();
632 Object lockVal = oldLockingValues[i].getValue();
633
634 field.set(obj, lockVal);
635 }
636 }
637
638
639
640
641
642
643
644
645
646
647
648
649 private void harvestReturnValues(
650 ProcedureDescriptor proc,
651 Object obj,
652 PreparedStatement stmt)
653 throws PersistenceBrokerSQLException
654 {
655
656
657 if ((proc == null) || (!proc.hasReturnValues()))
658 {
659 return;
660 }
661
662
663 CallableStatement callable = (CallableStatement) stmt;
664
665
666 int index = 0;
667
668
669 if (proc.hasReturnValue())
670 {
671
672
673 index++;
674
675
676 this.harvestReturnValue(obj, callable, proc.getReturnValueFieldRef(), index);
677 }
678
679
680
681 Iterator iter = proc.getArguments().iterator();
682 while (iter.hasNext())
683 {
684 index++;
685 ArgumentDescriptor arg = (ArgumentDescriptor) iter.next();
686 if (arg.getIsReturnedByProcedure())
687 {
688 this.harvestReturnValue(obj, callable, arg.getFieldRef(), index);
689 }
690 }
691 }
692
693
694
695
696
697
698
699
700
701
702
703
704 private void harvestReturnValue(
705 Object obj,
706 CallableStatement callable,
707 FieldDescriptor fmd,
708 int index)
709 throws PersistenceBrokerSQLException
710 {
711
712 try
713 {
714
715
716 if ((callable != null) && (fmd != null) && (obj != null))
717 {
718
719
720 Object value = fmd.getJdbcType().getObjectFromColumn(callable, index);
721
722
723 fmd.getPersistentField().set(obj, fmd.getFieldConversion().sqlToJava(value));
724
725 }
726 }
727 catch (SQLException e)
728 {
729 String msg = "SQLException during the execution of harvestReturnValue"
730 + " class="
731 + obj.getClass().getName()
732 + ","
733 + " field="
734 + fmd.getAttributeName()
735 + " : "
736 + e.getMessage();
737 logger.error(msg,e);
738 throw new PersistenceBrokerSQLException(msg, e);
739 }
740 }
741
742
743
744
745
746
747
748 protected boolean isStoredProcedure(String sql)
749 {
750
751
752
753
754
755
756
757
758
759 int k = 0, i = 0;
760 char c;
761 while(k < 3 && i < sql.length())
762 {
763 c = sql.charAt(i);
764 if(c != ' ')
765 {
766 switch (k)
767 {
768 case 0:
769 if(c != '{') return false;
770 break;
771 case 1:
772 if(c != '?' && c != 'c') return false;
773 break;
774 case 2:
775 if(c != '=' && c != 'a') return false;
776 break;
777 }
778 k++;
779 }
780 i++;
781 }
782 return true;
783 }
784
785 protected void assignAutoincrementSequences(ClassDescriptor cld, Object target) throws SequenceManagerException
786 {
787
788
789 FieldDescriptor[] fields = cld.getFieldDescriptor(false);
790 FieldDescriptor field;
791 for(int i = 0; i < fields.length; i++)
792 {
793 field = fields[i];
794 if(field.isAutoIncrement() && !field.isAccessReadOnly())
795 {
796 Object value = field.getPersistentField().get(target);
797 if(broker.serviceBrokerHelper().representsNull(field, value))
798 {
799 Object id = broker.serviceSequenceManager().getUniqueValue(field);
800 field.getPersistentField().set(target, id);
801 }
802 }
803 }
804 }
805
806 protected void assignAutoincrementIdentityColumns(ClassDescriptor cld, Object target) throws SequenceManagerException
807 {
808
809
810 if(cld.useIdentityColumnField()) broker.serviceSequenceManager().afterStore(this, cld, target);
811 }
812 }