001: package org.apache.ojb.broker.accesslayer;
002:
003: /* Copyright 2003-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.util.HashMap;
023: import java.util.Iterator;
024: import java.util.Map;
025:
026: import org.apache.ojb.broker.Identity;
027: import org.apache.ojb.broker.OptimisticLockException;
028: import org.apache.ojb.broker.PersistenceBroker;
029: import org.apache.ojb.broker.PersistenceBrokerException;
030: import org.apache.ojb.broker.PersistenceBrokerSQLException;
031: import org.apache.ojb.broker.accesslayer.sql.SelectStatement;
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.JdbcType;
037: import org.apache.ojb.broker.metadata.ProcedureDescriptor;
038: import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
039: import org.apache.ojb.broker.platforms.Platform;
040: import org.apache.ojb.broker.query.Query;
041: import org.apache.ojb.broker.util.ExceptionHelper;
042: import org.apache.ojb.broker.util.logging.Logger;
043: import org.apache.ojb.broker.util.logging.LoggerFactory;
044: import org.apache.ojb.broker.util.sequence.SequenceManagerException;
045:
046: /**
047: * JdbcAccess is responsible for establishing performing
048: * SQL Queries against remote Databases.
049: * It hides all knowledge about JDBC from the BrokerImpl
050: *
051: * @author <a href="mailto:thma@apache.org">Thomas Mahler</a>
052: * @version $Id: JdbcAccessImpl.java,v 1.22.2.11 2005/12/13 18:21:23 arminw Exp $
053: */
054: public class JdbcAccessImpl implements JdbcAccess {
055: /**
056: * The logger used.
057: */
058: protected Logger logger;
059:
060: /**
061: * The broker in use.
062: */
063: protected PersistenceBroker broker;
064:
065: /**
066: * constructor is private, use getInstance to get
067: * the singleton instance of this class
068: */
069: public JdbcAccessImpl(PersistenceBroker broker) {
070: this .broker = broker;
071: logger = LoggerFactory.getLogger(this .getClass());
072: }
073:
074: /**
075: * Helper Platform accessor method
076: *
077: * @return Platform for the current broker connection manager.
078: */
079: private Platform getPlatform() {
080: return this .broker.serviceConnectionManager()
081: .getSupportedPlatform();
082: }
083:
084: /**
085: * performs a DELETE operation against RDBMS.
086: * @param cld ClassDescriptor providing mapping information.
087: * @param obj The object to be deleted.
088: */
089: public void executeDelete(ClassDescriptor cld, Object obj)
090: throws PersistenceBrokerException {
091: if (logger.isDebugEnabled()) {
092: logger.debug("executeDelete: " + obj);
093: }
094:
095: final StatementManagerIF sm = broker.serviceStatementManager();
096: PreparedStatement stmt = null;
097: try {
098: stmt = sm.getDeleteStatement(cld);
099: if (stmt == null) {
100: logger
101: .error("getDeleteStatement returned a null statement");
102: throw new PersistenceBrokerException(
103: "JdbcAccessImpl: getDeleteStatement returned a null statement");
104: }
105:
106: sm.bindDelete(stmt, cld, obj);
107: if (logger.isDebugEnabled())
108: logger.debug("executeDelete: " + stmt);
109:
110: // @todo: clearify semantics
111: // thma: the following check is not secure. The object could be deleted *or* changed.
112: // if it was deleted it makes no sense to throw an OL exception.
113: // does is make sense to throw an OL exception if the object was changed?
114: if (stmt.executeUpdate() == 0 && cld.isLocking()) //BRJ
115: {
116: throw new OptimisticLockException(
117: "Object has been modified or deleted by someone else",
118: obj);
119: }
120:
121: // Harvest any return values.
122: harvestReturnValues(cld.getDeleteProcedure(), obj, stmt);
123: } catch (OptimisticLockException e) {
124: // Don't log as error
125: if (logger.isDebugEnabled())
126: logger.debug(
127: "OptimisticLockException during the execution of delete: "
128: + e.getMessage(), e);
129: throw e;
130: } catch (PersistenceBrokerException e) {
131: logger.error(
132: "PersistenceBrokerException during the execution of delete: "
133: + e.getMessage(), e);
134: throw e;
135: } catch (SQLException e) {
136: final String sql = broker.serviceSqlGenerator()
137: .getPreparedDeleteStatement(cld).getStatement();
138: throw ExceptionHelper.generateException(e, sql, cld,
139: logger, obj);
140: } finally {
141: sm.closeResources(stmt, null);
142: }
143: }
144:
145: /**
146: * Performs a DELETE operation based on the given {@link Query} against RDBMS.
147: * @param query the query string.
148: * @param cld ClassDescriptor providing JDBC information.
149: */
150: public void executeDelete(Query query, ClassDescriptor cld)
151: throws PersistenceBrokerException {
152: if (logger.isDebugEnabled()) {
153: logger.debug("executeDelete (by Query): " + query);
154: }
155: final StatementManagerIF sm = broker.serviceStatementManager();
156: PreparedStatement stmt = null;
157: final String sql = this .broker.serviceSqlGenerator()
158: .getPreparedDeleteStatement(query, cld).getStatement();
159: try {
160: stmt = sm.getPreparedStatement(cld, sql, false,
161: StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE, cld
162: .getDeleteProcedure() != null);
163:
164: sm.bindStatement(stmt, query, cld, 1);
165: if (logger.isDebugEnabled())
166: logger.debug("executeDelete (by Query): " + stmt);
167:
168: stmt.executeUpdate();
169: } catch (SQLException e) {
170: throw ExceptionHelper.generateException(e, sql, cld, null,
171: logger);
172: } finally {
173: sm.closeResources(stmt, null);
174: }
175: }
176:
177: /**
178: * performs an INSERT operation against RDBMS.
179: * @param obj The Object to be inserted as a row of the underlying table.
180: * @param cld ClassDescriptor providing mapping information.
181: */
182: public void executeInsert(ClassDescriptor cld, Object obj)
183: throws PersistenceBrokerException {
184: if (logger.isDebugEnabled()) {
185: logger.debug("executeInsert: " + obj);
186: }
187: final StatementManagerIF sm = broker.serviceStatementManager();
188: PreparedStatement stmt = null;
189: try {
190: stmt = sm.getInsertStatement(cld);
191: if (stmt == null) {
192: logger
193: .error("getInsertStatement returned a null statement");
194: throw new PersistenceBrokerException(
195: "getInsertStatement returned a null statement");
196: }
197: // before bind values perform autoincrement sequence columns
198: assignAutoincrementSequences(cld, obj);
199: sm.bindInsert(stmt, cld, obj);
200: if (logger.isDebugEnabled())
201: logger.debug("executeInsert: " + stmt);
202: stmt.executeUpdate();
203: // after insert read and assign identity columns
204: assignAutoincrementIdentityColumns(cld, obj);
205:
206: // Harvest any return values.
207: harvestReturnValues(cld.getInsertProcedure(), obj, stmt);
208: } catch (PersistenceBrokerException e) {
209: logger.error(
210: "PersistenceBrokerException during the execution of the insert: "
211: + e.getMessage(), e);
212: throw e;
213: } catch (SequenceManagerException e) {
214: throw new PersistenceBrokerException(
215: "Error while try to assign identity value", e);
216: } catch (SQLException e) {
217: final String sql = broker.serviceSqlGenerator()
218: .getPreparedInsertStatement(cld).getStatement();
219: throw ExceptionHelper.generateException(e, sql, cld,
220: logger, obj);
221: } finally {
222: sm.closeResources(stmt, null);
223: }
224: }
225:
226: /**
227: * performs a SELECT operation against RDBMS.
228: * @param query the query string.
229: * @param cld ClassDescriptor providing JDBC information.
230: */
231: public ResultSetAndStatement executeQuery(Query query,
232: ClassDescriptor cld) throws PersistenceBrokerException {
233: if (logger.isDebugEnabled()) {
234: logger.debug("executeQuery: " + query);
235: }
236: /*
237: * MBAIRD: we should create a scrollable resultset if the start at
238: * index or end at index is set
239: */
240: boolean scrollable = ((query.getStartAtIndex() > Query.NO_START_AT_INDEX) || (query
241: .getEndAtIndex() > Query.NO_END_AT_INDEX));
242: /*
243: * OR if the prefetching of relationships is being used.
244: */
245: if (query != null && query.getPrefetchedRelationships() != null
246: && !query.getPrefetchedRelationships().isEmpty()) {
247: scrollable = true;
248: }
249: final StatementManagerIF sm = broker.serviceStatementManager();
250: final SelectStatement sql = broker.serviceSqlGenerator()
251: .getPreparedSelectStatement(query, cld);
252: PreparedStatement stmt = null;
253: ResultSet rs = null;
254: try {
255: final int queryFetchSize = query.getFetchSize();
256: final boolean isStoredProcedure = isStoredProcedure(sql
257: .getStatement());
258: stmt = sm.getPreparedStatement(cld, sql.getStatement(),
259: scrollable, queryFetchSize, isStoredProcedure);
260: if (isStoredProcedure) {
261: // Query implemented as a stored procedure, which must return a result set.
262: // Query sytax is: { ?= call PROCEDURE_NAME(?,...,?)}
263: getPlatform().registerOutResultSet(
264: (CallableStatement) stmt, 1);
265: sm.bindStatement(stmt, query, cld, 2);
266:
267: if (logger.isDebugEnabled())
268: logger.debug("executeQuery: " + stmt);
269:
270: stmt.execute();
271: rs = (ResultSet) ((CallableStatement) stmt)
272: .getObject(1);
273: } else {
274: sm.bindStatement(stmt, query, cld, 1);
275:
276: if (logger.isDebugEnabled())
277: logger.debug("executeQuery: " + stmt);
278:
279: rs = stmt.executeQuery();
280: }
281:
282: return new ResultSetAndStatement(sm, stmt, rs, sql);
283: } catch (PersistenceBrokerException e) {
284: // release resources on exception
285: sm.closeResources(stmt, rs);
286: logger.error(
287: "PersistenceBrokerException during the execution of the query: "
288: + e.getMessage(), e);
289: throw e;
290: } catch (SQLException e) {
291: // release resources on exception
292: sm.closeResources(stmt, rs);
293: throw ExceptionHelper.generateException(e, sql
294: .getStatement(), null, logger, null);
295: }
296: }
297:
298: public ResultSetAndStatement executeSQL(String sqlStatement,
299: ClassDescriptor cld, boolean scrollable)
300: throws PersistenceBrokerException {
301: return executeSQL(sqlStatement, cld, null, scrollable);
302: }
303:
304: /**
305: * performs a SQL SELECT statement against RDBMS.
306: * @param sql the query string.
307: * @param cld ClassDescriptor providing meta-information.
308: */
309: public ResultSetAndStatement executeSQL(final String sql,
310: ClassDescriptor cld, ValueContainer[] values,
311: boolean scrollable) throws PersistenceBrokerException {
312: if (logger.isDebugEnabled())
313: logger.debug("executeSQL: " + sql);
314: final boolean isStoredprocedure = isStoredProcedure(sql);
315: final StatementManagerIF sm = broker.serviceStatementManager();
316: PreparedStatement stmt = null;
317: ResultSet rs = null;
318: try {
319: stmt = sm.getPreparedStatement(cld, sql, scrollable,
320: StatementManagerIF.FETCH_SIZE_NOT_EXPLICITLY_SET,
321: isStoredprocedure);
322: if (isStoredprocedure) {
323: // Query implemented as a stored procedure, which must return a result set.
324: // Query sytax is: { ?= call PROCEDURE_NAME(?,...,?)}
325: getPlatform().registerOutResultSet(
326: (CallableStatement) stmt, 1);
327: sm.bindValues(stmt, values, 2);
328: stmt.execute();
329: rs = (ResultSet) ((CallableStatement) stmt)
330: .getObject(1);
331: } else {
332: sm.bindValues(stmt, values, 1);
333: rs = stmt.executeQuery();
334: }
335:
336: // as we return the resultset for further operations, we cannot release the statement yet.
337: // that has to be done by the JdbcAccess-clients (i.e. RsIterator, ProxyRsIterator and PkEnumeration.)
338: return new ResultSetAndStatement(sm, stmt, rs,
339: new SelectStatement() {
340: public Query getQueryInstance() {
341: return null;
342: }
343:
344: public int getColumnIndex(FieldDescriptor fld) {
345: return JdbcType.MIN_INT;
346: }
347:
348: public String getStatement() {
349: return sql;
350: }
351: });
352: } catch (PersistenceBrokerException e) {
353: // release resources on exception
354: sm.closeResources(stmt, rs);
355: logger.error(
356: "PersistenceBrokerException during the execution of the SQL query: "
357: + e.getMessage(), e);
358: throw e;
359: } catch (SQLException e) {
360: // release resources on exception
361: sm.closeResources(stmt, rs);
362: throw ExceptionHelper.generateException(e, sql, cld,
363: values, logger, null);
364: }
365: }
366:
367: public int executeUpdateSQL(String sqlStatement, ClassDescriptor cld)
368: throws PersistenceBrokerException {
369: return executeUpdateSQL(sqlStatement, cld, null, null);
370: }
371:
372: /**
373: * performs a SQL UPDTE, INSERT or DELETE statement against RDBMS.
374: * @param sqlStatement the query string.
375: * @param cld ClassDescriptor providing meta-information.
376: * @return int returncode
377: */
378: public int executeUpdateSQL(String sqlStatement,
379: ClassDescriptor cld, ValueContainer[] values1,
380: ValueContainer[] values2) throws PersistenceBrokerException {
381: if (logger.isDebugEnabled())
382: logger.debug("executeUpdateSQL: " + sqlStatement);
383:
384: int result;
385: int index;
386: PreparedStatement stmt = null;
387: final StatementManagerIF sm = broker.serviceStatementManager();
388: try {
389: stmt = sm.getPreparedStatement(cld, sqlStatement,
390: Query.NOT_SCROLLABLE,
391: StatementManagerIF.FETCH_SIZE_NOT_APPLICABLE,
392: isStoredProcedure(sqlStatement));
393: index = sm.bindValues(stmt, values1, 1);
394: sm.bindValues(stmt, values2, index);
395: result = stmt.executeUpdate();
396: } catch (PersistenceBrokerException e) {
397: logger.error(
398: "PersistenceBrokerException during the execution of the Update SQL query: "
399: + e.getMessage(), e);
400: throw e;
401: } catch (SQLException e) {
402: ValueContainer[] tmp = addValues(values1, values2);
403: throw ExceptionHelper.generateException(e, sqlStatement,
404: cld, tmp, logger, null);
405: } finally {
406: sm.closeResources(stmt, null);
407: }
408: return result;
409: }
410:
411: /** Helper method, returns the addition of both arrays (add source to target array) */
412: private ValueContainer[] addValues(ValueContainer[] target,
413: ValueContainer[] source) {
414: ValueContainer[] newArray;
415: if (source != null && source.length > 0) {
416: if (target != null) {
417: newArray = new ValueContainer[target.length
418: + source.length];
419: System.arraycopy(target, 0, newArray, 0, target.length);
420: System.arraycopy(source, 0, newArray, target.length,
421: source.length);
422: } else {
423: newArray = source;
424: }
425: } else {
426: newArray = target;
427: }
428: return newArray;
429: }
430:
431: /**
432: * performs an UPDATE operation against RDBMS.
433: * @param obj The Object to be updated in the underlying table.
434: * @param cld ClassDescriptor providing mapping information.
435: */
436: public void executeUpdate(ClassDescriptor cld, Object obj)
437: throws PersistenceBrokerException {
438: if (logger.isDebugEnabled()) {
439: logger.debug("executeUpdate: " + obj);
440: }
441:
442: // obj with nothing but key fields is not updated
443: if (cld.getNonPkRwFields().length == 0) {
444: return;
445: }
446:
447: final StatementManagerIF sm = broker.serviceStatementManager();
448: PreparedStatement stmt = null;
449: // BRJ: preserve current locking values
450: // locking values will be restored in case of exception
451: ValueContainer[] oldLockingValues;
452: oldLockingValues = cld.getCurrentLockingValues(obj);
453: try {
454: stmt = sm.getUpdateStatement(cld);
455: if (stmt == null) {
456: logger
457: .error("getUpdateStatement returned a null statement");
458: throw new PersistenceBrokerException(
459: "getUpdateStatement returned a null statement");
460: }
461:
462: sm.bindUpdate(stmt, cld, obj);
463: if (logger.isDebugEnabled())
464: logger.debug("executeUpdate: " + stmt);
465:
466: if ((stmt.executeUpdate() == 0) && cld.isLocking()) //BRJ
467: {
468: throw new OptimisticLockException(
469: "Object has been modified by someone else", obj);
470: }
471:
472: // Harvest any return values.
473: harvestReturnValues(cld.getUpdateProcedure(), obj, stmt);
474: } catch (OptimisticLockException e) {
475: // Don't log as error
476: if (logger.isDebugEnabled())
477: logger.debug(
478: "OptimisticLockException during the execution of update: "
479: + e.getMessage(), e);
480: throw e;
481: } catch (PersistenceBrokerException e) {
482: // BRJ: restore old locking values
483: setLockingValues(cld, obj, oldLockingValues);
484:
485: logger.error(
486: "PersistenceBrokerException during the execution of the update: "
487: + e.getMessage(), e);
488: throw e;
489: } catch (SQLException e) {
490: final String sql = broker.serviceSqlGenerator()
491: .getPreparedUpdateStatement(cld).getStatement();
492: throw ExceptionHelper.generateException(e, sql, cld,
493: logger, obj);
494: } finally {
495: sm.closeResources(stmt, null);
496: }
497: }
498:
499: /**
500: * performs a primary key lookup operation against RDBMS and materializes
501: * an object from the resulting row. Only skalar attributes are filled from
502: * the row, references are not resolved.
503: * @param oid contains the primary key info.
504: * @param cld ClassDescriptor providing mapping information.
505: * @return the materialized object, null if no matching row was found or if
506: * any error occured.
507: */
508: public Object materializeObject(ClassDescriptor cld, Identity oid)
509: throws PersistenceBrokerException {
510: final StatementManagerIF sm = broker.serviceStatementManager();
511: final SelectStatement sql = broker.serviceSqlGenerator()
512: .getPreparedSelectByPkStatement(cld);
513: Object result = null;
514: PreparedStatement stmt = null;
515: ResultSet rs = null;
516: try {
517: stmt = sm.getSelectByPKStatement(cld);
518: if (stmt == null) {
519: logger
520: .error("getSelectByPKStatement returned a null statement");
521: throw new PersistenceBrokerException(
522: "getSelectByPKStatement returned a null statement");
523: }
524: /*
525: arminw: currently a select by PK could never be a stored procedure,
526: thus we can always set 'false'. Is this correct??
527: */
528: sm.bindSelect(stmt, oid, cld, false);
529: rs = stmt.executeQuery();
530: // data available read object, else return null
531: ResultSetAndStatement rs_stmt = new ResultSetAndStatement(
532: broker.serviceStatementManager(), stmt, rs, sql);
533: if (rs.next()) {
534: Map row = new HashMap();
535: cld.getRowReader().readObjectArrayFrom(rs_stmt, row);
536: result = cld.getRowReader().readObjectFrom(row);
537: }
538: // close resources
539: rs_stmt.close();
540: } catch (PersistenceBrokerException e) {
541: // release resources on exception
542: sm.closeResources(stmt, rs);
543: logger.error(
544: "PersistenceBrokerException during the execution of materializeObject: "
545: + e.getMessage(), e);
546: throw e;
547: } catch (SQLException e) {
548: // release resources on exception
549: sm.closeResources(stmt, rs);
550: throw ExceptionHelper.generateException(e, sql
551: .getStatement(), cld, logger, null);
552: }
553: return result;
554: }
555:
556: /**
557: * Set the locking values
558: * @param cld
559: * @param obj
560: * @param oldLockingValues
561: */
562: private void setLockingValues(ClassDescriptor cld, Object obj,
563: ValueContainer[] oldLockingValues) {
564: FieldDescriptor fields[] = cld.getLockingFields();
565:
566: for (int i = 0; i < fields.length; i++) {
567: PersistentField field = fields[i].getPersistentField();
568: Object lockVal = oldLockingValues[i].getValue();
569:
570: field.set(obj, lockVal);
571: }
572: }
573:
574: /**
575: * Harvest any values that may have been returned during the execution
576: * of a procedure.
577: *
578: * @param proc the procedure descriptor that provides info about the procedure
579: * that was invoked.
580: * @param obj the object that was persisted
581: * @param stmt the statement that was used to persist the object.
582: *
583: * @throws PersistenceBrokerSQLException if a problem occurs.
584: */
585: private void harvestReturnValues(ProcedureDescriptor proc,
586: Object obj, PreparedStatement stmt)
587: throws PersistenceBrokerSQLException {
588: // If the procedure descriptor is null or has no return values or
589: // if the statement is not a callable statment, then we're done.
590: if ((proc == null) || (!proc.hasReturnValues())) {
591: return;
592: }
593:
594: // Set up the callable statement
595: CallableStatement callable = (CallableStatement) stmt;
596:
597: // This is the index that we'll use to harvest the return value(s).
598: int index = 0;
599:
600: // If the proc has a return value, then try to harvest it.
601: if (proc.hasReturnValue()) {
602:
603: // Increment the index
604: index++;
605:
606: // Harvest the value.
607: this .harvestReturnValue(obj, callable, proc
608: .getReturnValueFieldRef(), index);
609: }
610:
611: // Check each argument. If it's returned by the procedure,
612: // then harvest the value.
613: Iterator iter = proc.getArguments().iterator();
614: while (iter.hasNext()) {
615: index++;
616: ArgumentDescriptor arg = (ArgumentDescriptor) iter.next();
617: if (arg.getIsReturnedByProcedure()) {
618: this .harvestReturnValue(obj, callable, arg
619: .getFieldRef(), index);
620: }
621: }
622: }
623:
624: /**
625: * Harvest a single value that was returned by a callable statement.
626: *
627: * @param obj the object that will receive the value that is harvested.
628: * @param callable the CallableStatement that contains the value to harvest
629: * @param fmd the FieldDescriptor that identifies the field where the
630: * harvested value will be stord.
631: * @param index the parameter index.
632: *
633: * @throws PersistenceBrokerSQLException if a problem occurs.
634: */
635: private void harvestReturnValue(Object obj,
636: CallableStatement callable, FieldDescriptor fmd, int index)
637: throws PersistenceBrokerSQLException {
638:
639: try {
640: // If we have a field descriptor, then we can harvest
641: // the return value.
642: if ((callable != null) && (fmd != null) && (obj != null)) {
643: // Get the value and convert it to it's appropriate
644: // java type.
645: Object value = fmd.getJdbcType().getObjectFromColumn(
646: callable, index);
647:
648: // Set the value of the persistent field.
649: fmd.getPersistentField().set(obj,
650: fmd.getFieldConversion().sqlToJava(value));
651:
652: }
653: } catch (SQLException e) {
654: String msg = "SQLException during the execution of harvestReturnValue"
655: + " class="
656: + obj.getClass().getName()
657: + ","
658: + " field="
659: + fmd.getAttributeName()
660: + " : "
661: + e.getMessage();
662: logger.error(msg, e);
663: throw new PersistenceBrokerSQLException(msg, e);
664: }
665: }
666:
667: /**
668: * Check if the specified sql-string is a stored procedure
669: * or not.
670: * @param sql The sql query to check
671: * @return <em>True</em> if the query is a stored procedure, else <em>false</em> is returned.
672: */
673: protected boolean isStoredProcedure(String sql) {
674: /*
675: Stored procedures start with
676: {?= call <procedure-name>[<arg1>,<arg2>, ...]}
677: or
678: {call <procedure-name>[<arg1>,<arg2>, ...]}
679: but also statements with white space like
680: { ?= call <procedure-name>[<arg1>,<arg2>, ...]}
681: are possible.
682: */
683: int k = 0, i = 0;
684: char c;
685: while (k < 3 && i < sql.length()) {
686: c = sql.charAt(i);
687: if (c != ' ') {
688: switch (k) {
689: case 0:
690: if (c != '{')
691: return false;
692: break;
693: case 1:
694: if (c != '?' && c != 'c')
695: return false;
696: break;
697: case 2:
698: if (c != '=' && c != 'a')
699: return false;
700: break;
701: }
702: k++;
703: }
704: i++;
705: }
706: return true;
707: }
708:
709: protected void assignAutoincrementSequences(ClassDescriptor cld,
710: Object target) throws SequenceManagerException {
711: // TODO: refactor auto-increment handling, auto-increment should only be supported by PK fields?
712: // FieldDescriptor[] fields = cld.getPkFields();
713: FieldDescriptor[] fields = cld.getFieldDescriptor(false);
714: FieldDescriptor field;
715: for (int i = 0; i < fields.length; i++) {
716: field = fields[i];
717: if (field.isAutoIncrement() && !field.isAccessReadOnly()) {
718: Object value = field.getPersistentField().get(target);
719: if (broker.serviceBrokerHelper().representsNull(field,
720: value)) {
721: Object id = broker.serviceSequenceManager()
722: .getUniqueValue(field);
723: field.getPersistentField().set(target, id);
724: }
725: }
726: }
727: }
728:
729: protected void assignAutoincrementIdentityColumns(
730: ClassDescriptor cld, Object target)
731: throws SequenceManagerException {
732: // if database Identity Columns are used, query the id from database
733: // other SequenceManager implementations will ignore this call
734: if (cld.useIdentityColumnField())
735: broker.serviceSequenceManager().afterStore(this, cld,
736: target);
737: }
738: }
|