Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
406 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
178 changes: 178 additions & 0 deletions
178
.../symmetric-core/src/main/java/org/jumpmind/symmetric/db/interbase/InterbaseDbDialect.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
/* | ||
* 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 Lesser General Public License (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library; if not, see | ||
* <http://www.gnu.org/licenses/>. | ||
* | ||
* 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.interbase; | ||
|
||
import org.jumpmind.symmetric.db.AbstractDbDialect; | ||
import org.jumpmind.symmetric.db.BinaryEncoding; | ||
import org.jumpmind.symmetric.db.IDbDialect; | ||
import org.jumpmind.symmetric.model.Trigger; | ||
import org.springframework.jdbc.UncategorizedSQLException; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
/** | ||
* Database dialect for <a href="http://www.embarcadero.com/products/interbase/">Interbase</a>. | ||
*/ | ||
|
||
public class InterbaseDbDialect extends AbstractDbDialect implements IDbDialect { | ||
|
||
static final String CONTEXT_TABLE_NAME = "context"; | ||
|
||
static final String CONTEXT_TABLE_CREATE = "create global temporary table %s (id varchar(30), context_value varchar(30)) on commit preserve rows"; | ||
|
||
static final String CONTEXT_TABLE_INSERT = "insert into %s (id, context_value) values (?, ?)"; | ||
|
||
static final String SYNC_TRIGGERS_DISABLED_USER_VARIABLE = "sync_triggers_disabled"; | ||
|
||
static final String SYNC_TRIGGERS_DISABLED_NODE_VARIABLE = "sync_node_disabled"; | ||
|
||
@Override | ||
protected void initTablesAndFunctionsForSpecificDialect() { | ||
String contextTableName = tablePrefix + "_" + CONTEXT_TABLE_NAME; | ||
try { | ||
jdbcTemplate.queryForInt("select count(*) from " + contextTableName); | ||
} catch (Exception e) { | ||
try { | ||
log.info("GlobalTempTableCreating", contextTableName); | ||
jdbcTemplate.execute(String.format(CONTEXT_TABLE_CREATE, contextTableName)); | ||
} catch (Exception ex) { | ||
log.error("InterbaseDialectInitializingError", ex); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
protected void createRequiredFunctions() { | ||
super.createRequiredFunctions(); | ||
try { | ||
jdbcTemplate.queryForObject("select sym_escape('') from rdb$database", String.class); | ||
} catch (UncategorizedSQLException e) { | ||
if (e.getSQLException().getErrorCode() == -804) { | ||
log.error("InterbaseSymUdfMissing"); | ||
} | ||
throw new RuntimeException("InterbaseSymEscapeMissing", e); | ||
} | ||
} | ||
|
||
@Override | ||
protected boolean doesTriggerExistOnPlatform(String catalogName, String schema, String tableName, String triggerName) { | ||
return jdbcTemplate.queryForInt("select count(*) from rdb$triggers where rdb$trigger_name = ?", | ||
new Object[] { triggerName.toUpperCase() }) > 0; | ||
} | ||
|
||
public void disableSyncTriggers(JdbcTemplate jdbcTemplate, String nodeId) { | ||
String contextTableName = tablePrefix + "_" + CONTEXT_TABLE_NAME; | ||
jdbcTemplate.update(String.format(CONTEXT_TABLE_INSERT, contextTableName), new Object[] { | ||
SYNC_TRIGGERS_DISABLED_USER_VARIABLE, "1" }); | ||
if (nodeId != null) { | ||
jdbcTemplate.update(String.format(CONTEXT_TABLE_INSERT, contextTableName), new Object[] { | ||
SYNC_TRIGGERS_DISABLED_NODE_VARIABLE, nodeId }); | ||
} | ||
} | ||
|
||
public void enableSyncTriggers(JdbcTemplate jdbcTemplate) { | ||
String contextTableName = tablePrefix + "_" + CONTEXT_TABLE_NAME; | ||
jdbcTemplate.update("delete from " + contextTableName); | ||
} | ||
|
||
public String getSyncTriggersExpression() { | ||
return ":" + SYNC_TRIGGERS_DISABLED_USER_VARIABLE + " is null"; | ||
} | ||
|
||
@Override | ||
public String getTransactionTriggerExpression(String defaultCatalog, String defaultSchema, Trigger trigger) { | ||
return "null"; | ||
} | ||
|
||
@Override | ||
protected String getTableNamePattern(String tableName) { | ||
/* | ||
* When looking up a table definition, Jaybird treats underscore (_) in | ||
* the table name as a wildcard, so it needs to be escaped, or you'll | ||
* get back column names for more than one table. Example: | ||
* DatabaseMetaData.metaData.getColumns(null, null, "SYM\\_NODE", null) | ||
*/ | ||
return tableName.replaceAll("\\_", "\\\\_"); | ||
} | ||
|
||
@Override | ||
public String getSelectLastInsertIdSql(String sequenceName) { | ||
return "select gen_id(gen_" + sequenceName + ", 0) from rdb$database"; | ||
} | ||
|
||
@Override | ||
public boolean isBlobSyncSupported() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public BinaryEncoding getBinaryEncoding() { | ||
return BinaryEncoding.HEX; | ||
} | ||
|
||
public boolean isNonBlankCharColumnSpacePadded() { | ||
return true; | ||
} | ||
|
||
public boolean isCharColumnSpaceTrimmed() { | ||
return false; | ||
} | ||
|
||
public boolean isEmptyStringNulled() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean storesUpperCaseNamesInCatalog() { | ||
return true; | ||
} | ||
|
||
@Override | ||
protected boolean allowsNullForIdentityColumn() { | ||
return true; | ||
} | ||
|
||
public void purge() { | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return super.getName(); | ||
} | ||
|
||
public String getDefaultCatalog() { | ||
return null; | ||
} | ||
|
||
@Override | ||
public boolean supportsOpenCursorsAcrossCommit() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean supportsTransactionId() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public void truncateTable(String tableName) { | ||
jdbcTemplate.update("delete from " + tableName); | ||
} | ||
} |
179 changes: 179 additions & 0 deletions
179
symmetric/symmetric-core/src/main/resources/org/jumpmind/symmetric/db/interbase.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<beans xmlns="http://www.springframework.org/schema/beans" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns:tx="http://www.springframework.org/schema/tx" | ||
xsi:schemaLocation=" | ||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd | ||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" default-lazy-init="true"> | ||
|
||
<bean id="interbaseDialect" class="org.jumpmind.symmetric.db.interbase.InterbaseDbDialect" | ||
scope="prototype"> | ||
<property name="tablePrefix" value="$[sym.sync.table.prefix]" /> | ||
<property name="parameterService" ref="parameterService" /> | ||
<property name="defaultSchema" value="$[sym.db.default.schema]" /> | ||
<property name="streamingResultsFetchSize" value="$[sym.db.jdbc.streaming.results.fetch.size]" /> | ||
<property name="sqlTemplate"> | ||
<bean class="org.jumpmind.symmetric.db.SqlTemplate"> | ||
|
||
<property name="functionInstalledSql"> | ||
<value> | ||
<![CDATA[select count(*) from rdb$functions where rdb$function_name = upper('$(functionName)')]]> | ||
</value> | ||
</property> | ||
<property name="functionTemplatesToInstall"> | ||
<map> | ||
<entry key="escape"> | ||
<value> | ||
declare external function $(functionName) cstring(32660) | ||
returns cstring(32660) free_it entry_point 'sym_escape' module_name 'sym_udf' | ||
</value> | ||
</entry> | ||
<entry key="hex"> | ||
<value> | ||
declare external function $(functionName) blob | ||
returns cstring(32660) free_it entry_point 'sym_hex' module_name 'sym_udf' | ||
</value> | ||
</entry> | ||
</map> | ||
</property> | ||
<property name="stringColumnTemplate" > | ||
<value> | ||
<![CDATA[case when $(tableAlias).$(columnName) is null then '' else '"' || $[sym.sync.table.prefix]_escape($(tableAlias).$(columnName)) || '"' end ]]> | ||
</value> | ||
</property> | ||
<property name="clobColumnTemplate"> | ||
<value> | ||
<![CDATA[case when $(tableAlias).$(columnName) is null then '' else '"' || $[sym.sync.table.prefix]_escape($(tableAlias).$(columnName)) || '"' end ]]> | ||
</value> | ||
</property> | ||
<property name="blobColumnTemplate"> | ||
<value> | ||
<![CDATA[case when $(tableAlias).$(columnName) is null then '' else '"' || $[sym.sync.table.prefix]_hex($(tableAlias).$(columnName)) || '"' end ]]> | ||
</value> | ||
</property> | ||
<property name="numberColumnTemplate"> | ||
<value> | ||
<![CDATA[case when $(tableAlias).$(columnName) is null then '' else '"' || $(tableAlias).$(columnName) || '"' end ]]> | ||
</value> | ||
</property> | ||
<property name="datetimeColumnTemplate" > | ||
<value> | ||
<![CDATA[case when $(tableAlias).$(columnName) is null then '' else '"' || $(tableAlias).$(columnName) || '"' end ]]> | ||
</value> | ||
</property> | ||
<property name="triggerConcatCharacter" value="||"/> | ||
<property name="newTriggerValue" value="new"/> | ||
<property name="oldTriggerValue" value="old"/> | ||
<property name="sqlTemplates"> | ||
<map> | ||
<entry key="insertTriggerTemplate"> | ||
<value> | ||
<![CDATA[ | ||
create trigger $(triggerName) for $(schemaName)$(tableName) after insert as | ||
declare variable id integer; | ||
declare variable sync_triggers_disabled varchar(30); | ||
declare variable sync_node_disabled varchar(30); | ||
begin | ||
select context_value from $(prefixName)_context where id = 'sync_triggers_disabled' into :sync_triggers_disabled; | ||
if ($(syncOnInsertCondition) and $(syncOnIncomingBatchCondition)) then | ||
begin | ||
select context_value from $(prefixName)_context where id = 'sync_node_disabled' into :sync_node_disabled; | ||
select gen_id($(defaultSchema)gen_$(prefixName)_data_data_id, 1) from rdb$database into :id; | ||
insert into $(defaultSchema)$(prefixName)_data | ||
(data_id, table_name, event_type, trigger_hist_id, row_data, channel_id, transaction_id, source_node_id, external_data, create_time) | ||
values( | ||
:id, | ||
'$(targetTableName)', | ||
'I', | ||
$(triggerHistoryId), | ||
$(columns), | ||
'$(channelName)', | ||
$(txIdExpression), | ||
:sync_node_disabled, | ||
$(externalSelect), | ||
CURRENT_TIMESTAMP | ||
); | ||
end | ||
end | ||
]]> | ||
</value> | ||
</entry> | ||
<entry key="updateTriggerTemplate"> | ||
<value> | ||
<![CDATA[ | ||
create trigger $(triggerName) for $(schemaName)$(tableName) after update as | ||
declare variable id integer; | ||
declare variable sync_triggers_disabled varchar(30); | ||
declare variable sync_node_disabled varchar(30); | ||
begin | ||
select context_value from $(prefixName)_context where id = 'sync_triggers_disabled' into :sync_triggers_disabled; | ||
if ($(syncOnUpdateCondition) and $(syncOnIncomingBatchCondition)) then | ||
begin | ||
select context_value from $(prefixName)_context where id = 'sync_node_disabled' into :sync_node_disabled; | ||
select gen_id($(defaultSchema)gen_$(prefixName)_data_data_id, 1) from rdb$database into :id; | ||
insert into $(defaultSchema)$(prefixName)_data | ||
(data_id, table_name, event_type, trigger_hist_id, pk_data, row_data, old_data, channel_id, transaction_id, source_node_id, external_data, create_time) | ||
values( | ||
:id, | ||
'$(targetTableName)', | ||
'U', | ||
$(triggerHistoryId), | ||
$(oldKeys), | ||
$(columns), | ||
$(oldColumns), | ||
'$(channelName)', | ||
$(txIdExpression), | ||
:sync_node_disabled, | ||
$(externalSelect), | ||
CURRENT_TIMESTAMP | ||
); | ||
end | ||
end | ||
]]> | ||
</value> | ||
</entry> | ||
<entry key="deleteTriggerTemplate"> | ||
<value> | ||
<![CDATA[ | ||
create trigger $(triggerName) for $(schemaName)$(tableName) after delete as | ||
declare variable id integer; | ||
declare variable sync_triggers_disabled varchar(30); | ||
declare variable sync_node_disabled varchar(30); | ||
begin | ||
select context_value from $(prefixName)_context where id = 'sync_triggers_disabled' into :sync_triggers_disabled; | ||
if ($(syncOnDeleteCondition) and $(syncOnIncomingBatchCondition)) then | ||
begin | ||
select context_value from $(prefixName)_context where id = 'sync_node_disabled' into :sync_node_disabled; | ||
select gen_id($(defaultSchema)gen_$(prefixName)_data_data_id, 1) from rdb$database into :id; | ||
insert into $(defaultSchema)$(prefixName)_data | ||
(data_id, table_name, event_type, trigger_hist_id, pk_data, old_data, channel_id, transaction_id, source_node_id, external_data, create_time) | ||
values( | ||
:id, | ||
'$(targetTableName)', | ||
'D', | ||
$(triggerHistoryId), | ||
$(oldKeys), | ||
$(oldColumns), | ||
'$(channelName)', | ||
$(txIdExpression), | ||
:sync_node_disabled, | ||
$(externalSelect), | ||
CURRENT_TIMESTAMP | ||
); | ||
end | ||
end | ||
]]> | ||
</value> | ||
</entry> | ||
<entry key="initialLoadSqlTemplate"> | ||
<value> | ||
<![CDATA[select $(columns) from $(schemaName)$(tableName) t where $(whereClause)]]> | ||
</value> | ||
</entry> | ||
</map> | ||
</property> | ||
</bean> | ||
</property> | ||
</bean> | ||
|
||
</beans> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.