1 /*
2 * $Source$
3 * $Revision$
4 *
5 * Copyright (C) 2002 Tim Pizey
6 *
7 * Part of Melati (http://melati.org), a framework for the rapid
8 * development of clean, maintainable web applications.
9 *
10 * Melati is free software; Permission is granted to copy, distribute
11 * and/or modify this software under the terms either:
12 *
13 * a) the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option)
15 * any later version,
16 *
17 * or
18 *
19 * b) any version of the Melati Software License, as published
20 * at http://melati.org
21 *
22 * You should have received a copy of the GNU General Public License and
23 * the Melati Software License along with this program;
24 * if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26 * GNU General Public License and visit http://melati.org to obtain the
27 * Melati Software License.
28 *
29 * Feel free to contact the Developers of Melati (http://melati.org),
30 * if you would like to work out a different arrangement than the options
31 * outlined here. It is our intention to allow Melati to be used by as
32 * wide an audience as possible.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * Contact details for copyright holder:
40 *
41 * Tim Pizey (timp At paneris.org)
42 *
43 */
44
45 package org.melati.poem.dbms;
46
47 import java.sql.Connection;
48 import java.sql.Statement;
49 import java.sql.SQLException;
50
51 import org.melati.poem.BinaryPoemType;
52 import org.melati.poem.Column;
53 import org.melati.poem.PoemType;
54 import org.melati.poem.StringPoemType;
55 import org.melati.poem.Table;
56 import org.melati.poem.util.StringUtils;
57
58 /**
59 * A Driver for HSQLDB (http://www.hsqldb.org/).
60 *
61 * Note that HSQLDB uppercases any name that isn't quoted.
62 *
63 **/
64
65 public class Hsqldb extends AnsiStandard {
66
67 // 2010/10/25 Have experienced issues with records no being committed
68 // st.execute("SET WRITE_DELAY FALSE");
69 // had no effect
70
71 /**
72 * HSQLDB does not have a pleasant <code>TEXT</code>
73 * datatype, so we use an arbitrary value in a
74 * <code>VARCHAR</code>.
75 */
76 public static int hsqldbTextHack = 266;
77 // Version 2.2.8 introduces a text field
78 public static int hsqldbTextSize1 = 1048576;
79 public static int hsqldbTextSize2 = 16777216;
80
81 /**
82 * Constructor.
83 */
84 public Hsqldb() {
85 setDriverClassName("org.hsqldb.jdbcDriver");
86 }
87
88 /**
89 * Shut the db down nicely.
90 */
91 @Override
92 public void shutdown(Connection connection) throws SQLException {
93 if (!connection.isClosed()) {
94 Statement st = connection.createStatement();
95 try {
96 st.execute("SHUTDOWN SCRIPT");
97 } catch (SQLException e) {
98 // This seems to be caused by a shutdownhook race
99 if (!e.getMessage().equals("Access is denied: Session is closed"))
100 throw e;
101 } finally {
102 st.close();
103 }
104 }
105 }
106
107 /**
108 * The default is to keep everything in memory,
109 * this allows for the db to be written to the disk.
110 *
111 */
112 @Override
113 public String createTableTypeQualifierSql(Table<?> table) {
114 String tableType;
115 if (table == null || table.getDbmsTableType() == null)
116 tableType = "CACHED ";
117 else
118 tableType = table.getDbmsTableType() + " ";
119
120 return tableType;
121 }
122
123 /*
124 * 0.7.2 and earlier did not have a Boolean type;
125 * there is one in 0.7.3 onwards.
126 *
127 * @see org.melati.poem.dbms.Dbms#getSqlDefinition(java.lang.String)
128 */
129
130 /*
131 public String getSqlDefinition(String sqlTypeName) {
132 if (sqlTypeName.equals("BOOLEAN")) {
133 return ("BIT");
134 }
135 return super.getSqlDefinition(sqlTypeName);
136 }
137 */
138 /**
139 * @see org.melati.poem.dbms.AnsiStandard#getStringSqlDefinition(int)
140 */
141 @Override
142 public String getStringSqlDefinition(int size) {
143 if (size < 0)
144 return "LONGVARCHAR";
145 //return "VARCHAR(" + hsqldbTextHack + ")";
146 return "VARCHAR(" + size + ")";
147 }
148
149 /**
150 * {@inheritDoc}
151 * @see org.melati.poem.dbms.AnsiStandard#getLongSqlDefinition()
152 */
153 @Override
154 public String getLongSqlDefinition() {
155 return "BIGINT";
156 }
157
158 /**
159 * {@inheritDoc}
160 * @see org.melati.poem.dbms.AnsiStandard#getBinarySqlDefinition(int)
161 */
162 @Override
163 public String getBinarySqlDefinition(int size) throws SQLException {
164 return "LONGVARBINARY";
165 }
166
167 /**
168 * Accommodate our String size hack.
169 * {@inheritDoc}
170 * @see org.melati.poem.dbms.AnsiStandard#canRepresent
171 */
172 @Override
173 public <S,O>PoemType<O> canRepresent(PoemType<S> storage, PoemType<O> type) {
174 if (storage instanceof StringPoemType && type instanceof StringPoemType) {
175 if (
176 (((StringPoemType)storage).getSize() == hsqldbTextHack
177 ||
178 ((StringPoemType)storage).getSize() == hsqldbTextSize1
179 ||
180 ((StringPoemType)storage).getSize() == hsqldbTextSize2
181 )
182 && ((StringPoemType)type).getSize() == -1
183 && !(!storage.getNullable() && type.getNullable()) // Nullable may represent not nullable
184 ) {
185 return type;
186 } else {
187 return storage.canRepresent(type);
188 }
189 } else if (storage instanceof BinaryPoemType && type instanceof BinaryPoemType) {
190 if (
191 (
192 (((BinaryPoemType)storage).getSize() == 0)
193 ||
194 (((BinaryPoemType)storage).getSize() > ((BinaryPoemType)type).getSize())
195 )
196 &&
197 !(!storage.getNullable() && type.getNullable()) // Nullable may represent not nullable
198 ) {
199 return type;
200 } else {
201 return storage.canRepresent(type);
202 }
203 } else {
204 return super.canRepresent(storage, type);
205 }
206 }
207
208 /**
209 * {@inheritDoc}
210 * @see org.melati.poem.dbms.AnsiStandard#unreservedName(java.lang.String)
211 */
212 @Override
213 public String unreservedName(String name) {
214 if(name.equalsIgnoreCase("UNIQUE")) name = "MELATI_" + name.toUpperCase();
215 if(name.equalsIgnoreCase("CONSTRAINT")) name = "MELATI_" + name.toUpperCase();
216 //if(name.equalsIgnoreCase("USERS")) name = "MELATI_" + name.toUpperCase();
217 return name.toUpperCase();
218 }
219
220 /**
221 * {@inheritDoc}
222 * @see org.melati.poem.dbms.AnsiStandard#melatiName(java.lang.String)
223 */
224 @Override
225 public String melatiName(String name) {
226 if (name == null) return name;
227 if(name.equalsIgnoreCase("MELATI_UNIQUE")) name = "UNIQUE";
228 if(name.equalsIgnoreCase("MELATI_CONSTRAINT")) name = "CONSTRAINT";
229 //if(name.equalsIgnoreCase("MELATI_USERS")) name = "USERS";
230 return name.toLowerCase();
231 }
232
233 /**
234 * Note that this is NOT case insensitive.
235 *
236 * {@inheritDoc}
237 *
238 * @see org.melati.poem.dbms.Dbms#caseInsensitiveRegExpSQL
239 */
240 @Override
241 public String caseInsensitiveRegExpSQL(String term1, String term2) {
242 if (StringUtils.isQuoted(term2)) {
243 term2 = term2.substring(1, term2.length() - 1);
244 }
245 term2 = StringUtils.quoted(StringUtils.quoted(term2, '%'), '\'');
246
247 return term1 + " LIKE " + term2;
248 }
249
250 /**
251 * {@inheritDoc}
252 * @see org.melati.poem.dbms.AnsiStandard#getForeignKeyDefinition
253 */
254 @Override
255 public String getForeignKeyDefinition(String tableName, String fieldName,
256 String targetTableName,
257 String targetTableFieldName,
258 String fixName) {
259 StringBuffer sb = new StringBuffer();
260 sb.append(" ADD FOREIGN KEY (" + getQuotedName(fieldName) + ") REFERENCES " +
261 getQuotedName(targetTableName) +
262 "(" + getQuotedName(targetTableFieldName) + ")");
263 // Not currently implemented by hsqldb,
264 //another reason for not using the DB to control these things
265 //if (fixName.equals("prevent"))
266 // sb.append(" ON DELETE NO ACTION");
267 // There is an "ON DELETE SET DEFAULT"
268
269 if (fixName.equals("delete"))
270 sb.append(" ON DELETE CASCADE");
271 if (fixName.equals("clear"))
272 sb.append(" ON DELETE SET NULL");
273
274 return sb.toString();
275 }
276
277 /**
278 * Bad smell.
279 * {@inheritDoc}
280 * @see org.melati.poem.dbms.AnsiStandard#getJdbcMetadataName(java.lang.String)
281 */
282 @Override
283 public String getJdbcMetadataName(String name) {
284 return name.toUpperCase();
285 }
286 /**
287 * Our current version does not honour COMMENT.
288 */
289 @Override
290 public String alterColumnAddCommentSQL(Column<?> column, String comment) {
291 return null;
292 }
293
294 }