001: /*
002: * (c) Copyright 2007 by Volker Bergmann. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, is permitted under the terms of the
006: * GNU General Public License.
007: *
008: * For redistributing this software or a derivative work under a license other
009: * than the GPL-compatible Free Software License as defined by the Free
010: * Software Foundation or approved by OSI, you must first obtain a commercial
011: * license to this software product from Volker Bergmann.
012: *
013: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
014: * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
015: * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
016: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
017: * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
018: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
019: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
020: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
021: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
022: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
023: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
024: * POSSIBILITY OF SUCH DAMAGE.
025: */
026:
027: package org.databene.platform.db;
028:
029: import org.databene.id.IdProvider;
030: import org.databene.id.IdProviderFactory;
031: import org.databene.id.IdProviderId;
032: import org.databene.id.IdStrategy;
033: import org.databene.id.IncrementIdProvider;
034: import org.databene.platform.db.DBUtil;
035: import org.databene.platform.db.dialect.UnknownDialect;
036: import org.databene.platform.db.model.jdbc.JDBCDBImporter;
037: import org.databene.platform.db.model.*;
038: import org.databene.platform.bean.ArrayPropertyExtractor;
039: import org.databene.commons.*;
040: import org.databene.commons.converter.AnyConverter;
041: import org.databene.commons.converter.ConvertingIterable;
042: import org.databene.model.data.*;
043: import org.databene.model.depend.DependencyModel;
044: import org.databene.model.storage.StorageSystem;
045: import org.apache.commons.logging.Log;
046: import org.apache.commons.logging.LogFactory;
047:
048: import java.util.Collection;
049: import java.util.HashSet;
050: import java.util.Iterator;
051: import java.util.Map;
052: import java.util.HashMap;
053: import java.util.List;
054: import java.util.Properties;
055: import java.util.Set;
056: import java.io.IOException;
057: import java.math.BigInteger;
058: import java.math.BigDecimal;
059: import java.sql.Blob;
060: import java.sql.Connection;
061: import java.sql.PreparedStatement;
062: import java.sql.SQLException;
063: import java.sql.ResultSet;
064: import java.sql.DriverManager;
065: import java.sql.Statement;
066:
067: /**
068: * RDBMS implementation of the {@link StorageSystem} interface.<br/>
069: * <br/>
070: * Created: 27.06.2007 23:04:19
071: * @since 0.3
072: * @author Volker Bergmann
073: */
074: public class DBSystem implements StorageSystem, IdProviderFactory {
075:
076: // constants -------------------------------------------------------------------------------------------------------
077:
078: protected static final ArrayPropertyExtractor<String> nameExtractor = new ArrayPropertyExtractor<String>(
079: "name", String.class);
080:
081: public static final IdStrategy<Long> SEQHILO = new IdStrategy<Long>(
082: "seqhilo", Long.class);
083: public static final IdStrategy<Long> INCREMENT = new IdStrategy<Long>(
084: "increment", Long.class);
085: public static final IdStrategy<Long> SEQUENCE = new IdStrategy<Long>(
086: "sequence", Long.class);
087: public static final IdStrategy<Object> QUERY = new IdStrategy<Object>(
088: "query", Object.class);
089:
090: private static final IdStrategy[] ID_STRATEGIES = { SEQHILO,
091: INCREMENT, SEQUENCE, QUERY };
092:
093: // attributes ------------------------------------------------------------------------------------------------------
094:
095: private String id;
096: private String url;
097: private String user;
098: private String password;
099: private String driver;
100: private String schema;
101: private boolean batch;
102:
103: private int fetchSize;
104:
105: private Database database;
106:
107: private Map<Thread, ThreadContext> contexts;
108: private Map<String, EntityDescriptor> typeDescriptors;
109:
110: private TypeMapper<Class<? extends Object>> driverTypeMapper;
111: private DatabaseDialect dialect;
112:
113: // constructors ----------------------------------------------------------------------------------------------------
114:
115: public DBSystem() {
116: this (null, null, null, null, null);
117: }
118:
119: public DBSystem(String id, String url, String driver, String user,
120: String password) {
121: super ();
122: this .id = id;
123: this .url = url;
124: this .user = user;
125: this .password = password;
126: this .driver = driver;
127: this .schema = null;
128: this .fetchSize = 100;
129: this .batch = false;
130: this .contexts = new HashMap<Thread, ThreadContext>();
131: this .driverTypeMapper = driverTypeMapper();
132: }
133:
134: // properties ------------------------------------------------------------------------------------------------------
135:
136: public String getId() {
137: return id;
138: }
139:
140: public void setId(String id) {
141: this .id = id;
142: }
143:
144: public String getDriver() {
145: return driver;
146: }
147:
148: public void setDriver(String driver) {
149: this .driver = driver;
150: }
151:
152: public String getUrl() {
153: return url;
154: }
155:
156: public void setUrl(String url) {
157: this .url = url;
158: }
159:
160: public String getUser() {
161: return user;
162: }
163:
164: public void setUser(String user) {
165: this .user = user;
166: }
167:
168: public String getPassword() {
169: return password;
170: }
171:
172: public void setPassword(String password) {
173: this .password = password;
174: }
175:
176: public String getSchema() {
177: return schema;
178: }
179:
180: public void setSchema(String schema) {
181: this .schema = schema;
182: }
183:
184: /**
185: * @return the batch
186: */
187: public boolean isBatch() {
188: return batch;
189: }
190:
191: /**
192: * @param batch the batch to set
193: */
194: public void setBatch(boolean batch) {
195: this .batch = batch;
196: }
197:
198: /**
199: * @return the fetchSize
200: */
201: public int getFetchSize() {
202: return fetchSize;
203: }
204:
205: /**
206: * @param fetchSize the fetchSize to set
207: */
208: public void setFetchSize(int fetchSize) {
209: this .fetchSize = fetchSize;
210: }
211:
212: // DescriptorProvider interface ------------------------------------------------------------------------------------
213:
214: public EntityDescriptor[] getTypeDescriptors() {
215: if (logger.isDebugEnabled())
216: logger.debug("getTypeDescriptors()");
217: if (typeDescriptors == null)
218: parseMetaData();
219: return CollectionUtil.toArray(typeDescriptors.values(),
220: EntityDescriptor.class);
221: }
222:
223: public EntityDescriptor getTypeDescriptor(String tableName) {
224: if (logger.isDebugEnabled())
225: logger.debug("getTypeDescriptor(" + tableName + ")");
226: if (typeDescriptors == null)
227: parseMetaData();
228: EntityDescriptor entityDescriptor = typeDescriptors
229: .get(tableName);
230: if (entityDescriptor == null)
231: for (EntityDescriptor candidate : typeDescriptors.values())
232: if (candidate.getName().equalsIgnoreCase(tableName)) {
233: entityDescriptor = candidate;
234: break;
235: }
236: return entityDescriptor;
237: }
238:
239: // StorageSystem interface -----------------------------------------------------------------------------------------
240:
241: public void store(Entity entity) {
242: if (logger.isDebugEnabled())
243: logger.debug("Storing " + entity);
244: ColumnInfo[] writeColumnInfos = writeColumnInfos(entity);
245: try {
246: String tableName = entity.getName();
247: PreparedStatement insertStatement = getInsertStatement(
248: entity.getDescriptor(), writeColumnInfos);
249: for (int i = 0; i < writeColumnInfos.length; i++) {
250: Object componentValue = entity
251: .getComponent(writeColumnInfos[i].name);
252: Class<? extends Object> type = writeColumnInfos[i].type;
253: Object jdbcValue = AnyConverter.convert(componentValue,
254: type);
255: try {
256: if (jdbcValue != null)
257: insertStatement.setObject(i + 1, jdbcValue);
258: else
259: insertStatement.setNull(i + 1,
260: writeColumnInfos[i].sqlType);
261: } catch (SQLException e) {
262: throw new RuntimeException("error setting column "
263: + tableName + '.'
264: + writeColumnInfos[i].name, e);
265: }
266: }
267: if (batch)
268: insertStatement.addBatch();
269: else
270: insertStatement.executeUpdate();
271: } catch (SQLException e) {
272: throw new RuntimeException("Error in persisting " + entity,
273: e);
274: }
275: }
276:
277: public void flush() {
278: if (logger.isDebugEnabled())
279: logger.debug("flush()");
280: for (ThreadContext threadContext : contexts.values())
281: threadContext.commit();
282: }
283:
284: public void close() {
285: if (logger.isDebugEnabled())
286: logger.debug("close()");
287: flush();
288: for (IdProvider<? extends Object> idProvider : idProviders
289: .values())
290: idProvider.close();
291: Iterator<ThreadContext> iterator = contexts.values().iterator();
292: while (iterator.hasNext()) {
293: iterator.next().close();
294: iterator.remove();
295: }
296: }
297:
298: public TypedIterable<Entity> queryEntities(String type,
299: String selector) {
300: if (logger.isDebugEnabled())
301: logger.debug("getEntities(" + type + ")");
302: Connection connection = getThreadContext().connection;
303: String sql = "select * from "
304: + type
305: + (StringUtil.isEmpty(selector) ? "" : " WHERE "
306: + selector);
307: Iterable<ResultSet> iterable = new QueryIterable(connection,
308: sql, fetchSize);
309: return new EntityResultSetIterable(iterable,
310: getTypeDescriptor(type));
311: }
312:
313: public long countEntities(String tableName) {
314: if (logger.isDebugEnabled())
315: logger.debug("countEntities(" + tableName + ")");
316: String sql = "select count(*) from " + tableName;
317: try {
318: Connection connection = getThreadContext().connection;
319: Statement statement = connection.createStatement();
320: ResultSet resultSet = statement.executeQuery(sql);
321: resultSet.next();
322: long count = resultSet.getLong(1);
323: return count;
324: } catch (SQLException e) {
325: throw new RuntimeException(
326: "Error in counting rows of table " + tableName
327: + ". SQL = " + sql, e);
328: }
329: }
330:
331: public <T> TypedIterable<T> queryEntityIds(String tableName,
332: String selector) {
333: if (logger.isDebugEnabled())
334: logger.debug("getIds(" + tableName + ", " + selector + ")");
335:
336: DBTable table = getTable(tableName);
337: DBPrimaryKeyConstraint pkConstraint = table
338: .getPrimaryKeyConstraint();
339: DBColumn[] columns = pkConstraint.getColumns();
340: String[] pkColumnNames = ArrayPropertyExtractor.convert(
341: columns, "name", String.class);
342: String query = "select " + ArrayFormat.format(pkColumnNames)
343: + " from " + tableName;
344: if (selector != null)
345: query += " where " + selector;
346: return query(query);
347: }
348:
349: public <T> TypedIterable<T> query(String query) {
350: if (logger.isDebugEnabled())
351: logger.debug("getBySelector(" + query + ")");
352: Connection connection = getThreadContext().connection;
353: QueryIterable resultSetIterable = new QueryIterable(connection,
354: query);
355: return (TypedIterable<T>) new ConvertingIterable<ResultSet, Object>(
356: resultSetIterable, new ResultSetConverter(true));
357: }
358:
359: // IdProviderFactory interface -------------------------------------------------------------------------------------
360:
361: private Map<IdProviderId, IdProvider> idProviders = new HashMap<IdProviderId, IdProvider>();
362:
363: public IdStrategy<? extends Object>[] getIdStrategies() {
364: return ID_STRATEGIES;
365: }
366:
367: public <T> IdProvider<T> idProvider(IdStrategy<T> strategy,
368: String param, String scope) {
369: IdProviderId pId = new IdProviderId(strategy.getName(), param,
370: scope, this .getId());
371: IdProvider<T> provider = idProviders.get(pId);
372: if (provider == null) {
373: if (SEQHILO.equals(strategy))
374: provider = (IdProvider<T>) new SeqHiLoIdProvider(
375: getConnection(), dialect
376: .sequenceAccessorSql(param), 100);
377: else if (INCREMENT.equals(strategy))
378: provider = (IdProvider<T>) createIdProvider(param);
379: else if (SEQUENCE.equals(strategy))
380: provider = (IdProvider<T>) new LongQueryIdProvider(
381: getConnection(), dialect
382: .sequenceAccessorSql(param));
383: else if (QUERY.equals(strategy))
384: provider = (IdProvider<T>) new QueryIdProvider(
385: getConnection(), param);
386: else
387: throw new IllegalArgumentException(
388: "unknown id generation strategy: " + strategy);
389: idProviders.put(pId, provider);
390: }
391: return provider;
392: }
393:
394: public Connection createConnection() {
395: try {
396: Class.forName(driver);
397: Connection connection = new PooledConnection(DriverManager
398: .getConnection(url, user, password));
399: connection.setAutoCommit(false);
400: return connection;
401: } catch (ClassNotFoundException e) {
402: throw new ConfigurationError("JDBC driver not found: "
403: + driver, e);
404: } catch (SQLException e) {
405: throw new RuntimeException(
406: "Connecting the database failed. URL: " + url, e);
407: }
408: }
409:
410: // java.lang.Object overrides ------------------------------------------------------------------
411:
412: @Override
413: public String toString() {
414: return getClass().getSimpleName() + '[' + user + '@' + url
415: + ']';
416: }
417:
418: // private helpers ------------------------------------------------------------------------------
419:
420: private PreparedStatement getInsertStatement(
421: EntityDescriptor descriptor, ColumnInfo[] columnInfos)
422: throws SQLException {
423: ThreadContext context = getThreadContext();
424: return context.getInsertStatement(descriptor, columnInfos);
425: }
426:
427: private void parseMetaData() {
428: logger.debug("parsing metadata...");
429: try {
430: this .typeDescriptors = new OrderedMap<String, EntityDescriptor>();
431: //this.tableColumnIndexes = new HashMap<String, Map<String, Integer>>();
432: JDBCDBImporter importer = new JDBCDBImporter(url, driver,
433: user, password, schema, false);
434: database = importer.importDatabase();
435: String productName = importer.getProductName();
436: mapStrategy(productName);
437: List<DBTable> tables = dependencyOrderedTables(database);
438: for (DBTable table : tables)
439: parseTable(table);
440: } catch (ImportFailedException e) {
441: throw new ConfigurationError(
442: "Unexpected failure of database meta data import. ",
443: e);
444: }
445: }
446:
447: private void mapStrategy(String productName) {
448: String filename = "org/databene/platform/db/databene.db_dialect.properties";
449: try {
450: Properties mappings = IOUtil.readProperties(filename);
451: for (Map.Entry<Object, Object> entry : mappings.entrySet())
452: if (productName.toLowerCase().contains(
453: (String) entry.getKey())) {
454: dialect = (DatabaseDialect) BeanUtil
455: .newInstance((String) entry.getValue());
456: return;
457: }
458: dialect = new UnknownDialect(productName);
459: } catch (IOException e) {
460: throw new ConfigurationError(
461: "Database dialect mapping not found: " + filename,
462: e);
463: }
464: }
465:
466: private static List<DBTable> dependencyOrderedTables(
467: Database database) {
468: DependencyModel<DBTable> model = new DependencyModel<DBTable>();
469: for (DBCatalog catalog : database.getCatalogs())
470: for (DBTable table : catalog.getTables())
471: model.addNode(table);
472: for (DBSchema schema : database.getSchemas())
473: for (DBTable table : schema.getTables())
474: model.addNode(table);
475: List<DBTable> tables = model.dependencyOrderedObjects(true);
476: return tables;
477: }
478:
479: private void parseTable(DBTable table) {
480: if (logger.isDebugEnabled())
481: logger.debug("Parsing table " + table);
482: String tableName = table.getName();
483: if (tableName.startsWith("BIN$"))
484: return;
485: EntityDescriptor td = new EntityDescriptor(tableName, false);
486: // process foreign keys
487: for (DBForeignKeyConstraint constraint : table
488: .getForeignKeyConstraints()) {
489: List<DBForeignKeyColumn> foreignKeyColumns = constraint
490: .getForeignKeyColumns();
491: if (foreignKeyColumns.size() == 1) {
492: DBForeignKeyColumn foreignKeyColumn = foreignKeyColumns
493: .get(0);
494: DBColumn targetColumn = foreignKeyColumn
495: .getTargetColumn();
496: DBTable targetTable = targetColumn.getTable();
497: String fkColumnName = foreignKeyColumn
498: .getForeignKeyColumn().getName();
499: ReferenceDescriptor descriptor = new ReferenceDescriptor(
500: fkColumnName);
501: descriptor.setSource(id);
502: descriptor.setTargetTye(targetTable.getName());
503: DBColumnType concreteType = foreignKeyColumn
504: .getForeignKeyColumn().getType();
505: String abstractType = JdbcMetaTypeMapper
506: .abstractType(concreteType);
507: descriptor.setType(abstractType);
508: td.setComponentDescriptor(descriptor); // overwrite attribute descriptor
509: logger.debug("Parsed reference " + table.getName()
510: + '.' + descriptor);
511: } else {
512: logger
513: .error("Not implemented: Don't know how to handle composite foreign keys");
514: }
515: }
516: // process normal columns
517: for (DBColumn column : table.getColumns()) {
518: if (logger.isDebugEnabled())
519: logger.debug("parsing column: " + column);
520: if (td.getComponentDescriptor(column.getName()) != null)
521: continue; // skip columns that were already parsed (fk)
522: String columnId = table.getName() + '.' + column.getName();
523: if (column.isVersionColumn()) {
524: logger.debug("Leaving out version column " + columnId);
525: continue;
526: }
527: AttributeDescriptor descriptor = new AttributeDescriptor(
528: column.getName());
529: DBColumnType columnType = column.getType();
530: String type = JdbcMetaTypeMapper.abstractType(columnType);
531: descriptor.setType(type);
532: String defaultValue = column.getDefaultValue();
533: if (defaultValue != null)
534: descriptor.setDetail("values", defaultValue);
535: int[] modifiers = column.getModifiers();
536: switch (modifiers.length) {
537: case 0:
538: break;
539: case 1:
540: descriptor.setMaxLength(modifiers[0]);
541: break;
542: case 2:
543: descriptor.setMaxLength(modifiers[0]);
544: if (!"string".equals(type))
545: break;
546: descriptor.setPrecision(precision(modifiers[1]));
547: break;
548: default:
549: logger.error("ignored size(s) for " + columnId + ": "
550: + ArrayFormat.formatInts(", ", modifiers));
551: }
552: descriptor
553: .setNullable(column.getNotNullConstraint() == null);
554: List<DBConstraint> ukConstraints = column
555: .getUkConstraints();
556: for (DBConstraint constraint : ukConstraints) {
557: if (constraint.getColumns().length == 1) {
558: assert constraint.getColumns()[0].equals(column); // consistence check
559: descriptor.setUnique(true);
560: } else {
561: logger
562: .error("Uniqueness assurance on multiple columns is not supported yet: "
563: + constraint);
564: // TODO v0.5 support uniqueness constraints on combination of columns
565: }
566: }
567: logger.debug("parsed attribute " + columnId + ": "
568: + descriptor);
569: td.setComponentDescriptor(descriptor);
570: }
571:
572: typeDescriptors.put(td.getName(), td);
573: }
574:
575: private String createSQLInsert(String tableName,
576: ColumnInfo[] columnInfos) {
577: StringBuilder builder = new StringBuilder("insert into ")
578: .append(tableName).append("(");
579: if (columnInfos.length > 0)
580: builder.append(columnInfos[0].name);
581: for (int i = 1; i < columnInfos.length; i++)
582: builder.append(',').append(columnInfos[i].name);
583: builder.append(") values (");
584: if (columnInfos.length > 0)
585: builder.append("?");
586: for (int i = 1; i < columnInfos.length; i++)
587: builder.append(",?");
588: builder.append(")");
589: String sql = builder.toString();
590: logger.debug("built SQL statement: " + sql);
591: return sql;
592: }
593:
594: /*
595: private int getColumnIndex(String tableName, String columnName) {
596: tableName = tableName.toLowerCase();
597: columnName = columnName.toLowerCase();
598: Map<String, Integer> columnIndexes = tableColumnIndexes.get(tableName);
599: if (columnIndexes == null) {
600: columnIndexes = new HashMap<String, Integer>();
601: tableColumnIndexes.put(tableName, columnIndexes);
602: }
603: Integer index = columnIndexes.get(columnName);
604: if (index == null) {
605: String[] columnNames = StringUtil.toLowerCase(getColumnNames(tableName));
606: index = ArrayUtil.indexOf(columnName, columnNames) + 1;
607: if (index == 0)
608: throw new IllegalArgumentException("Column not found: " + columnName);
609: columnIndexes.put(columnName, index);
610: }
611: return index;
612: }
613: */
614:
615: private ColumnInfo[] writeColumnInfos(Entity entity) {
616: String tableName = entity.getName();
617: DBTable table = getTable(tableName);
618: EntityDescriptor typeDescriptor = getTypeDescriptor(tableName);
619: Collection<ComponentDescriptor> componentDescriptors = typeDescriptor
620: .getComponentDescriptors();
621: ArrayBuilder<ColumnInfo> builder = new ArrayBuilder<ColumnInfo>(
622: ColumnInfo.class, componentDescriptors.size());
623: EntityDescriptor entityDescriptor = entity.getDescriptor();
624: for (ComponentDescriptor dbCompDescriptor : componentDescriptors) {
625: ComponentDescriptor enCompDescriptor = entityDescriptor
626: .getComponentDescriptor(dbCompDescriptor.getName());
627: if (enCompDescriptor != null
628: && enCompDescriptor.getMode() == Mode.ignored)
629: continue;
630: if (dbCompDescriptor.getMode() != Mode.ignored) {
631: String name = dbCompDescriptor.getName();
632: String abstractType = dbCompDescriptor.getType();
633: DBColumn column = table.getColumn(name);
634: DBColumnType columnType = column.getType();
635: int sqlType = columnType.getJdbcType();
636: Class<? extends Object> javaType = driverTypeMapper
637: .concreteType(abstractType);
638: builder.append(new ColumnInfo(name, sqlType, javaType));
639: }
640: }
641: return builder.toArray();
642: }
643:
644: private DBTable getTable(String tableName) {
645: DBSchema dbSchema = database.getSchema(this .schema);
646: if (dbSchema != null) {
647: DBTable table = dbSchema.getTable(tableName);
648: if (table != null)
649: return table;
650: }
651: for (DBCatalog catalog : database.getCatalogs()) {
652: DBTable table = catalog.getTable(tableName);
653: if (table != null)
654: return table;
655: }
656: for (DBSchema schema2 : database.getSchemas()) {
657: DBTable table = schema2.getTable(tableName);
658: if (table != null)
659: return table;
660: }
661: throw new ObjectNotFoundException("Table " + tableName);
662: }
663:
664: private IncrementIdProvider createIdProvider(String param) {
665: long initialValue = 1;
666: if (param != null)
667: initialValue = Long.parseLong(param);
668: return new IncrementIdProvider(initialValue);
669: }
670:
671: private synchronized ThreadContext getThreadContext() {
672: Thread currentThread = Thread.currentThread();
673: ThreadContext context = contexts.get(currentThread);
674: if (context == null) {
675: context = new ThreadContext();
676: contexts.put(currentThread, context);
677: }
678: return context;
679: }
680:
681: private Connection getConnection() {
682: return getThreadContext().connection;
683: }
684:
685: private class ThreadContext {
686:
687: private Connection connection;
688:
689: public Map<EntityDescriptor, PreparedStatement> insertStatements;
690:
691: public ThreadContext() {
692: insertStatements = new HashMap<EntityDescriptor, PreparedStatement>();
693: connection = createConnection();
694: }
695:
696: void commit() {
697: try {
698: for (Map.Entry<EntityDescriptor, PreparedStatement> entry : insertStatements
699: .entrySet()) {
700: PreparedStatement statement = entry.getValue();
701: if (statement != null) {
702: statement.executeBatch();
703: // need to finish old statement
704: if (jdbcLogger.isDebugEnabled())
705: jdbcLogger.debug("Closing statement: "
706: + statement);
707: DBUtil.close(statement);
708: }
709: entry.setValue(null);
710: }
711: if (jdbcLogger.isDebugEnabled())
712: jdbcLogger.debug("Committing connection: "
713: + connection);
714: connection.commit();
715: } catch (SQLException e) {
716: throw new RuntimeException(e);
717: }
718: }
719:
720: public PreparedStatement getInsertStatement(
721: EntityDescriptor descriptor, ColumnInfo[] columnInfos) {
722: try {
723: PreparedStatement statement = insertStatements
724: .get(descriptor);
725: if (statement == null) {
726: String sql = createSQLInsert(descriptor.getName(),
727: columnInfos);
728: if (jdbcLogger.isDebugEnabled())
729: jdbcLogger
730: .debug("Creating prepared statement: "
731: + sql);
732: statement = connection.prepareStatement(sql);
733: insertStatements.put(descriptor, statement);
734: } else {
735: statement.clearParameters();
736: }
737: return statement;
738: } catch (SQLException e) {
739: throw new RuntimeException(e);
740: }
741: }
742:
743: public void close() {
744: commit();
745: DBUtil.close(connection);
746: }
747: }
748:
749: private String precision(int scale) {
750: if (scale == 0)
751: return "1";
752: StringBuilder builder = new StringBuilder("0.");
753: for (int i = 1; i < scale; i++)
754: builder.append('0');
755: builder.append(1);
756: return builder.toString();
757: }
758:
759: private TypeMapper<Class<? extends Object>> driverTypeMapper() {
760: return new TypeMapper<Class<? extends Object>>("byte",
761: Byte.class, "short", Short.class, "int", Integer.class,
762: "big_integer", BigInteger.class, "float", Float.class,
763: "double", Double.class, "big_decimal",
764: BigDecimal.class,
765:
766: "boolean", Boolean.class, "char", Character.class,
767: "date", java.sql.Date.class, "timestamp",
768: java.sql.Timestamp.class,
769:
770: "string", java.sql.Clob.class, "string", String.class,
771:
772: "binary", Blob.class, "binary", byte[].class
773:
774: // "object", Object.class,
775:
776: );
777: }
778:
779: private static final Log logger = LogFactory.getLog(DBSystem.class);
780: // private static final Log sqlLogger = LogFactory.getLog("org.databene.benerator.SQL");
781: private static final Log jdbcLogger = LogFactory
782: .getLog("org.databene.benerator.JDBC");
783:
784: }
|