001: /*
002: * Copyright (C) 2006 Rob Manning
003: * manningr@users.sourceforge.net
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * as published by the Free Software Foundation; either version 2
008: * of the License, or any later version.
009: *
010: * This program is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU General Public License for more details.
014: *
015: * You should have received a copy of the GNU General Public License
016: * along with this program; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: */
019: package net.sourceforge.squirrel_sql.fw.dialects;
020:
021: import java.sql.Types;
022: import java.util.ArrayList;
023: import java.util.List;
024:
025: import net.sourceforge.squirrel_sql.fw.sql.IDatabaseObjectInfo;
026: import net.sourceforge.squirrel_sql.fw.sql.ITableInfo;
027: import net.sourceforge.squirrel_sql.fw.sql.TableColumnInfo;
028: import net.sourceforge.squirrel_sql.fw.util.StringManager;
029: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
030:
031: /**
032: * An extension to the standard Derby dialect
033: */
034: public class DerbyDialect extends DB2Dialect implements
035: HibernateDialect {
036:
037: /** Internationalized strings for this class. */
038: private static final StringManager s_stringMgr = StringManagerFactory
039: .getStringManager(DerbyDialect.class);
040:
041: private static interface i18n {
042: //i18n[DerbyDialect.typeMessage=Derby doesn't allow the column type to
043: //be altered]
044: String TYPE_MESSAGE = s_stringMgr
045: .getString("DerbyDialect.typeMessage");
046:
047: //i18n[DerbyDialect.varcharMessage=Derby only allows varchar columns
048: //to be altered]
049: String VARCHAR_MESSAGE = s_stringMgr
050: .getString("DerbyDialect.varcharMessage");
051:
052: //i18n[DerbyDialect.columnLengthMessage=Derby only allows varchar
053: //column length to be increased]
054: String COLUMN_LENGTH_MESSAGE = s_stringMgr
055: .getString("DerbyDialect.columnLengthMessage");
056: }
057:
058: public DerbyDialect() {
059: super ();
060: registerColumnType(Types.BIGINT, "bigint");
061: registerColumnType(Types.BINARY, 254, "char($l) for bit data");
062: registerColumnType(Types.BINARY, "blob");
063: registerColumnType(Types.BIT, "smallint");
064: // DB2 spec says max=2147483647, but the driver throws an exception
065: registerColumnType(Types.BLOB, 1073741823, "blob($l)");
066: registerColumnType(Types.BLOB, "blob(1073741823)");
067: registerColumnType(Types.BOOLEAN, "smallint");
068: registerColumnType(Types.CHAR, 254, "char($l)");
069: registerColumnType(Types.CHAR, 4000, "varchar($l)");
070: registerColumnType(Types.CHAR, 32700, "long varchar");
071: registerColumnType(Types.CHAR, 1073741823, "clob($l)");
072: registerColumnType(Types.CHAR, "clob(1073741823)");
073: // DB2 spec says max=2147483647, but the driver throws an exception
074: registerColumnType(Types.CLOB, 1073741823, "clob($l)");
075: registerColumnType(Types.CLOB, "clob(1073741823)");
076: registerColumnType(Types.DATE, "date");
077: registerColumnType(Types.DECIMAL, "decimal($p)");
078: // Derby is real close to DB2. Only difference I've found so far is 48
079: // instead of 53 for float length llimit.
080: registerColumnType(Types.DOUBLE, "float($p)");
081: registerColumnType(Types.FLOAT, "float($p)");
082: registerColumnType(Types.INTEGER, "int");
083: registerColumnType(Types.LONGVARBINARY, 32700,
084: "long varchar for bit data");
085: // DB2 spec says max=2147483647, but the driver throws an exception
086: registerColumnType(Types.LONGVARBINARY, 1073741823, "blob($l)");
087: registerColumnType(Types.LONGVARBINARY, "blob(1073741823)");
088: registerColumnType(Types.LONGVARCHAR, 32700, "long varchar");
089: // DB2 spec says max=2147483647, but the driver throws an exception
090: registerColumnType(Types.LONGVARCHAR, 1073741823, "clob($l)");
091: registerColumnType(Types.LONGVARCHAR, "clob(1073741823)");
092: registerColumnType(Types.NUMERIC, "bigint");
093: registerColumnType(Types.REAL, "real");
094: registerColumnType(Types.SMALLINT, "smallint");
095: registerColumnType(Types.TIME, "time");
096: registerColumnType(Types.TIMESTAMP, "timestamp");
097: registerColumnType(Types.TINYINT, "smallint");
098: registerColumnType(Types.VARBINARY, 254,
099: "long varchar for bit data");
100: registerColumnType(Types.VARBINARY, "blob");
101: registerColumnType(Types.VARCHAR, 4000, "varchar($l)");
102: registerColumnType(Types.VARCHAR, 32700, "long varchar");
103: // DB2 spec says max=2147483647, but the driver throws an exception
104: registerColumnType(Types.VARCHAR, 1073741823, "clob($l)");
105: registerColumnType(Types.VARCHAR, "clob(1073741823)");
106:
107: }
108:
109: /* (non-Javadoc)
110: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#canPasteTo(net.sourceforge.squirrel_sql.fw.sql.DatabaseObjectType)
111: */
112: public boolean canPasteTo(IDatabaseObjectInfo info) {
113: // TODO Auto-generated method stub
114: return true;
115: }
116:
117: /* (non-Javadoc)
118: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#supportsSchemasInTableDefinition()
119: */
120: public boolean supportsSchemasInTableDefinition() {
121: return true;
122: }
123:
124: /* (non-Javadoc)
125: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.DB2Dialect#getMaxPrecision(int)
126: */
127: public int getMaxPrecision(int dataType) {
128: if (dataType == Types.DOUBLE || dataType == Types.FLOAT) {
129: return 48;
130: } else {
131: return 31;
132: }
133: }
134:
135: /* (non-Javadoc)
136: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.DB2Dialect#getMaxScale(int)
137: */
138: public int getMaxScale(int dataType) {
139: return getMaxPrecision(dataType);
140: }
141:
142: /* (non-Javadoc)
143: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#getColumnLength(int, int)
144: */
145: public int getColumnLength(int columnSize, int dataType) {
146: return columnSize;
147: }
148:
149: /**
150: * The string which identifies this dialect in the dialect chooser.
151: *
152: * @return a descriptive name that tells the user what database this dialect
153: * is design to work with.
154: */
155: public String getDisplayName() {
156: return "Derby";
157: }
158:
159: /**
160: * Returns boolean value indicating whether or not this dialect supports the
161: * specified database product/version.
162: *
163: * @param databaseProductName the name of the database as reported by
164: * DatabaseMetaData.getDatabaseProductName()
165: * @param databaseProductVersion the version of the database as reported by
166: * DatabaseMetaData.getDatabaseProductVersion()
167: * @return true if this dialect can be used for the specified product name
168: * and version; false otherwise.
169: */
170: public boolean supportsProduct(String databaseProductName,
171: String databaseProductVersion) {
172: if (databaseProductName == null) {
173: return false;
174: }
175: if (databaseProductName.trim().startsWith("Apache Derby")) {
176: // We don't yet have the need to discriminate by version.
177: return true;
178: }
179: return false;
180: }
181:
182: /**
183: * Returns the SQL statement to use to add a column to the specified table
184: * using the information about the new column specified by info.
185: * @param info information about the new column such as type, name, etc.
186: *
187: * @return
188: * @throws UnsupportedOperationException if the database doesn't support
189: * adding columns after a table has already been created.
190: */
191: public String[] getColumnAddSQL(TableColumnInfo info)
192: throws UnsupportedOperationException {
193: return new String[] { DialectUtils.getColumnAddSQL(info, this ,
194: true, false, true) };
195: }
196:
197: /**
198: * Returns a boolean value indicating whether or not this database dialect
199: * supports dropping columns from tables.
200: *
201: * @return true if the database supports dropping columns; false otherwise.
202: */
203: public boolean supportsDropColumn() {
204: return false;
205: }
206:
207: /**
208: * Returns the SQL that forms the command to drop the specified colum in the
209: * specified table.
210: *
211: * ALTER TABLE table-Name DROP [ COLUMN ] column-name [ CASCADE | RESTRICT ]
212: *
213: * @param tableName the name of the table that has the column
214: * @param columnName the name of the column to drop.
215: * @return
216: * @throws UnsupportedOperationException if the database doesn't support
217: * dropping columns.
218: */
219: public String getColumnDropSQL(String tableName, String columnName) {
220: int featureId = DialectUtils.COLUMN_DROP_TYPE;
221: String msg = DialectUtils
222: .getUnsupportedMessage(this , featureId);
223: throw new UnsupportedOperationException(msg);
224: }
225:
226: /**
227: * Returns the SQL that forms the command to drop the specified table. If
228: * cascade contraints is supported by the dialect and cascadeConstraints is
229: * true, then a drop statement with cascade constraints clause will be
230: * formed.
231: *
232: * @param iTableInfo the table to drop
233: * @param cascadeConstraints whether or not to drop any FKs that may
234: * reference the specified table.
235: * @return the drop SQL command.
236: */
237: public List<String> getTableDropSQL(ITableInfo iTableInfo,
238: boolean cascadeConstraints, boolean isMaterializedView) {
239: return DialectUtils.getTableDropSQL(iTableInfo, false,
240: cascadeConstraints, false, DialectUtils.CASCADE_CLAUSE,
241: false);
242: }
243:
244: /**
245: * Returns the SQL that forms the command to add a primary key to the
246: * specified table composed of the given column names.
247: *
248: * @param pkName the name of the constraint
249: * @param columnInfos the columns that form the key
250: * @return
251: */
252: public String[] getAddPrimaryKeySQL(String pkName,
253: TableColumnInfo[] colInfos, ITableInfo ti) {
254: ArrayList<String> result = new ArrayList<String>();
255: String alterClause = DialectUtils.ALTER_COLUMN_CLAUSE;
256:
257: // convert each column that will be a member key to non-null - this
258: // doesn't hurt if they are already null.
259: DialectUtils.getMultiColNotNullSQL(colInfos, this , alterClause,
260: false, result);
261:
262: result.add(DialectUtils.getAddPrimaryKeySQL(ti, pkName,
263: colInfos, false));
264:
265: return result.toArray(new String[result.size()]);
266: }
267:
268: /**
269: * Returns a boolean value indicating whether or not this dialect supports
270: * adding comments to columns.
271: *
272: * @return true if column comments are supported; false otherwise.
273: */
274: public boolean supportsColumnComment() {
275: return false;
276: }
277:
278: /**
279: * Returns the SQL statement to use to add a comment to the specified
280: * column of the specified table.
281: * @param info information about the column such as type, name, etc.
282: * @return
283: * @throws UnsupportedOperationException if the database doesn't support
284: * annotating columns with a comment.
285: */
286: public String getColumnCommentAlterSQL(TableColumnInfo info)
287: throws UnsupportedOperationException {
288: int featureId = DialectUtils.COLUMN_COMMENT_ALTER_TYPE;
289: String msg = DialectUtils
290: .getUnsupportedMessage(this , featureId);
291: throw new UnsupportedOperationException(msg);
292: }
293:
294: /**
295: * Returns a boolean value indicating whether or not this database dialect
296: * supports changing a column from null to not-null and vice versa.
297: *
298: * @return true if the database supports dropping columns; false otherwise.
299: */
300: public boolean supportsAlterColumnNull() {
301: return true;
302: }
303:
304: /**
305: * Returns the SQL used to alter the specified column to not allow null
306: * values
307: *
308: * ALTER TABLE table-Name ALTER [ COLUMN ] column-name [ NOT ] NULL
309: *
310: * @param info the column to modify
311: * @return the SQL to execute
312: */
313: public String getColumnNullableAlterSQL(TableColumnInfo info) {
314: String alterClause = DialectUtils.ALTER_COLUMN_CLAUSE;
315: return DialectUtils.getColumnNullableAlterSQL(info, this ,
316: alterClause, false);
317: }
318:
319: /**
320: * Returns a boolean value indicating whether or not this database dialect
321: * supports renaming columns.
322: *
323: * @return true if the database supports changing the name of columns;
324: * false otherwise.
325: */
326: public boolean supportsRenameColumn() {
327: return false;
328: }
329:
330: /**
331: * Returns the SQL that is used to change the column name.
332: *
333: * RENAME COLUMN table-Name.simple-Column-Name TO simple-Column-Name
334: *
335: * @param from the TableColumnInfo as it is
336: * @param to the TableColumnInfo as it wants to be
337: *
338: * @return the SQL to make the change
339: */
340: public String getColumnNameAlterSQL(TableColumnInfo from,
341: TableColumnInfo to) {
342: int featureId = DialectUtils.COLUMN_NAME_ALTER_TYPE;
343: String msg = DialectUtils
344: .getUnsupportedMessage(this , featureId);
345: throw new UnsupportedOperationException(msg);
346: }
347:
348: /**
349: * Returns a boolean value indicating whether or not this dialect supports
350: * modifying a columns type.
351: *
352: * @return true if supported; false otherwise
353: */
354: public boolean supportsAlterColumnType() {
355: return true;
356: }
357:
358: /**
359: * Returns the SQL that is used to change the column type.
360: *
361: * ALTER [ COLUMN ] column-Name SET DATA TYPE VARCHAR(integer)
362: *
363: * Note: Only allowed to increase size of existing varchar as long as it is
364: * not a member of a PK that is a parent of a FK. Also not allowed to
365: * change the type to anything else. Oh, and only during a full moon
366: * while chanting - sheesh! I think I'll need a dozen or so methods
367: * to describe all of those restrictions.
368: *
369: * @param from the TableColumnInfo as it is
370: * @param to the TableColumnInfo as it wants to be
371: *
372: * @return the SQL to make the change
373: * @throw UnsupportedOperationException if the database doesn't support
374: * modifying column types.
375: */
376: public List<String> getColumnTypeAlterSQL(TableColumnInfo from,
377: TableColumnInfo to) throws UnsupportedOperationException {
378: ArrayList<String> list = new ArrayList<String>();
379: if (from.getDataType() != to.getDataType()) {
380: throw new UnsupportedOperationException(i18n.TYPE_MESSAGE);
381: }
382: if (from.getDataType() != Types.VARCHAR) {
383: throw new UnsupportedOperationException(
384: i18n.VARCHAR_MESSAGE);
385: }
386: if (from.getColumnSize() > to.getColumnSize()) {
387: throw new UnsupportedOperationException(
388: i18n.COLUMN_LENGTH_MESSAGE);
389: }
390: StringBuffer result = new StringBuffer();
391: result.append("ALTER TABLE ");
392: result.append(to.getTableName());
393: result.append(" ALTER COLUMN ");
394: result.append(to.getColumnName());
395: result.append(" SET DATA TYPE ");
396: result.append(DialectUtils.getTypeName(to, this ));
397: list.add(result.toString());
398: return list;
399: }
400:
401: /**
402: * Returns a boolean value indicating whether or not this database dialect
403: * supports changing a column's default value.
404: *
405: * @return true if the database supports modifying column defaults; false
406: * otherwise
407: */
408: public boolean supportsAlterColumnDefault() {
409: return false;
410: }
411:
412: /**
413: * Returns the SQL command to change the specified column's default value
414: *
415: * @param info the column to modify and it's default value.
416: * @return SQL to make the change
417: */
418: public String getColumnDefaultAlterSQL(TableColumnInfo info) {
419: int featureId = DialectUtils.COLUMN_DEFAULT_ALTER_TYPE;
420: String msg = DialectUtils
421: .getUnsupportedMessage(this , featureId);
422: throw new UnsupportedOperationException(msg);
423: }
424:
425: /**
426: * Returns the SQL command to drop the specified table's primary key.
427: *
428: * @param pkName the name of the primary key that should be dropped
429: * @param tableName the name of the table whose primary key should be
430: * dropped
431: * @return
432: */
433: public String getDropPrimaryKeySQL(String pkName, String tableName) {
434: return DialectUtils.getDropPrimaryKeySQL(pkName, tableName,
435: false, false);
436: }
437:
438: /**
439: * Returns the SQL command to drop the specified table's foreign key
440: * constraint.
441: *
442: * @param fkName the name of the foreign key that should be dropped
443: * @param tableName the name of the table whose foreign key should be
444: * dropped
445: * @return
446: */
447: public String getDropForeignKeySQL(String fkName, String tableName) {
448: return DialectUtils.getDropForeignKeySQL(fkName, tableName);
449: }
450:
451: }
|