diff --git a/core/src/main/java/org/hibernate/dialect/Ingres10Dialect.java b/core/src/main/java/org/hibernate/dialect/Ingres10Dialect.java new file mode 100644 index 0000000000..748bd2897f --- /dev/null +++ b/core/src/main/java/org/hibernate/dialect/Ingres10Dialect.java @@ -0,0 +1,22 @@ +package org.hibernate.dialect; + +import java.sql.Types; + +import org.hibernate.Hibernate; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.function.NoArgSQLFunction; + +/** + * A SQL dialect for Ingres 10 and later versions. + * + * Changes: + * + * + * @author Raymond Fan + */ +public class Ingres10Dialect extends Ingres9Dialect { + public Ingres10Dialect() { + super(); + } +} diff --git a/core/src/main/java/org/hibernate/dialect/Ingres9Dialect.java b/core/src/main/java/org/hibernate/dialect/Ingres9Dialect.java new file mode 100644 index 0000000000..5f5e250f7a --- /dev/null +++ b/core/src/main/java/org/hibernate/dialect/Ingres9Dialect.java @@ -0,0 +1,215 @@ +package org.hibernate.dialect; + +import java.sql.Types; + +import org.hibernate.Hibernate; +import org.hibernate.dialect.function.NoArgSQLFunction; + +/** + * A SQL dialect for Ingres 9.3 and later versions. + *

+ * Changes: + *

+ * + * @author Enrico Schenk, Raymond Fan + */ +public class Ingres9Dialect extends IngresDialect { + public Ingres9Dialect() { + super(); + registerDateTimeFunctions(); + registerDateTimeColumnTypes(); + } + + /** + * Register functions current_time, current_timestamp, current_date + */ + protected void registerDateTimeFunctions() { + registerFunction("current_time", new NoArgSQLFunction("current_time", Hibernate.TIME, false)); + registerFunction("current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP, false)); + registerFunction("current_date", new NoArgSQLFunction("current_date", Hibernate.DATE, false)); + } + + /** + * Register column types date, time, timestamp + */ + protected void registerDateTimeColumnTypes() { + registerColumnType(Types.DATE, "ansidate"); + //registerColumnType(Types.TIME, "time with time zone"); + registerColumnType(Types.TIMESTAMP, "timestamp(9) with time zone"); + } + + // lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Does this dialect support FOR UPDATE in conjunction with outer + * joined rows? + * + * @return True if outer joined rows can be locked via FOR UPDATE. + */ + public boolean supportsOuterJoinForUpdate() { + return false; + } + + /** + * Is FOR UPDATE OF syntax supported? + * + * @return True if the database supports FOR UPDATE OF syntax; + * false otherwise. + */ + public boolean forUpdateOfColumns() { + return true; + } + + // SEQUENCE support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Get the select command used to retrieve the last generated sequence + * value. + * + * @return Statement to retrieve last generated sequence value + */ + public String getIdentitySelectString() { + return "select last_identity()"; + } + + /** + * Get the select command used retrieve the names of all sequences. + * + * @return The select command; or null if sequences are not supported. + * @see org.hibernate.tool.hbm2ddl.SchemaUpdate + */ + public String getQuerySequencesString() { + return "select seq_name from iisequences"; + } + + /** + * Does this dialect support "pooled" sequences. Not aware of a better name + * for this. Essentially can we specify the initial and increment values? + * + * @return True if such "pooled" sequences are supported; false otherwise. + * @see #getCreateSequenceStrings(String, int, int) + * @see #getCreateSequenceString(String, int, int) + */ + public boolean supportsPooledSequences() { + return true; + } + + // current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Should the value returned by {@link #getCurrentTimestampSelectString} be + * treated as callable. Typically this indicates that JDBC escape sytnax is + * being used... + * + * @return True if the {@link #getCurrentTimestampSelectString} return is + * callable; false otherwise. + */ + public boolean isCurrentTimestampSelectStringCallable() { + return false; + } + + /** + * Does this dialect support a way to retrieve the database's current + * timestamp value? + * + * @return True if the current timestamp can be retrieved; false otherwise. + */ + public boolean supportsCurrentTimestampSelection() { + return true; + } + + /** + * Retrieve the command used to retrieve the current timestamp from the + * database. + * + * @return The command. + */ + public String getCurrentTimestampSelectString() { + return "select current_timestamp"; + } + + /** + * Expression for current_timestamp + */ + public String getCurrentTimestampSQLFunctionName() { + return "current_timestamp"; + } + + // union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Does this dialect support UNION ALL, which is generally a faster variant + * of UNION? + * + * @return True if UNION ALL is supported; false otherwise. + */ + public boolean supportsUnionAll() { + return true; + } + + // Informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * For the underlying database, is READ_COMMITTED isolation implemented by + * forcing readers to wait for write locks to be released? + * + * @return true + */ + public boolean doesReadCommittedCauseWritersToBlockReaders() { + return true; + } + + /** + * For the underlying database, is REPEATABLE_READ isolation implemented by + * forcing writers to wait for read locks to be released? + * + * @return true + */ + public boolean doesRepeatableReadCauseReadersToBlockWriters() { + return true; + } + + // limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * Does this dialect's LIMIT support (if any) additionally support + * specifying an offset? + * + * @return true + */ + public boolean supportsLimitOffset() { + return true; + } + + /** + * Does this dialect support bind variables (i.e., prepared statement + * parameters) for its limit/offset? + * + * @return false + */ + public boolean supportsVariableLimit() { + return false; + } + + /** + * Add a LIMIT clause to the given SQL SELECT + * + * @return the modified SQL + */ + public String getLimitString(String querySelect, int offset, int limit) { + StringBuffer sb = new StringBuffer(querySelect.length() + 16); + sb.append(querySelect.trim()).insert(6, " first " + limit); + if (offset > 0) { + sb.append(" offset " + offset); + } + return sb.toString(); + } + +} diff --git a/core/src/main/java/org/hibernate/dialect/IngresDialect.java b/core/src/main/java/org/hibernate/dialect/IngresDialect.java index 3ace608f34..1e19672a89 100644 --- a/core/src/main/java/org/hibernate/dialect/IngresDialect.java +++ b/core/src/main/java/org/hibernate/dialect/IngresDialect.java @@ -27,6 +27,7 @@ package org.hibernate.dialect; import java.sql.Types; import org.hibernate.Hibernate; +import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.StandardSQLFunction; @@ -36,9 +37,12 @@ import org.hibernate.dialect.function.VarArgsSQLFunction; * An SQL dialect for Ingres 9.2. *

* Known limitations: - * - only supports simple constants or columns on the left side of an IN, making (1,2,3) in (...) or (<subselect>) in (...) non-supported - * - supports only 39 digits in decimal - * + *

+ * * @author Ian Booth, Bruce Lunsford, Max Rydahl Andersen */ public class IngresDialect extends Dialect { @@ -135,6 +139,17 @@ public class IngresDialect extends Dialect { registerFunction( "uuid_from_char", new StandardSQLFunction( "uuid_from_char", Hibernate.BYTE ) ); registerFunction( "uuid_to_char", new StandardSQLFunction( "uuid_to_char", Hibernate.STRING ) ); registerFunction( "year", new StandardSQLFunction( "year", Hibernate.INTEGER ) ); + // Ingres driver supports getGeneratedKeys but only in the following + // form: + // The Ingres DBMS returns only a single table key or a single object + // key per insert statement. Ingres does not return table and object + // keys for INSERT AS SELECT statements. Depending on the keys that are + // produced by the statement executed, auto-generated key parameters in + // execute(), executeUpdate(), and prepareStatement() methods are + // ignored and getGeneratedKeys() returns a result-set containing no + // rows, a single row with one column, or a single row with two columns. + // Ingres JDBC Driver returns table and object keys as BINARY values. + getDefaultProperties().setProperty(Environment.USE_GET_GENERATED_KEYS, "false"); } /** diff --git a/core/src/main/java/org/hibernate/dialect/resolver/StandardDialectResolver.java b/core/src/main/java/org/hibernate/dialect/resolver/StandardDialectResolver.java index e809e3b28c..409a6ca669 100644 --- a/core/src/main/java/org/hibernate/dialect/resolver/StandardDialectResolver.java +++ b/core/src/main/java/org/hibernate/dialect/resolver/StandardDialectResolver.java @@ -35,6 +35,8 @@ import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.DerbyDialect; +import org.hibernate.dialect.Ingres10Dialect; +import org.hibernate.dialect.Ingres9Dialect; import org.hibernate.dialect.IngresDialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.dialect.InformixDialect; @@ -78,6 +80,19 @@ public class StandardDialectResolver extends AbstractDialectResolver{ } if ( "ingres".equalsIgnoreCase( databaseName ) ) { + switch( databaseMajorVersion ) { + case 9: + int databaseMinorVersion = metaData.getDatabaseMinorVersion(); + if (databaseMinorVersion > 2) { + return new Ingres9Dialect(); + } + return new IngresDialect(); + case 10: + log.warn( "Ingres " + databaseMajorVersion + " is not yet fully supported; using Ingres 9.3 dialect" ); + return new Ingres10Dialect(); + default: + log.warn( "Unknown Ingres major version [" + databaseMajorVersion + "] using Ingres 9.2 dialect" ); + } return new IngresDialect(); }