1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.jumpmind.symmetric.db.hsqldb;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.ddlutils.model.Table;
26 import org.jumpmind.symmetric.db.AbstractDbDialect;
27 import org.jumpmind.symmetric.db.BinaryEncoding;
28 import org.jumpmind.symmetric.db.IDbDialect;
29 import org.jumpmind.symmetric.model.Trigger;
30 import org.jumpmind.symmetric.model.TriggerHistory;
31
32 public class HsqlDbDialect extends AbstractDbDialect implements IDbDialect {
33
34 static final Log logger = LogFactory.getLog(HsqlDbDialect.class);
35
36 public static String DUAL_TABLE = "DUAL";
37
38 private boolean initializeDatabase;
39
40 private boolean charFieldTrimmed = false;
41
42 private static boolean hsqldbInitialized = false;
43
44 ThreadLocal<Boolean> syncEnabled = new ThreadLocal<Boolean>() {
45 @Override
46 protected Boolean initialValue() {
47 return Boolean.TRUE;
48 }
49
50 };
51
52 ThreadLocal<String> syncNodeDisabled = new ThreadLocal<String>() {
53 @Override
54 protected String initialValue() {
55 return null;
56 }
57 };
58
59 protected void initForSpecificDialect() {
60 if (initializeDatabase) {
61 if (!hsqldbInitialized) {
62 jdbcTemplate.update("SET WRITE_DELAY 100 MILLIS");
63 jdbcTemplate.update("SET PROPERTY \"hsqldb.default_table_type\" 'cached'");
64 jdbcTemplate.update("SET PROPERTY \"sql.enforce_strict_size\" true");
65 Runtime.getRuntime().addShutdownHook(new Thread() {
66
67 @Override
68 public void run() {
69 jdbcTemplate.update("SHUTDOWN");
70 }
71 });
72 hsqldbInitialized = true;
73 }
74 }
75
76 createDummyDualTable();
77
78 charFieldTrimmed = jdbcTemplate
79 .queryForInt("select count(*) from INFORMATION_SCHEMA.SYSTEM_PROPERTIES where property_name='sql.enforce_strict_size' and property_value='true'") == 1;
80
81 if (jdbcTemplate
82 .queryForInt("select count(*) from INFORMATION_SCHEMA.SYSTEM_ALIASES where ALIAS='BASE64_ENCODE'") == 0) {
83 jdbcTemplate
84 .update("CREATE ALIAS BASE64_ENCODE for \"org.jumpmind.symmetric.db.hsqldb.HsqlDbFunctions.encodeBase64\"");
85 }
86 }
87
88 /***
89 * This is for use in the java triggers so we can create a virtual table w/
90 * old and new columns values to bump SQL expressions up against.
91 */
92 private void createDummyDualTable() {
93 Table table = getMetaDataFor(null, null, DUAL_TABLE, false);
94 if (table == null) {
95 jdbcTemplate.update("CREATE MEMORY TABLE " + DUAL_TABLE + "(DUMMY VARCHAR(1))");
96 jdbcTemplate.update("INSERT INTO " + DUAL_TABLE + " VALUES(NULL)");
97 jdbcTemplate.update("SET TABLE " + DUAL_TABLE + " READONLY TRUE");
98 }
99
100 }
101
102 protected boolean doesTriggerExistOnPlatform(String catalogName, String schema, String tableName, String triggerName) {
103 schema = schema == null ? (getDefaultSchema() == null ? null : getDefaultSchema()) : schema;
104 return jdbcTemplate.queryForInt(
105 "select count(*) from INFORMATION_SCHEMA.SYSTEM_TRIGGERS where trigger_name = ?",
106 new Object[] { triggerName }) > 0;
107 }
108
109 public void removeTrigger(String schemaName, String triggerName, TriggerHistory hist) {
110 schemaName = schemaName == null ? "" : (schemaName + ".");
111 triggerName = schemaName + triggerName;
112 try {
113 jdbcTemplate.update(new String("drop trigger " + triggerName + "_" + getEngineName() + "_" + hist.getTriggerHistoryId()).toUpperCase());
114 } catch (Exception e) {
115 logger.warn("Error removing " + triggerName + ": " + e.getMessage());
116 }
117 }
118
119 public void removeTrigger(String catalogName, String schemaName, String triggerName, String tableName, TriggerHistory oldHistory) {
120 removeTrigger(schemaName, triggerName, oldHistory);
121 }
122
123 public boolean isBlobSyncSupported() {
124 return true;
125 }
126
127 public boolean isClobSyncSupported() {
128 return true;
129 }
130
131 public boolean isSyncEnabled() {
132 return syncEnabled.get();
133 }
134
135 public String getSyncNodeDisabled() {
136 return syncNodeDisabled.get();
137 }
138
139 public void disableSyncTriggers(String nodeId) {
140 syncEnabled.set(Boolean.FALSE);
141 syncNodeDisabled.set(nodeId);
142 }
143
144 public void enableSyncTriggers() {
145 syncEnabled.set(Boolean.TRUE);
146 syncNodeDisabled.set(null);
147 }
148
149 public String getSyncTriggersExpression() {
150 return "1 = 1";
151 }
152
153 /***
154 * This is not used by the HSQLDB Java triggers
155 */
156 public String getTransactionTriggerExpression(Trigger trigger) {
157 return "not used";
158 }
159
160 public String getSelectLastInsertIdSql(String sequenceName) {
161 return "call IDENTITY()";
162 }
163
164 @Override
165 public BinaryEncoding getBinaryEncoding() {
166 return BinaryEncoding.BASE64;
167 }
168
169 public boolean isCharSpacePadded() {
170 return charFieldTrimmed;
171 }
172
173 public boolean isCharSpaceTrimmed() {
174 return false;
175 }
176
177 public boolean isEmptyStringNulled() {
178 return false;
179 }
180
181 public boolean storesUpperCaseNamesInCatalog() {
182 return true;
183 }
184
185 public boolean supportsGetGeneratedKeys() {
186 return false;
187 }
188
189 protected boolean allowsNullForIdentityColumn() {
190 return false;
191 }
192
193 public void purge() {
194 }
195
196 public String getDefaultCatalog() {
197 return null;
198 }
199
200 public String getDefaultSchema() {
201 return null;
202 }
203
204 public void setInitializeDatabase(boolean initializeDatabase) {
205 this.initializeDatabase = initializeDatabase;
206 }
207 }