diff --git a/symmetric/src/main/java/org/jumpmind/symmetric/db/AbstractDbDialect.java b/symmetric/src/main/java/org/jumpmind/symmetric/db/AbstractDbDialect.java index dd7459e157..d9f555250c 100644 --- a/symmetric/src/main/java/org/jumpmind/symmetric/db/AbstractDbDialect.java +++ b/symmetric/src/main/java/org/jumpmind/symmetric/db/AbstractDbDialect.java @@ -76,7 +76,7 @@ abstract public class AbstractDbDialect implements IDbDialect { protected String tablePrefix; private int streamingResultsFetchSize; - + private Boolean supportsGetGeneratedKeys; protected AbstractDbDialect() { @@ -96,6 +96,10 @@ protected AbstractDbDialect() { _defaultSizes.put(new Integer(2), "15,15"); } + protected boolean allowsNullForIdentityColumn() { + return true; + } + public String getDefaultCatalog() { return getDefaultSchema(); } @@ -130,7 +134,8 @@ public String getTransactionTriggerExpression() { public String createInitalLoadSqlFor(Node node, Trigger config) { return sqlTemplate.createInitalLoadSql(node, this, config, - getMetaDataFor(getDefaultCatalog(), config.getSourceSchemaName(), config.getSourceTableName(), true)).trim(); + getMetaDataFor(getDefaultCatalog(), config.getSourceSchemaName(), config.getSourceTableName(), true)) + .trim(); } public String createPurgeSqlFor(Node node, Trigger trig) { @@ -139,12 +144,14 @@ public String createPurgeSqlFor(Node node, Trigger trig) { public String createCsvDataSql(Trigger trig, String whereClause) { return sqlTemplate.createCsvDataSql(trig, - getMetaDataFor(getDefaultCatalog(), trig.getSourceSchemaName(), trig.getSourceTableName(), true), whereClause).trim(); + getMetaDataFor(getDefaultCatalog(), trig.getSourceSchemaName(), trig.getSourceTableName(), true), + whereClause).trim(); } public String createCsvPrimaryKeySql(Trigger trig, String whereClause) { return sqlTemplate.createCsvPrimaryKeySql(trig, - getMetaDataFor(getDefaultCatalog(), trig.getSourceSchemaName(), trig.getSourceTableName(), true), whereClause).trim(); + getMetaDataFor(getDefaultCatalog(), trig.getSourceSchemaName(), trig.getSourceTableName(), true), + whereClause).trim(); } /** @@ -341,27 +348,35 @@ public void initTrigger(final DataEventType dml, final Trigger trigger, final Tr public Object doInConnection(Connection con) throws SQLException, DataAccessException { String previousSourceSchema = trigger.getSourceSchemaName(); logger.info("Creating " + dml.toString() + " trigger for " - + (previousSourceSchema != null ? (previousSourceSchema + ".") : "") + trigger.getSourceTableName()); + + (previousSourceSchema != null ? (previousSourceSchema + ".") : "") + + trigger.getSourceTableName()); String previousCatalog = null; try { previousCatalog = switchSchemasForTriggerInstall(previousSourceSchema, con); Statement stmt = con.createStatement(); - stmt.executeUpdate(createTriggerDDL(dml, trigger, audit, tablePrefix, table)); + String triggerSql = createTriggerDDL(dml, trigger, audit, tablePrefix, table); + try { + stmt.executeUpdate(triggerSql); + } catch (SQLException ex) { + logger.error("Failed to create trigger: " + triggerSql); + throw ex; + } String postTriggerDml = createPostTriggerDDL(dml, trigger, audit, tablePrefix, table); if (postTriggerDml != null) { stmt.executeUpdate(postTriggerDml); } stmt.close(); + } finally { if (previousSourceSchema != null && !previousSourceSchema.equalsIgnoreCase(previousCatalog)) { - switchSchemasForTriggerInstall(previousCatalog, con); + switchSchemasForTriggerInstall(previousCatalog, con); } } return null; } }); } - + /** * Provide the option switch a connection's schema for trigger installation. */ @@ -384,8 +399,8 @@ public String getCreateSymmetricDDL() { prefixConfigDatabase(db); return platform.getCreateTablesSql(db, true, true); } - - protected boolean prefixConfigDatabase(Database targetTables) { + + protected boolean prefixConfigDatabase(Database targetTables) { try { String tblPrefix = this.tablePrefix.toLowerCase() + "_"; @@ -400,7 +415,7 @@ protected boolean prefixConfigDatabase(Database targetTables) { createTables = true; } } - + return createTables; } catch (CloneNotSupportedException e) { throw new RuntimeException(e); @@ -489,7 +504,7 @@ public String getSelectLastInsertIdSql(String sequenceName) { public long insertWithGeneratedKey(final String sql, final String sequenceName) { return insertWithGeneratedKey(sql, sequenceName, null); } - + public long insertWithGeneratedKey(final String sql, final String sequenceName, final PreparedStatementCallback callback) { return (Long) jdbcTemplate.execute(new ConnectionCallback() { @@ -497,7 +512,7 @@ public Object doInConnection(Connection conn) throws SQLException, DataAccessExc long key = 0; PreparedStatement ps = null; boolean supportsGetGeneratedKeys = supportsGetGeneratedKeys(); - if (supportsGetGeneratedKeys) { + if (allowsNullForIdentityColumn()) { ps = conn.prepareStatement(sql, new int[] { 1 }); } else { String replaceSql = sql.replaceFirst("\\(\\w*,", "(").replaceFirst("\\(null,", "("); diff --git a/symmetric/src/main/java/org/jumpmind/symmetric/db/SqlScript.java b/symmetric/src/main/java/org/jumpmind/symmetric/db/SqlScript.java index f4903832e0..186fb9fb1f 100644 --- a/symmetric/src/main/java/org/jumpmind/symmetric/db/SqlScript.java +++ b/symmetric/src/main/java/org/jumpmind/symmetric/db/SqlScript.java @@ -99,6 +99,7 @@ private void executeScript(Statement st) throws SQLException { st.execute(sql.toString()); } catch (SQLException e) { if (failOnError) { + logger.error(sql.toString() + " failed to execute.", e); throw e; } else { logger.warn(e.getMessage() + ": " + sql.toString()); diff --git a/symmetric/src/main/java/org/jumpmind/symmetric/db/SqlTemplate.java b/symmetric/src/main/java/org/jumpmind/symmetric/db/SqlTemplate.java index e3083843bd..978d95af5d 100644 --- a/symmetric/src/main/java/org/jumpmind/symmetric/db/SqlTemplate.java +++ b/symmetric/src/main/java/org/jumpmind/symmetric/db/SqlTemplate.java @@ -147,8 +147,11 @@ public String createTriggerDDL(IDbDialect dialect, DataEventType dml, Trigger tr columns = metaData.getPrimaryKeyColumns(); columnsText = buildColumnString(oldTriggerValue, columns); ddl = replace("oldKeys", columnsText, ddl); - ddl = replace("oldNewPrimaryKeyJoin", oldNewPrimaryKeyJoin(columns), ddl); + + // replace $(newTriggerValue) and $(oldTriggerValue) + ddl = replace("newTriggerValue", newTriggerValue, ddl); + ddl = replace("oldTriggerValue", oldTriggerValue, ddl); return ddl; } diff --git a/symmetric/src/main/java/org/jumpmind/symmetric/db/mssql/MsSqlDbDialect.java b/symmetric/src/main/java/org/jumpmind/symmetric/db/mssql/MsSqlDbDialect.java index ffec221d8b..3476e0d54b 100644 --- a/symmetric/src/main/java/org/jumpmind/symmetric/db/mssql/MsSqlDbDialect.java +++ b/symmetric/src/main/java/org/jumpmind/symmetric/db/mssql/MsSqlDbDialect.java @@ -37,6 +37,10 @@ public class MsSqlDbDialect extends AbstractDbDialect implements IDbDialect { protected void initForSpecificDialect() { } + + protected boolean allowsNullForIdentityColumn() { + return false; + } @Override protected boolean doesTriggerExistOnPlatform(String schema, String tableName, String triggerName) { diff --git a/symmetric/src/main/java/org/jumpmind/symmetric/db/postgresql/PostgreSqlDbDialect.java b/symmetric/src/main/java/org/jumpmind/symmetric/db/postgresql/PostgreSqlDbDialect.java index c6d537cf3f..032426a348 100644 --- a/symmetric/src/main/java/org/jumpmind/symmetric/db/postgresql/PostgreSqlDbDialect.java +++ b/symmetric/src/main/java/org/jumpmind/symmetric/db/postgresql/PostgreSqlDbDialect.java @@ -48,6 +48,10 @@ protected void initForSpecificDialect() { logger.error("Error while initializing PostgreSql.", e); } } + + protected boolean allowsNullForIdentityColumn() { + return false; + } private URL getTransactionIdSqlUrl() { return getClass().getResource("/dialects/postgresql-transactionid.sql"); diff --git a/symmetric/src/main/resources/dialects/mssql.xml b/symmetric/src/main/resources/dialects/mssql.xml index 23311681e4..d290ef48c4 100644 --- a/symmetric/src/main/resources/dialects/mssql.xml +++ b/symmetric/src/main/resources/dialects/mssql.xml @@ -22,14 +22,12 @@ - - @@ -38,7 +36,7 @@ - + @@ -61,7 +59,7 @@ insert into $(defaultSchema)$(prefixName)_data (table_name, channel_id, event_type, trigger_hist_id, transaction_id, row_data, create_time) (select '$(targetTableName)','$(channelName)','I', $(triggerHistoryId), $(txIdExpression), $(columns), current_timestamp from inserted where $(syncOnInsertCondition)); insert into $(defaultSchema)$(prefixName)_data_event (node_id, data_id) (select node_id, @@IDENTITY from $(defaultSchema)$(prefixName)_node c where - $(syncOnInsertCondition) and c.node_group_id='$(targetGroupId)' and c.sync_enabled=1 $(nodeSelectWhere)); + c.node_group_id='$(targetGroupId)' and c.sync_enabled=1 $(nodeSelectWhere)); end end ]]> @@ -87,7 +85,7 @@ update $(defaultSchema)$(prefixName)_data set pk_data=@OldKeys where data_id=@@IDENTITY; end insert into $(defaultSchema)$(prefixName)_data_event (node_id, data_id) (select node_id, @@IDENTITY from $(defaultSchema)$(prefixName)_node c where - $(syncOnUpdateCondition) and c.node_group_id='$(targetGroupId)' and c.sync_enabled=1 $(nodeSelectWhere)); + c.node_group_id='$(targetGroupId)' and c.sync_enabled=1 $(nodeSelectWhere)); end end ]]> @@ -106,9 +104,9 @@ $(syncOnIncomingBatchCondition) if (@SyncEnabled <> 0x1) begin insert into $(defaultSchema)$(prefixName)_data (table_name, channel_id, event_type, trigger_hist_id, transaction_id, pk_data, create_time) - (select '$(targetTableName)','$(channelName)','D', $(triggerHistoryId), $(txIdExpression), $(oldKeys), current_timestamp from deleted where $(syncOnUpdateCondition)); + (select '$(targetTableName)','$(channelName)','D', $(triggerHistoryId), $(txIdExpression), $(oldKeys), current_timestamp from deleted where $(syncOnDeleteCondition)); insert into $(defaultSchema)$(prefixName)_data_event (node_id, data_id) (select node_id, @@IDENTITY from $(defaultSchema)$(prefixName)_node c where - $(syncOnUpdateCondition) and c.node_group_id='$(targetGroupId)' and c.sync_enabled=1 $(nodeSelectWhere)); + c.node_group_id='$(targetGroupId)' and c.sync_enabled=1 $(nodeSelectWhere)); end end ]]> diff --git a/symmetric/src/main/resources/symmetric-services.xml b/symmetric/src/main/resources/symmetric-services.xml index 08467ca1b0..127f8d51f8 100644 --- a/symmetric/src/main/resources/symmetric-services.xml +++ b/symmetric/src/main/resources/symmetric-services.xml @@ -457,7 +457,7 @@ - update ${sync.table.prefix}_node c set sync_enabled = '1', sync_url = ?, + update ${sync.table.prefix}_node set sync_enabled = '1', sync_url = ?, schema_version = ?, database_type = ?, database_version = ?, symmetric_version = ? where node_id = ? diff --git a/symmetric/src/test/java/org/jumpmind/symmetric/SymmetricEngineTestFactory.java b/symmetric/src/test/java/org/jumpmind/symmetric/SymmetricEngineTestFactory.java index 924a8c0afa..cc3503208f 100644 --- a/symmetric/src/test/java/org/jumpmind/symmetric/SymmetricEngineTestFactory.java +++ b/symmetric/src/test/java/org/jumpmind/symmetric/SymmetricEngineTestFactory.java @@ -54,7 +54,8 @@ public class SymmetricEngineTestFactory { static final String ENGINE_2_PROPERTIES = "symmetric-mysql-engine-2.properties"; static final String ORACLE_ENGINE_1_PROPERTIES = "symmetric-oracle-engine-1.properties"; - + + public static SymmetricEngine getMySqlTestEngine1(String engineScript) { if (mySqlEngine1 == null) { diff --git a/symmetric/src/test/java/org/jumpmind/symmetric/TestFactory.java b/symmetric/src/test/java/org/jumpmind/symmetric/TestFactory.java new file mode 100644 index 0000000000..77e76c2f9d --- /dev/null +++ b/symmetric/src/test/java/org/jumpmind/symmetric/TestFactory.java @@ -0,0 +1,13 @@ +package org.jumpmind.symmetric; + +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +@Test(groups="integrationx") +public class TestFactory { + + @Factory + public Object[] createTests() { + return new Object[] {}; + } +} diff --git a/symmetric/src/test/resources/test-continuous-setup.sql b/symmetric/src/test/resources/test-continuous-setup.sql index 33c4417b33..5d1ecee290 100644 --- a/symmetric/src/test/resources/test-continuous-setup.sql +++ b/symmetric/src/test/resources/test-continuous-setup.sql @@ -28,12 +28,13 @@ insert into sym_trigger values('sym_node_group','symmetric','test-root-group','config', 1, 1, 1, null, null, null, null, null, null, 1, 'chenson', current_timestamp, current_timestamp); insert into test_dataloader_table -(id, string_value, string_required_value, char_value, char_required_value, +(string_value, string_required_value, char_value, char_required_value, date_value, time_value, boolean_value, integer_value, decimal_value) -values (1, 'string', 'string not null', 'char', 'char not null', +values ('string', 'string not null', 'char', 'char not null', {d '2007-02-03'}, {ts '2007-01-02 03:04:05.06'}, '1', 42, 99.99); + insert into test_dataloader_table -(id, string_value, string_required_value, char_value, char_required_value, +(string_value, string_required_value, char_value, char_required_value, date_value, time_value, boolean_value, integer_value, decimal_value) -values (5, 'string', 'string not null', 'char', 'char not null', +values ('string', 'string not null', 'char', 'char not null', {d '2007-02-03'}, {ts '2007-01-02 03:04:05.06'}, '1', 42, 99.99); \ No newline at end of file diff --git a/symmetric/src/test/resources/test-integration-root-setup.sql b/symmetric/src/test/resources/test-integration-root-setup.sql index 676a665265..060469f70a 100644 --- a/symmetric/src/test/resources/test-integration-root-setup.sql +++ b/symmetric/src/test/resources/test-integration-root-setup.sql @@ -22,7 +22,7 @@ values('test_order_header','test-node-group','test-root-group','testchannel', 1, insert into sym_trigger (source_table_name,source_node_group_id,target_node_group_id,channel_id,sync_on_update,sync_on_insert,sync_on_delete,sync_on_update_condition,sync_on_insert_condition,sync_on_delete_condition,initial_load_select,node_select,tx_id_expression,initial_load_order,last_updated_by,last_updated_time,name_for_insert_trigger,create_time) -values('test_order_header','test-root-group','test-node-group','testchannel', 1, 1, 1,'new.status = \'C\'', 'new.status = \'C\'', null, null, null, null, 1, 'erilong', current_timestamp,null,current_timestamp); +values('test_order_header','test-root-group','test-node-group','testchannel', 1, 1, 1,'$(newTriggerValue).status = ''C''', '$(newTriggerValue).status = ''C''', null, null, null, null, 1, 'erilong', current_timestamp,null,current_timestamp); insert into sym_trigger (source_table_name,source_node_group_id,target_node_group_id,channel_id,sync_on_update,sync_on_insert,sync_on_delete,sync_on_update_condition,sync_on_insert_condition,sync_on_delete_condition,initial_load_select,node_select,tx_id_expression,initial_load_order,last_updated_by,last_updated_time,name_for_insert_trigger,create_time)