diff --git a/symmetric-android/src/main/java/org/jumpmind/symmetric/android/AndroidSqlTransaction.java b/symmetric-android/src/main/java/org/jumpmind/symmetric/android/AndroidSqlTransaction.java index 0b78469500..ee7bef3fa4 100644 --- a/symmetric-android/src/main/java/org/jumpmind/symmetric/android/AndroidSqlTransaction.java +++ b/symmetric-android/src/main/java/org/jumpmind/symmetric/android/AndroidSqlTransaction.java @@ -27,6 +27,8 @@ import org.jumpmind.db.model.Table; import org.jumpmind.db.sql.ISqlRowMapper; import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.sql.Row; +import org.jumpmind.db.sql.RowMapper; import android.database.sqlite.SQLiteDatabase; @@ -56,6 +58,16 @@ public boolean isInBatchMode() { return false; } + @Override + public Row queryForRow(String sql, Object... args) { + List rows = query(sql, new RowMapper(), args, null); + if (rows.size() > 0) { + return rows.get(0); + } else { + return null; + } + } + public List query(String sql, ISqlRowMapper mapper, Map namedParams) { return sqlTemplate.query(sql, mapper, namedParams); } diff --git a/symmetric-client/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java b/symmetric-client/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java index 7ef53e8cd7..cfe9895fba 100644 --- a/symmetric-client/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java +++ b/symmetric-client/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java @@ -277,6 +277,7 @@ protected IDatabasePlatform createDatabasePlatform(TypedProperties properties) { public static IDatabasePlatform createDatabasePlatform(ApplicationContext springContext, TypedProperties properties, DataSource dataSource, boolean waitOnAvailableDatabase) { + log.info("Initializing connection to database"); if (dataSource == null) { String jndiName = properties.getProperty(ParameterConstants.DB_JNDI_NAME); if (StringUtils.isNotBlank(jndiName)) { diff --git a/symmetric-client/src/main/java/org/jumpmind/symmetric/db/JdbcSymmetricDialectFactory.java b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/JdbcSymmetricDialectFactory.java index c08b9f8302..5d2097ac2b 100644 --- a/symmetric-client/src/main/java/org/jumpmind/symmetric/db/JdbcSymmetricDialectFactory.java +++ b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/JdbcSymmetricDialectFactory.java @@ -53,6 +53,7 @@ import org.jumpmind.symmetric.db.firebird.Firebird20SymmetricDialect; import org.jumpmind.symmetric.db.firebird.Firebird21SymmetricDialect; import org.jumpmind.symmetric.db.firebird.FirebirdSymmetricDialect; +import org.jumpmind.symmetric.db.generic.GenericSymmetricDialect; import org.jumpmind.symmetric.db.h2.H2SymmetricDialect; import org.jumpmind.symmetric.db.hsqldb.HsqlDbSymmetricDialect; import org.jumpmind.symmetric.db.hsqldb2.HsqlDb2SymmetricDialect; @@ -155,7 +156,7 @@ public ISymmetricDialect create() { } else if (platform instanceof VoltDbDatabasePlatform) { dialect = new VoltDbSymmetricDialect(parameterService, platform); } else { - throw new DbNotSupportedException(); + dialect = new GenericSymmetricDialect(parameterService, platform); } return dialect; } diff --git a/symmetric-client/src/main/java/org/jumpmind/symmetric/db/generic/GenericSymmetricDialect.java b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/generic/GenericSymmetricDialect.java new file mode 100644 index 0000000000..b9a2c7dfb0 --- /dev/null +++ b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/generic/GenericSymmetricDialect.java @@ -0,0 +1,53 @@ +package org.jumpmind.symmetric.db.generic; + +import org.jumpmind.db.platform.IDatabasePlatform; +import org.jumpmind.db.sql.ISqlTransaction; +import org.jumpmind.db.util.BinaryEncoding; +import org.jumpmind.symmetric.db.AbstractSymmetricDialect; +import org.jumpmind.symmetric.service.IParameterService; + +public class GenericSymmetricDialect extends AbstractSymmetricDialect { + + public GenericSymmetricDialect(IParameterService parameterService, IDatabasePlatform platform) { + super(parameterService, platform); + this.triggerTemplate = new GenericTriggerTemplate(this); + this.supportsSubselectsInDelete = false; + this.supportsSubselectsInUpdate = false; + } + + @Override + public void cleanDatabase() { + } + + @Override + public void disableSyncTriggers(ISqlTransaction transaction, String nodeId) { + } + + @Override + public void enableSyncTriggers(ISqlTransaction transaction) { + } + + @Override + public String getSyncTriggersExpression() { + return null; + } + + @Override + public void dropRequiredDatabaseObjects() { + } + + @Override + public void createRequiredDatabaseObjects() { + } + + @Override + public BinaryEncoding getBinaryEncoding() { + return null; + } + + @Override + protected boolean doesTriggerExistOnPlatform(String catalogName, String schema, String tableName, String triggerName) { + return false; + } + +} diff --git a/symmetric-client/src/main/java/org/jumpmind/symmetric/db/generic/GenericTriggerTemplate.java b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/generic/GenericTriggerTemplate.java new file mode 100644 index 0000000000..0e76e2bbbf --- /dev/null +++ b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/generic/GenericTriggerTemplate.java @@ -0,0 +1,40 @@ +/** + * Licensed to JumpMind Inc under one or more contributor + * license agreements. See the NOTICE file distributed + * with this work for additional information regarding + * copyright ownership. JumpMind Inc licenses this file + * to you under the GNU General Public License, version 3.0 (GPLv3) + * (the "License"); you may not use this file except in compliance + * with the License. + * + * You should have received a copy of the GNU General Public License, + * version 3.0 (GPLv3) along with this library; if not, see + * . + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jumpmind.symmetric.db.generic; + +import java.util.HashMap; + +import org.jumpmind.symmetric.db.AbstractTriggerTemplate; +import org.jumpmind.symmetric.db.ISymmetricDialect; + +public class GenericTriggerTemplate extends AbstractTriggerTemplate { + + public GenericTriggerTemplate(ISymmetricDialect symmetricDialect) { + super(symmetricDialect); + + sqlTemplates = new HashMap(); + sqlTemplates.put("insertTriggerTemplate" , ""); + sqlTemplates.put("updateTriggerTemplate" , ""); + sqlTemplates.put("deleteTriggerTemplate" , ""); + sqlTemplates.put("initialLoadSqlTemplate" , "select $(columns) from $(schemaName)$(tableName) t where $(whereClause) " ); + } + +} diff --git a/symmetric-client/src/main/java/org/jumpmind/symmetric/db/voltdb/VoltDbSymmetricDialect.java b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/voltdb/VoltDbSymmetricDialect.java index edd56a67d0..ef37e72043 100644 --- a/symmetric-client/src/main/java/org/jumpmind/symmetric/db/voltdb/VoltDbSymmetricDialect.java +++ b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/voltdb/VoltDbSymmetricDialect.java @@ -24,9 +24,6 @@ import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.db.util.BinaryEncoding; import org.jumpmind.symmetric.db.AbstractSymmetricDialect; -import org.jumpmind.symmetric.db.ISymmetricDialect; -import org.jumpmind.symmetric.db.JdbcSymmetricDialectFactory; -import org.jumpmind.symmetric.db.postgresql.GreenplumTriggerTemplate; import org.jumpmind.symmetric.service.IParameterService; public class VoltDbSymmetricDialect extends AbstractSymmetricDialect { diff --git a/symmetric-client/src/main/java/org/jumpmind/symmetric/db/voltdb/VoltDbTriggerTemplate.java b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/voltdb/VoltDbTriggerTemplate.java index 3eb4ef61c1..8f3ba0c2de 100644 --- a/symmetric-client/src/main/java/org/jumpmind/symmetric/db/voltdb/VoltDbTriggerTemplate.java +++ b/symmetric-client/src/main/java/org/jumpmind/symmetric/db/voltdb/VoltDbTriggerTemplate.java @@ -39,34 +39,13 @@ public VoltDbTriggerTemplate(ISymmetricDialect symmetricDialect) { triggerConcatCharacter = "||" ; newTriggerValue = "" ; oldTriggerValue = "" ; -// timeColumnTemplate = null; -// dateColumnTemplate = null; -// clobColumnTemplate = "case when $(tableAlias)..\"$(columnName)\" is null then '' else '\"' || replace(replace($(tableAlias)..\"$(columnName)\",$$\\$$,$$\\\\$$),'\"',$$\\\"$$) || '\"' end" ; -// blobColumnTemplate = "case when $(tableAlias)..\"$(columnName)\" is null then '' else '\"' || pg_catalog.encode($(tableAlias)..\"$(columnName)\", 'base64') || '\"' end" ; -// wrappedBlobColumnTemplate = "case when $(tableAlias)..\"$(columnName)\" is null then '' else '\"' || $(defaultSchema)$(prefixName)_largeobject($(tableAlias)..\"$(columnName)\") || '\"' end" ; -// booleanColumnTemplate = "case when $(tableAlias)..\"$(columnName)\" is null then '' when $(tableAlias)..\"$(columnName)\" then '\"1\"' else '\"0\"' end" ; -// triggerConcatCharacter = "||" ; -// newTriggerValue = "new" ; -// oldTriggerValue = "old" ; -// oldColumnPrefix = "" ; -// newColumnPrefix = "" ; -// otherColumnTemplate = null; sqlTemplates = new HashMap(); sqlTemplates.put("insertTriggerTemplate" , ""); sqlTemplates.put("updateTriggerTemplate" , ""); sqlTemplates.put("deleteTriggerTemplate" , ""); - sqlTemplates.put("initialLoadSqlTemplate" , -"select $(columns) from $(schemaName)$(tableName) t where $(whereClause) " ); + sqlTemplates.put("initialLoadSqlTemplate" , "select $(columns) from $(schemaName)$(tableName) t where $(whereClause) " ); } -// -// sqlTemplates.put("deletePostTriggerTemplate" , -//"create trigger $(triggerName) after delete on $(schemaName)$(tableName) " + -//" for each row execute procedure $(schemaName)f$(triggerName)(); " ); -// -// sqlTemplates.put("initialLoadSqlTemplate" , -//"select $(columns) from $(schemaName)$(tableName) t where $(whereClause) " ); -// } } diff --git a/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataExtractorService.java b/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataExtractorService.java index c2e694cbba..433a93a071 100644 --- a/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataExtractorService.java +++ b/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataExtractorService.java @@ -959,7 +959,7 @@ protected boolean isPreviouslyExtracted(OutgoingBatch currentBatch) { protected boolean isRetry(OutgoingBatch currentBatch, Node remoteNode) { IStagedResource previouslyExtracted = getStagedResource(currentBatch); return previouslyExtracted != null && previouslyExtracted.exists() && previouslyExtracted.getState() != State.CREATE - && currentBatch.getStatus() != OutgoingBatch.Status.RS && remoteNode.isVersionGreaterThanOrEqualTo(3, 8, 0); + && currentBatch.getStatus() != OutgoingBatch.Status.RS && currentBatch.getSentCount() > 0 && remoteNode.isVersionGreaterThanOrEqualTo(3, 8, 0); } protected OutgoingBatch sendOutgoingBatch(ProcessInfo processInfo, Node targetNode, diff --git a/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataService.java b/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataService.java index 1314653f96..535de9cb09 100644 --- a/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataService.java +++ b/symmetric-core/src/main/java/org/jumpmind/symmetric/service/impl/DataService.java @@ -33,6 +33,7 @@ import java.util.Set; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.jumpmind.db.model.Table; @@ -1624,20 +1625,8 @@ protected Data createData(ISqlTransaction transaction, Trigger trigger, String w String rowData = null; String pkData = null; if (whereClause != null) { - rowData = (String) transaction.queryForObject(symmetricDialect - .createCsvDataSql(trigger, triggerHistory, engine - .getConfigurationService().getChannel(trigger.getChannelId()), - whereClause), String.class); - if (rowData != null) { - rowData = rowData.trim(); - } - pkData = (String) transaction.queryForObject(symmetricDialect - .createCsvPrimaryKeySql(trigger, triggerHistory, engine - .getConfigurationService().getChannel(trigger.getChannelId()), - whereClause), String.class); - if (pkData != null) { - pkData = pkData.trim(); - } + rowData = getCsvDataFor(transaction, trigger, triggerHistory, whereClause, false); + pkData = getCsvDataFor(transaction, trigger, triggerHistory, whereClause, true); } data = new Data(trigger.getSourceTableName(), DataEventType.UPDATE, rowData, pkData, triggerHistory, trigger.getChannelId(), null, null); @@ -1645,6 +1634,43 @@ protected Data createData(ISqlTransaction transaction, Trigger trigger, String w } return data; } + + protected String getCsvDataFor(ISqlTransaction transaction, Trigger trigger, TriggerHistory triggerHistory, String whereClause, boolean pkOnly) { + String data = null; + String sql = null; + try { + if (pkOnly) { + sql = symmetricDialect.createCsvPrimaryKeySql(trigger, triggerHistory, + engine.getConfigurationService().getChannel(trigger.getChannelId()), whereClause); + } else { + sql = symmetricDialect.createCsvDataSql(trigger, triggerHistory, + engine.getConfigurationService().getChannel(trigger.getChannelId()), whereClause); + } + } catch (NotImplementedException e) { + } + + if (isNotBlank(sql)) { + data = transaction.queryForObject(sql, String.class); + } else { + DatabaseInfo databaseInfo = platform.getDatabaseInfo(); + String quote = databaseInfo.getDelimiterToken() == null || !parameterService.is(ParameterConstants.DB_DELIMITED_IDENTIFIER_MODE) + ? "" : databaseInfo.getDelimiterToken(); + sql = "select " + triggerHistory.getColumnNames() + " from " + + Table.getFullyQualifiedTableName(triggerHistory.getSourceCatalogName(), triggerHistory.getSourceSchemaName(), + triggerHistory.getSourceTableName(), quote, databaseInfo.getCatalogSeparator(), + databaseInfo.getSchemaSeparator()) + " t where " + whereClause; + Row row = transaction.queryForRow(sql); + if (row != null) { + data = row.csvValue(); + } + } + + if (data != null) { + data = data.trim(); + } + + return data; + } public long countDataGapsByStatus(DataGap.Status status) { return sqlTemplate.queryForLong(getSql("countDataGapsByStatusSql"), new Object[] { status.name() }); diff --git a/symmetric-db/src/main/java/org/jumpmind/db/platform/DatabaseNamesConstants.java b/symmetric-db/src/main/java/org/jumpmind/db/platform/DatabaseNamesConstants.java index b5e016601e..be4c0c9ebd 100644 --- a/symmetric-db/src/main/java/org/jumpmind/db/platform/DatabaseNamesConstants.java +++ b/symmetric-db/src/main/java/org/jumpmind/db/platform/DatabaseNamesConstants.java @@ -25,6 +25,7 @@ final public class DatabaseNamesConstants { private DatabaseNamesConstants() { } + public final static String GENERIC = "generic"; public final static String H2 = "h2"; public final static String HSQLDB = "hsqldb"; public final static String HSQLDB2 = "hsqldb2"; diff --git a/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTransaction.java b/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTransaction.java index 885c593ad0..c37e39f640 100644 --- a/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTransaction.java +++ b/symmetric-db/src/main/java/org/jumpmind/db/sql/ISqlTransaction.java @@ -33,6 +33,8 @@ public interface ISqlTransaction { public T queryForObject(String sql, Class clazz, Object... args); + public Row queryForRow(String sql, Object... args); + public int queryForInt(String sql, Object... args); public long queryForLong(String sql, Object... args); diff --git a/symmetric-db/src/main/java/org/jumpmind/db/sql/RowMapper.java b/symmetric-db/src/main/java/org/jumpmind/db/sql/RowMapper.java new file mode 100644 index 0000000000..4512271b40 --- /dev/null +++ b/symmetric-db/src/main/java/org/jumpmind/db/sql/RowMapper.java @@ -0,0 +1,13 @@ +package org.jumpmind.db.sql; + +public class RowMapper implements ISqlRowMapper { + + public RowMapper() { + } + + @Override + public Row mapRow(Row row) { + return row; + } + +} diff --git a/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/DbExport.java b/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/DbExport.java index 9a08fe8cc4..93fc5112bb 100644 --- a/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/DbExport.java +++ b/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/DbExport.java @@ -65,7 +65,7 @@ public enum Format { }; public enum Compatible { - DB2, DERBY, FIREBIRD, FIREBIRD_DIALECT1, GREENPLUM, H2, HSQLDB, HSQLDB2, INFORMIX, INTERBASE, MSSQL, MSSQL2000, MSSQL2005, MSSQL2008, MYSQL, ORACLE, POSTGRES, SYBASE, SQLITE, MARIADB, ASE, SQLANYWHERE, REDSHIFT, VOLTDB + DB2, DERBY, FIREBIRD, FIREBIRD_DIALECT1, GREENPLUM, H2, HSQLDB, HSQLDB2, INFORMIX, INTERBASE, MSSQL, MSSQL2000, MSSQL2005, MSSQL2008, MYSQL, ORACLE, POSTGRES, SYBASE, SQLITE, MARIADB, ASE, SQLANYWHERE, REDSHIFT, VOLTDB, GENERIC }; private Format format = Format.SQL; diff --git a/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/writer/DefaultDatabaseWriter.java b/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/writer/DefaultDatabaseWriter.java index 21dcd78a83..9b3abb70a3 100644 --- a/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/writer/DefaultDatabaseWriter.java +++ b/symmetric-io/src/main/java/org/jumpmind/symmetric/io/data/writer/DefaultDatabaseWriter.java @@ -228,8 +228,8 @@ protected LoadStatus delete(CsvData data, boolean useConflictDetection) { lookupColumns.add(versionColumn); } else { log.error( - "Could not find the timestamp/version column with the name {}. Defaulting to using primary keys for the lookup.", - conflict.getDetectExpression()); + "Could not find the timestamp/version column with the name {} on table {}. Defaulting to using primary keys for the lookup.", + conflict.getDetectExpression(), targetTable.getName()); } Column[] pks = targetTable.getPrimaryKeyColumns(); for (Column column : pks) { @@ -376,8 +376,8 @@ protected LoadStatus update(CsvData data, boolean applyChangesOnly, boolean useC lookupColumns.add(versionColumn); } else { log.error( - "Could not find the timestamp/version column with the name {}. Defaulting to using primary keys for the lookup.", - conflict.getDetectExpression()); + "Could not find the timestamp/version column with the name {} on table {}. Defaulting to using primary keys for the lookup.", + conflict.getDetectExpression(), targetTable.getName()); } pks = targetTable.getPrimaryKeyColumns(); for (Column column : pks) { diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/JdbcDatabasePlatformFactory.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/JdbcDatabasePlatformFactory.java index eef859a96c..eb2e68abac 100644 --- a/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/JdbcDatabasePlatformFactory.java +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/JdbcDatabasePlatformFactory.java @@ -39,6 +39,7 @@ import org.jumpmind.db.platform.derby.DerbyDatabasePlatform; import org.jumpmind.db.platform.firebird.FirebirdDatabasePlatform; import org.jumpmind.db.platform.firebird.FirebirdDialect1DatabasePlatform; +import org.jumpmind.db.platform.generic.GenericJdbcDatabasePlatform; import org.jumpmind.db.platform.greenplum.GreenplumPlatform; import org.jumpmind.db.platform.h2.H2DatabasePlatform; import org.jumpmind.db.platform.hsqldb.HsqlDbDatabasePlatform; @@ -168,7 +169,7 @@ public static synchronized IDatabasePlatform createNewPlatformInstance(DataSourc protected static synchronized Class findPlatformClass( - String[] nameVersion) throws DdlException { + String[] nameVersion) { Class platformClass = platforms.get(String.format("%s%s", nameVersion[0], nameVersion[1]).toLowerCase()); @@ -181,11 +182,10 @@ protected static synchronized Class findPlatformCla } if (platformClass == null) { - throw new DdlException("Could not find platform for database " + nameVersion[0]); - } else { - return platformClass; - } - + platformClass = GenericJdbcDatabasePlatform.class; + } + + return platformClass; } protected static String[] determineDatabaseNameVersionSubprotocol(DataSource dataSource) diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcDatabasePlatform.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcDatabasePlatform.java new file mode 100644 index 0000000000..dcb05866a7 --- /dev/null +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcDatabasePlatform.java @@ -0,0 +1,49 @@ +package org.jumpmind.db.platform.generic; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.AbstractJdbcDatabasePlatform; +import org.jumpmind.db.platform.DatabaseNamesConstants; +import org.jumpmind.db.platform.IDdlBuilder; +import org.jumpmind.db.platform.IDdlReader; +import org.jumpmind.db.sql.ISqlTemplate; +import org.jumpmind.db.sql.SqlTemplateSettings; +import org.jumpmind.db.sql.SymmetricLobHandler; + +public class GenericJdbcDatabasePlatform extends AbstractJdbcDatabasePlatform { + + public GenericJdbcDatabasePlatform(DataSource dataSource, SqlTemplateSettings settings) { + super(dataSource, settings); + } + + @Override + public String getName() { + return DatabaseNamesConstants.GENERIC; + } + + @Override + public String getDefaultSchema() { + return null; + } + + @Override + public String getDefaultCatalog() { + return null; + } + + @Override + protected IDdlBuilder createDdlBuilder() { + return new GenericJdbcDdlBuilder(getName(), this); + } + + @Override + protected IDdlReader createDdlReader() { + return new GenericJdbcSqlDdlReader(this); + } + + @Override + protected ISqlTemplate createSqlTemplate() { + return new GenericJdbcSqlTemplate(dataSource, settings, new SymmetricLobHandler(), getDatabaseInfo()); + } + +} diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcDdlBuilder.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcDdlBuilder.java new file mode 100644 index 0000000000..f3a3fafb7e --- /dev/null +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcDdlBuilder.java @@ -0,0 +1,100 @@ +package org.jumpmind.db.platform.generic; + +import static org.apache.commons.lang.StringUtils.isNotBlank; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Iterator; +import java.util.List; + +import javax.sql.DataSource; + +import org.jumpmind.db.alter.ColumnAutoIncrementChange; +import org.jumpmind.db.alter.TableChange; +import org.jumpmind.db.model.Column; +import org.jumpmind.db.model.Database; +import org.jumpmind.db.model.Table; +import org.jumpmind.db.platform.AbstractDdlBuilder; +import org.jumpmind.db.platform.IDatabasePlatform; +import org.jumpmind.db.sql.JdbcSqlTemplate; +import org.jumpmind.db.sql.SqlException; + +public class GenericJdbcDdlBuilder extends AbstractDdlBuilder { + + public GenericJdbcDdlBuilder(String databaseName, IDatabasePlatform platform) { + super(databaseName); + + databaseInfo.setTriggersSupported(false); + databaseInfo.setForeignKeysSupported(false); + databaseInfo.setNullAsDefaultValueRequired(true); + databaseInfo.setHasNullDefault(Types.TIMESTAMP, true); + databaseInfo.setHasNullDefault(Types.DATE, true); + databaseInfo.setHasNullDefault(Types.TIME, true); + + DataSource ds = platform.getDataSource(); + Connection c = null; + try { + c = ds.getConnection(); + DatabaseMetaData meta = c.getMetaData(); + String quoteString = meta.getIdentifierQuoteString(); + if (isNotBlank(quoteString)) { + databaseInfo.setDelimiterToken(quoteString); + } else { + databaseInfo.setDelimitedIdentifiersSupported(false); + } + + if (!setNativeMapping(Types.LONGVARCHAR, meta, Types.LONGVARCHAR)) { + if (!setNativeMapping(Types.LONGVARCHAR, meta, Types.CLOB)) { + setNativeMapping(Types.LONGVARCHAR, meta, Types.VARCHAR); + } + } + + } catch (SQLException ex) { + throw new SqlException(ex); + } finally { + JdbcSqlTemplate.close(c); + } + } + + @Override + protected void writeColumnAutoIncrementStmt(Table table, Column column, StringBuilder ddl) { + /** + * Auto increment isn't supported for generic platforms + */ + } + + protected boolean setNativeMapping(int targetJdbcType, DatabaseMetaData meta, int acceptableType) throws SQLException { + ResultSet rs = null; + try { + rs = meta.getTypeInfo(); + while (rs.next()) { + String name = rs.getString("TYPE_NAME"); + int type = rs.getInt("DATA_TYPE"); + if (type == acceptableType) { + databaseInfo.addNativeTypeMapping(targetJdbcType, name, acceptableType); + return true; + } + } + } finally { + JdbcSqlTemplate.close(rs); + } + return false; + } + + protected void processTableStructureChanges(Database currentModel, Database desiredModel, + Table sourceTable, Table targetTable, List changes, StringBuilder ddl) { + for (Iterator changeIt = changes.iterator(); changeIt.hasNext();) { + TableChange change = changeIt.next(); + if (change instanceof ColumnAutoIncrementChange) { + /** + * Auto increment isn't supported for generic platforms + */ + changeIt.remove(); + } + } + } + +} diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcSqlDdlReader.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcSqlDdlReader.java new file mode 100644 index 0000000000..b0018a465e --- /dev/null +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcSqlDdlReader.java @@ -0,0 +1,23 @@ +package org.jumpmind.db.platform.generic; + +import java.sql.Connection; + +import org.jumpmind.db.model.IIndex; +import org.jumpmind.db.model.Table; +import org.jumpmind.db.platform.AbstractJdbcDdlReader; +import org.jumpmind.db.platform.DatabaseMetaDataWrapper; +import org.jumpmind.db.platform.IDatabasePlatform; + +public class GenericJdbcSqlDdlReader extends AbstractJdbcDdlReader { + + public GenericJdbcSqlDdlReader(IDatabasePlatform platform) { + super(platform); + } + + @Override + protected boolean isInternalPrimaryKeyIndex(Connection connection, + DatabaseMetaDataWrapper metaData, Table table, IIndex index) { + return "PRIMARY".equals(index.getName()); + } + +} diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcSqlTemplate.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcSqlTemplate.java new file mode 100644 index 0000000000..31cf7f7d77 --- /dev/null +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/generic/GenericJdbcSqlTemplate.java @@ -0,0 +1,66 @@ +package org.jumpmind.db.platform.generic; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import javax.sql.DataSource; + +import org.jumpmind.db.platform.DatabaseInfo; +import org.jumpmind.db.sql.JdbcSqlTemplate; +import org.jumpmind.db.sql.SqlTemplateSettings; +import org.jumpmind.db.sql.SymmetricLobHandler; + +public class GenericJdbcSqlTemplate extends JdbcSqlTemplate { + + public GenericJdbcSqlTemplate(DataSource dataSource, SqlTemplateSettings settings, SymmetricLobHandler lobHandler, + DatabaseInfo databaseInfo) { + super(dataSource, settings, lobHandler, databaseInfo); + } + + @Override + public boolean isUniqueKeyViolation(Throwable ex) { + SQLException sqlEx = findSQLException(ex); + return sqlEx.getClass().getName().equals("SQLIntegrityConstraintViolationException"); + } + + @Override + public boolean supportsGetGeneratedKeys() { + return false; + } + + @Override + protected long insertWithGeneratedKey(Connection conn, String sql, String column, + String sequenceName, Object[] args, int[] types) throws SQLException { + + long key = 0; + PreparedStatement ps = null; + try { + Statement st = null; + ResultSet rs = null; + try { + st = conn.createStatement(); + rs = st.executeQuery("select max(data_id)+1 from sym_data"); + if (rs.next()) { + key = rs.getLong(1); + } + } finally { + close(rs); + close(st); + } + + String replaceSql = sql.replaceFirst("\\(null,", "(" + key + ","); + ps = conn.prepareStatement(replaceSql); + ps.setQueryTimeout(settings.getQueryTimeout()); + setValues(ps, args, types, lobHandler.getDefaultHandler()); + ps.executeUpdate(); + } finally { + close(ps); + } + return key; + } + +} + \ No newline at end of file diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/voltdb/VoltDbDatabasePlatform.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/voltdb/VoltDbDatabasePlatform.java index bf1872c400..f745de54e9 100644 --- a/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/voltdb/VoltDbDatabasePlatform.java +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/platform/voltdb/VoltDbDatabasePlatform.java @@ -115,7 +115,6 @@ protected VoltDbDdlReader createDdlReader() { @Override protected VoltDbJdbcSqlTemplate createSqlTemplate() { - // TODO return new VoltDbJdbcSqlTemplate(dataSource, settings, new SymmetricLobHandler(), getDatabaseInfo()); } diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTemplate.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTemplate.java index de14bcfe50..53e4fffe0e 100644 --- a/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTemplate.java +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTemplate.java @@ -44,7 +44,6 @@ import java.util.Arrays; import java.util.Date; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTransaction.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTransaction.java index 34538e9afe..6d5bc15082 100644 --- a/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTransaction.java +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTransaction.java @@ -32,7 +32,6 @@ import java.util.List; import java.util.Map; -import org.apache.commons.lang.ArrayUtils; import org.jumpmind.db.model.Table; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -168,6 +167,16 @@ public int flush() { } return rowsUpdated; } + + @Override + public Row queryForRow(String sql, Object... args) { + List rows = query(sql, new RowMapper(), args, null); + if (rows.size() > 0) { + return rows.get(0); + } else { + return null; + } + } public int queryForInt(String sql, Object... args) { Integer val = queryForObject(sql, Integer.class, args);