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.SQLException;
022: import java.sql.Types;
023: import java.util.ArrayList;
024: import java.util.List;
025:
026: import net.sourceforge.squirrel_sql.fw.sql.DatabaseObjectType;
027: import net.sourceforge.squirrel_sql.fw.sql.IDatabaseObjectInfo;
028: import net.sourceforge.squirrel_sql.fw.sql.ISQLDatabaseMetaData;
029: import net.sourceforge.squirrel_sql.fw.sql.ITableInfo;
030: import net.sourceforge.squirrel_sql.fw.sql.TableColumnInfo;
031:
032: /**
033: * An extension to the standard Hibernate Ingres dialect
034: *
035: */
036: public class IngresDialect extends org.hibernate.dialect.IngresDialect
037: implements HibernateDialect {
038:
039: public IngresDialect() {
040: super ();
041:
042: registerColumnType(Types.BIGINT, "bigint");
043: // SQL Reference Guide says 32k, but I get:
044: //
045: // The specified row size exceeded the maximum allowable row width.,
046: // SQL State: 50002, Error Code: 2045
047: //
048: // when I go above 8000.
049: registerColumnType(Types.BINARY, 8000, "byte($l)");
050: registerColumnType(Types.BINARY, "long byte");
051: registerColumnType(Types.BIT, "tinyint");
052: registerColumnType(Types.BLOB, "long byte");
053: registerColumnType(Types.BOOLEAN, "tinyint");
054: registerColumnType(Types.CHAR, 2000, "char($l)");
055: registerColumnType(Types.CHAR, "long varchar");
056: registerColumnType(Types.CLOB, "long varchar");
057: registerColumnType(Types.DATE, "date");
058: registerColumnType(Types.DECIMAL, "decimal($p, $s)");
059: registerColumnType(Types.DOUBLE, "double precision");
060: registerColumnType(Types.FLOAT, "float($p)");
061: registerColumnType(Types.INTEGER, "integer");
062: registerColumnType(Types.LONGVARBINARY, "long byte");
063: registerColumnType(Types.LONGVARCHAR, "long varchar");
064: registerColumnType(Types.NUMERIC, "numeric($p, $s)");
065: registerColumnType(Types.REAL, "real");
066: registerColumnType(Types.SMALLINT, "smallint");
067: registerColumnType(Types.TIME, "date");
068: registerColumnType(Types.TIMESTAMP, "date");
069: registerColumnType(Types.TINYINT, "tinyint");
070: // I tried the following for values under 8000 but I get
071: // Encountered unexpected exception - line 1, You cannot assign a
072: // value of type 'long byte' to a column of type 'byte varying'.
073: // Explicitly convert the value to the required type.
074: // registerColumnType(Types.VARBINARY, 8000, "byte varying($l)");
075: registerColumnType(Types.VARBINARY, "long byte");
076: // I tried 8000 for the max length of VARCHAR and ingres gives an exception
077: // (cannot assign a value of type long varchar to a varchar field). So
078: // I limit this field to 4000 for now - the Ingres product documentation
079: // indicated that 32k was acceptable. I've tested 4k and it seems to
080: // work fine.
081: registerColumnType(Types.VARCHAR, 4000, "varchar($l)");
082: registerColumnType(Types.VARCHAR, "long varchar");
083: }
084:
085: /* (non-Javadoc)
086: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#canPasteTo(net.sourceforge.squirrel_sql.fw.sql.DatabaseObjectType)
087: */
088: public boolean canPasteTo(IDatabaseObjectInfo info) {
089: boolean result = true;
090: DatabaseObjectType type = info.getDatabaseObjectType();
091: if (type.getName().equalsIgnoreCase("database")) {
092: result = false;
093: }
094: return result;
095: }
096:
097: /* (non-Javadoc)
098: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#supportsSchemasInTableDefinition()
099: */
100: public boolean supportsSchemasInTableDefinition() {
101: return false;
102: }
103:
104: /* (non-Javadoc)
105: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#getLengthFunction()
106: */
107: public String getLengthFunction(int dataType) {
108: return "length";
109: }
110:
111: /* (non-Javadoc)
112: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#getMaxFunction()
113: */
114: public String getMaxFunction() {
115: return "max";
116: }
117:
118: /* (non-Javadoc)
119: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#getMaxPrecision(int)
120: */
121: public int getMaxPrecision(int dataType) {
122: // float(54) produces an exception:
123: //
124: // invalid column format 'float' on column 'float_column'.,
125: // SQL State: 42000, Error Code: 2014
126: if (dataType == Types.FLOAT) {
127: return 53;
128: } else {
129: return 31;
130: }
131: }
132:
133: /* (non-Javadoc)
134: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#getMaxScale(int)
135: */
136: public int getMaxScale(int dataType) {
137: return getMaxPrecision(dataType);
138: }
139:
140: /* (non-Javadoc)
141: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#getPrecisionDigits(int, int)
142: */
143: public int getPrecisionDigits(int columnSize, int dataType) {
144: return columnSize;
145: }
146:
147: /* (non-Javadoc)
148: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.dialects.HibernateDialect#getColumnLength(int, int)
149: */
150: public int getColumnLength(int columnSize, int dataType) {
151: return columnSize;
152: }
153:
154: /**
155: * The string which identifies this dialect in the dialect chooser.
156: *
157: * @return a descriptive name that tells the user what database this dialect
158: * is design to work with.
159: */
160: public String getDisplayName() {
161: return "Ingres";
162: }
163:
164: /**
165: * Returns boolean value indicating whether or not this dialect supports the
166: * specified database product/version.
167: *
168: * @param databaseProductName the name of the database as reported by
169: * DatabaseMetaData.getDatabaseProductName()
170: * @param databaseProductVersion the version of the database as reported by
171: * DatabaseMetaData.getDatabaseProductVersion()
172: * @return true if this dialect can be used for the specified product name
173: * and version; false otherwise.
174: */
175: public boolean supportsProduct(String databaseProductName,
176: String databaseProductVersion) {
177: if (databaseProductName == null) {
178: return false;
179: }
180: if (databaseProductName.trim().toLowerCase().startsWith(
181: "ingres")) {
182: // We don't yet have the need to discriminate by version.
183: return true;
184: }
185: return false;
186: }
187:
188: /**
189: * Returns the SQL statement to use to add a column to the specified table
190: * using the information about the new column specified by info.
191: *
192: * ALTER TABLE tableName ADD COLUMN columnName type
193: *
194: * alter table tableName alter column columnName type default defVal
195: *
196: * alter table tableName alter column columnName type not null
197: *
198: * @param info information about the new column such as type, name, etc.
199: * @return
200: * @throws UnsupportedOperationException if the database doesn't support
201: * adding columns after a table has already been created.
202: */
203: public String[] getColumnAddSQL(TableColumnInfo info)
204: throws UnsupportedOperationException {
205: ArrayList<String> result = new ArrayList<String>();
206:
207: result.add(DialectUtils.getColumnAddSQL(info, this , false,
208: false, false));
209:
210: // Ingres requires that columns that are to become not null must have a
211: // default value.
212: if (info.isNullable().equals("NO")) {
213: result.add(getColumnDefaultAlterSQL(info));
214: result.add(getColumnNullableAlterSQL(info));
215: }
216: if (info.getRemarks() != null && !"".equals(info.getRemarks())) {
217: result.add(getColumnCommentAlterSQL(info));
218: }
219: return result.toArray(new String[result.size()]);
220: }
221:
222: /**
223: * Returns a boolean value indicating whether or not this database dialect
224: * supports dropping columns from tables.
225: *
226: * @return true if the database supports dropping columns; false otherwise.
227: */
228: public boolean supportsDropColumn() {
229: return true;
230: }
231:
232: /**
233: * Returns the SQL that forms the command to drop the specified colum in the
234: * specified table.
235: *
236: * @param tableName the name of the table that has the column
237: * @param columnName the name of the column to drop.
238: * @return
239: * @throws UnsupportedOperationException if the database doesn't support
240: * dropping columns.
241: */
242: public String getColumnDropSQL(String tableName, String columnName) {
243: String dropClause = DialectUtils.DROP_COLUMN_CLAUSE;
244: // TODO: Need to allow user to specify this
245: String constraintClause = "CASCADE";
246:
247: return DialectUtils.getColumnDropSQL(tableName, columnName,
248: dropClause, true, constraintClause);
249: }
250:
251: /**
252: * Returns the SQL that forms the command to drop the specified table. If
253: * cascade contraints is supported by the dialect and cascadeConstraints is
254: * true, then a drop statement with cascade constraints clause will be
255: * formed.
256: *
257: * @param iTableInfo the table to drop
258: * @param cascadeConstraints whether or not to drop any FKs that may
259: * reference the specified table.
260: * @return the drop SQL command.
261: */
262: public List<String> getTableDropSQL(ITableInfo iTableInfo,
263: boolean cascadeConstraints, boolean isMaterializedView) {
264: return DialectUtils.getTableDropSQL(iTableInfo, false,
265: cascadeConstraints, false, DialectUtils.CASCADE_CLAUSE,
266: false);
267: }
268:
269: /**
270: * Returns the SQL that forms the command to add a primary key to the
271: * specified table composed of the given column names.
272: *
273: *
274: * alter table test alter column pkcol integer not null
275: *
276: * alter table test add constraint pk_test primary key (pkcol)
277: *
278: * @param pkName the name of the constraint
279: * @param columnNames the columns that form the key
280: * @return
281: */
282: public String[] getAddPrimaryKeySQL(String pkName,
283: TableColumnInfo[] columns, ITableInfo ti) {
284: ArrayList<String> result = new ArrayList<String>();
285: String alterClause = DialectUtils.ALTER_COLUMN_CLAUSE;
286: for (int i = 0; i < columns.length; i++) {
287: TableColumnInfo info = columns[i];
288: String notNullSQL = DialectUtils.getColumnNullableAlterSQL(
289: info, false, this , alterClause, true);
290: result.add(notNullSQL);
291: }
292: result.add(DialectUtils.getAddPrimaryKeySQL(ti, pkName,
293: columns, false));
294: return result.toArray(new String[result.size()]);
295: }
296:
297: /**
298: * Returns a boolean value indicating whether or not this dialect supports
299: * adding comments to columns.
300: *
301: * @return true if column comments are supported; false otherwise.
302: */
303: public boolean supportsColumnComment() {
304: return true;
305: }
306:
307: /**
308: * Returns the SQL statement to use to add a comment to the specified
309: * column of the specified table.
310: * @param info information about the column such as type, name, etc.
311: * @return
312: * @throws UnsupportedOperationException if the database doesn't support
313: * annotating columns with a comment.
314: */
315: public String getColumnCommentAlterSQL(TableColumnInfo info)
316: throws UnsupportedOperationException {
317: return DialectUtils.getColumnCommentAlterSQL(info);
318: }
319:
320: /**
321: * Returns a boolean value indicating whether or not this database dialect
322: * supports changing a column from null to not-null and vice versa.
323: *
324: * @return true if the database supports dropping columns; false otherwise.
325: */
326: public boolean supportsAlterColumnNull() {
327: return true;
328: }
329:
330: /**
331: * Returns the SQL used to alter the specified column to not allow null
332: * values
333: *
334: * alter table test alter column notnullint integer not null
335: *
336: * @param info the column to modify
337: * @return the SQL to execute
338: */
339: public String getColumnNullableAlterSQL(TableColumnInfo info) {
340: String alterClause = DialectUtils.ALTER_COLUMN_CLAUSE;
341: return DialectUtils.getColumnNullableAlterSQL(info, this ,
342: alterClause, true);
343: }
344:
345: /**
346: * Returns a boolean value indicating whether or not this database dialect
347: * supports renaming columns.
348: *
349: * @return true if the database supports changing the name of columns;
350: * false otherwise.
351: */
352: public boolean supportsRenameColumn() {
353: return false;
354: }
355:
356: /**
357: * Returns the SQL that is used to change the column name.
358: *
359: *
360: * @param from the TableColumnInfo as it is
361: * @param to the TableColumnInfo as it wants to be
362: *
363: * @return the SQL to make the change
364: */
365: public String getColumnNameAlterSQL(TableColumnInfo from,
366: TableColumnInfo to) {
367: int featureId = DialectUtils.COLUMN_NAME_ALTER_TYPE;
368: String msg = DialectUtils
369: .getUnsupportedMessage(this , featureId);
370: throw new UnsupportedOperationException(msg);
371: }
372:
373: /**
374: * Returns a boolean value indicating whether or not this dialect supports
375: * modifying a columns type.
376: *
377: * @return true if supported; false otherwise
378: */
379: public boolean supportsAlterColumnType() {
380: return true;
381: }
382:
383: /**
384: * Returns the SQL that is used to change the column type.
385: *
386: * alter table tableName alter column columnName columnTypeSpec
387: *
388: * @param from the TableColumnInfo as it is
389: * @param to the TableColumnInfo as it wants to be
390: *
391: * @return the SQL to make the change
392: * @throw UnsupportedOperationException if the database doesn't support
393: * modifying column types.
394: */
395: public List<String> getColumnTypeAlterSQL(TableColumnInfo from,
396: TableColumnInfo to) throws UnsupportedOperationException {
397: String alterClause = DialectUtils.ALTER_COLUMN_CLAUSE;
398: String setClause = "";
399: return DialectUtils.getColumnTypeAlterSQL(this , alterClause,
400: setClause, false, from, to);
401: }
402:
403: /**
404: * Returns a boolean value indicating whether or not this database dialect
405: * supports changing a column's default value.
406: *
407: * @return true if the database supports modifying column defaults; false
408: * otherwise
409: */
410: public boolean supportsAlterColumnDefault() {
411: return true;
412: }
413:
414: /**
415: * Returns the SQL command to change the specified column's default value
416: *
417: * alter table test2 alter column mycol char(10) default 'foo'
418: *
419: * @param info the column to modify and it's default value.
420: * @return SQL to make the change
421: */
422: public String getColumnDefaultAlterSQL(TableColumnInfo info) {
423: String alterClause = DialectUtils.ALTER_COLUMN_CLAUSE;
424: String defaultClause = DialectUtils.DEFAULT_CLAUSE;
425: return DialectUtils.getColumnDefaultAlterSQL(this , info,
426: alterClause, true, defaultClause);
427: }
428:
429: /**
430: * Returns the SQL command to drop the specified table's primary key.
431: *
432: * @param pkName the name of the primary key that should be dropped
433: * @param tableName the name of the table whose primary key should be
434: * dropped
435: * @return
436: */
437: public String getDropPrimaryKeySQL(String pkName, String tableName) {
438: return DialectUtils.getDropPrimaryKeySQL(pkName, tableName,
439: true, true);
440: }
441:
442: /**
443: * Returns the SQL command to drop the specified table's foreign key
444: * constraint.
445: *
446: * @param fkName the name of the foreign key that should be dropped
447: * @param tableName the name of the table whose foreign key should be
448: * dropped
449: * @return
450: */
451: public String getDropForeignKeySQL(String fkName, String tableName) {
452: return DialectUtils.getDropForeignKeySQL(fkName, tableName);
453: }
454:
455: /**
456: * Returns the SQL command to create the specified table.
457: *
458: * @param tables the tables to get create statements for
459: * @param md the metadata from the ISession
460: * @param prefs preferences about how the resultant SQL commands should be
461: * formed.
462: * @param isJdbcOdbc whether or not the connection is via JDBC-ODBC bridge.
463: *
464: * @return the SQL that is used to create the specified table
465: */
466: public List<String> getCreateTableSQL(List<ITableInfo> tables,
467: ISQLDatabaseMetaData md, CreateScriptPreferences prefs,
468: boolean isJdbcOdbc) throws SQLException {
469: return DialectUtils.getCreateTableSQL(tables, md, this, prefs,
470: isJdbcOdbc);
471: }
472:
473: }
|