This commit is contained in:
commit
cc4055d50c
|
@ -994,15 +994,15 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect</programlisting>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>MySQL</entry>
|
<entry>MySQL5</entry>
|
||||||
|
|
||||||
<entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
|
<entry><literal>org.hibernate.dialect.MySQL5Dialect</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>MySQL with InnoDB</entry>
|
<entry>MySQL5 with InnoDB</entry>
|
||||||
|
|
||||||
<entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
|
<entry><literal>org.hibernate.dialect.MySQL5InnoDBDialect</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
|
@ -1026,13 +1026,19 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect</programlisting>
|
||||||
<row>
|
<row>
|
||||||
<entry>Oracle 10g</entry>
|
<entry>Oracle 10g</entry>
|
||||||
|
|
||||||
|
<entry><literal>org.hibernate.dialect.Oracle10gDialect</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Oracle 11g</entry>
|
||||||
|
|
||||||
<entry><literal>org.hibernate.dialect.Oracle10gDialect</literal></entry>
|
<entry><literal>org.hibernate.dialect.Oracle10gDialect</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Sybase</entry>
|
<entry>Sybase</entry>
|
||||||
|
|
||||||
<entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
|
<entry><literal>org.hibernate.dialect.SybaseASE15Dialect</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
|
@ -1042,11 +1048,23 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect</programlisting>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Microsoft SQL Server</entry>
|
<entry>Microsoft SQL Server 2000</entry>
|
||||||
|
|
||||||
<entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
|
<entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Microsoft SQL Server 2005</entry>
|
||||||
|
|
||||||
|
<entry><literal>org.hibernate.dialect.SQLServer2005Dialect</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Microsoft SQL Server 2008</entry>
|
||||||
|
|
||||||
|
<entry><literal>org.hibernate.dialect.SQLServer2008Dialect</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>SAP DB</entry>
|
<entry>SAP DB</entry>
|
||||||
|
|
||||||
|
@ -1065,6 +1083,12 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect</programlisting>
|
||||||
<entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
|
<entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>H2 Database</entry>
|
||||||
|
|
||||||
|
<entry><literal>org.hibernate.dialect.H2Dialect</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Ingres</entry>
|
<entry>Ingres</entry>
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ public abstract class Dialect {
|
||||||
|
|
||||||
private final Properties properties = new Properties();
|
private final Properties properties = new Properties();
|
||||||
private final Map<String, SQLFunction> sqlFunctions = new HashMap<String, SQLFunction>();
|
private final Map<String, SQLFunction> sqlFunctions = new HashMap<String, SQLFunction>();
|
||||||
private final Set sqlKeywords = new HashSet();
|
private final Set<String> sqlKeywords = new HashSet<String>();
|
||||||
|
|
||||||
|
|
||||||
// constructors and factory methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// constructors and factory methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -197,7 +197,7 @@ public abstract class Dialect {
|
||||||
throw new HibernateException( "Dialect class not found: " + dialectName );
|
throw new HibernateException( "Dialect class not found: " + dialectName );
|
||||||
}
|
}
|
||||||
catch ( Exception e ) {
|
catch ( Exception e ) {
|
||||||
throw new HibernateException( "Could not instantiate dialect class", e );
|
throw new HibernateException( "Could not instantiate given dialect class: " + dialectName, e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +373,7 @@ public abstract class Dialect {
|
||||||
*
|
*
|
||||||
* @return The map of registered functions.
|
* @return The map of registered functions.
|
||||||
*/
|
*/
|
||||||
public final Map getFunctions() {
|
public final Map<String, SQLFunction> getFunctions() {
|
||||||
return sqlFunctions;
|
return sqlFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +384,7 @@ public abstract class Dialect {
|
||||||
sqlKeywords.add(word);
|
sqlKeywords.add(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set getKeywords() {
|
public Set<String> getKeywords() {
|
||||||
return sqlKeywords;
|
return sqlKeywords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +481,7 @@ public abstract class Dialect {
|
||||||
* @throws MappingException If IDENTITY generation is not supported.
|
* @throws MappingException If IDENTITY generation is not supported.
|
||||||
*/
|
*/
|
||||||
protected String getIdentitySelectString() throws MappingException {
|
protected String getIdentitySelectString() throws MappingException {
|
||||||
throw new MappingException( "Dialect does not support identity key generation" );
|
throw new MappingException( getClass().getName() + " does not support identity key generation" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -503,7 +503,7 @@ public abstract class Dialect {
|
||||||
* @throws MappingException If IDENTITY generation is not supported.
|
* @throws MappingException If IDENTITY generation is not supported.
|
||||||
*/
|
*/
|
||||||
protected String getIdentityColumnString() throws MappingException {
|
protected String getIdentityColumnString() throws MappingException {
|
||||||
throw new MappingException( "Dialect does not support identity key generation" );
|
throw new MappingException( getClass().getName() + " does not support identity key generation" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -551,7 +551,7 @@ public abstract class Dialect {
|
||||||
* @throws MappingException If sequences are not supported.
|
* @throws MappingException If sequences are not supported.
|
||||||
*/
|
*/
|
||||||
public String getSequenceNextValString(String sequenceName) throws MappingException {
|
public String getSequenceNextValString(String sequenceName) throws MappingException {
|
||||||
throw new MappingException( "Dialect does not support sequences" );
|
throw new MappingException( getClass().getName() + " does not support sequences" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -566,7 +566,7 @@ public abstract class Dialect {
|
||||||
* @throws MappingException If sequences are not supported.
|
* @throws MappingException If sequences are not supported.
|
||||||
*/
|
*/
|
||||||
public String getSelectSequenceNextValString(String sequenceName) throws MappingException {
|
public String getSelectSequenceNextValString(String sequenceName) throws MappingException {
|
||||||
throw new MappingException( "Dialect does not support sequences" );
|
throw new MappingException( getClass().getName() + " does not support sequences" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -609,7 +609,7 @@ public abstract class Dialect {
|
||||||
* @throws MappingException If sequences are not supported.
|
* @throws MappingException If sequences are not supported.
|
||||||
*/
|
*/
|
||||||
protected String getCreateSequenceString(String sequenceName) throws MappingException {
|
protected String getCreateSequenceString(String sequenceName) throws MappingException {
|
||||||
throw new MappingException( "Dialect does not support sequences" );
|
throw new MappingException( getClass().getName() + " does not support sequences" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -633,7 +633,7 @@ public abstract class Dialect {
|
||||||
if ( supportsPooledSequences() ) {
|
if ( supportsPooledSequences() ) {
|
||||||
return getCreateSequenceString( sequenceName ) + " start with " + initialValue + " increment by " + incrementSize;
|
return getCreateSequenceString( sequenceName ) + " start with " + initialValue + " increment by " + incrementSize;
|
||||||
}
|
}
|
||||||
throw new MappingException( "Dialect does not support pooled sequences" );
|
throw new MappingException( getClass().getName() + " does not support pooled sequences" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -662,7 +662,7 @@ public abstract class Dialect {
|
||||||
* @throws MappingException If sequences are not supported.
|
* @throws MappingException If sequences are not supported.
|
||||||
*/
|
*/
|
||||||
protected String getDropSequenceString(String sequenceName) throws MappingException {
|
protected String getDropSequenceString(String sequenceName) throws MappingException {
|
||||||
throw new MappingException( "Dialect does not support sequences" );
|
throw new MappingException( getClass().getName() + " does not support sequences" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -686,7 +686,7 @@ public abstract class Dialect {
|
||||||
* @return The appropriate command.
|
* @return The appropriate command.
|
||||||
*/
|
*/
|
||||||
public String getSelectGUIDString() {
|
public String getSelectGUIDString() {
|
||||||
throw new UnsupportedOperationException( "dialect does not support GUIDs" );
|
throw new UnsupportedOperationException( getClass().getName() + " does not support GUIDs" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -802,7 +802,7 @@ public abstract class Dialect {
|
||||||
* @return the modified SQL
|
* @return the modified SQL
|
||||||
*/
|
*/
|
||||||
protected String getLimitString(String query, boolean hasOffset) {
|
protected String getLimitString(String query, boolean hasOffset) {
|
||||||
throw new UnsupportedOperationException( "paged queries not supported" );
|
throw new UnsupportedOperationException( "Paged queries not supported by " + getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1502,7 +1502,7 @@ public abstract class Dialect {
|
||||||
* @return The "add column" fragment.
|
* @return The "add column" fragment.
|
||||||
*/
|
*/
|
||||||
public String getAddColumnString() {
|
public String getAddColumnString() {
|
||||||
throw new UnsupportedOperationException( "No add column syntax supported by Dialect" );
|
throw new UnsupportedOperationException( "No add column syntax supported by " + getClass().getName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDropForeignKeyString() {
|
public String getDropForeignKeyString() {
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
|
import java.sql.Types;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.function.NoArgSQLFunction;
|
||||||
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dialect for Microsoft SQL 2005. (HHH-3936 fix)
|
||||||
|
*
|
||||||
|
* @author Yoryos Valotasios
|
||||||
|
*/
|
||||||
|
public class SQLServer2005Dialect extends SQLServerDialect {
|
||||||
|
private static final String SELECT = "select";
|
||||||
|
private static final String FROM = "from";
|
||||||
|
private static final String DISTINCT = "distinct";
|
||||||
|
private static final int MAX_LENGTH = 8000;
|
||||||
|
|
||||||
|
public SQLServer2005Dialect() {
|
||||||
|
// HHH-3965 fix
|
||||||
|
// As per http://www.sql-server-helper.com/faq/sql-server-2005-varchar-max-p01.aspx
|
||||||
|
// use varchar(max) and varbinary(max) instead of TEXT and IMAGE types
|
||||||
|
registerColumnType( Types.BLOB, "varbinary(MAX)" );
|
||||||
|
registerColumnType( Types.VARBINARY, "varbinary(MAX)" );
|
||||||
|
registerColumnType( Types.VARBINARY, MAX_LENGTH, "varbinary($l)" );
|
||||||
|
registerColumnType( Types.LONGVARBINARY, "varbinary(MAX)" );
|
||||||
|
|
||||||
|
registerColumnType( Types.CLOB, "varchar(MAX)" );
|
||||||
|
registerColumnType( Types.LONGVARCHAR, "varchar(MAX)" );
|
||||||
|
registerColumnType( Types.VARCHAR, "varchar(MAX)" );
|
||||||
|
registerColumnType( Types.VARCHAR, MAX_LENGTH, "varchar($l)" );
|
||||||
|
|
||||||
|
|
||||||
|
registerFunction("row_number", new NoArgSQLFunction("row_number", StandardBasicTypes.INTEGER, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsLimitOffset() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean bindLimitParametersFirst() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsVariableLimit() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int convertToFirstRowValue(int zeroBasedFirstResult) {
|
||||||
|
// Our dialect paginated results aren't zero based. The first row should get the number 1 and so on
|
||||||
|
return zeroBasedFirstResult + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLimitString(String query, int offset, int limit) {
|
||||||
|
// We transform the query to one with an offset and limit if we have an offset and limit to bind
|
||||||
|
if (offset > 1 || limit > 1) return getLimitString(query, true);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a LIMIT clause to the given SQL SELECT (HHH-2655: ROW_NUMBER for Paging)
|
||||||
|
*
|
||||||
|
* The LIMIT SQL will look like:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* WITH query AS (
|
||||||
|
* SELECT ROW_NUMBER() OVER (ORDER BY orderby) as __hibernate_row_nr__,
|
||||||
|
* original_query_without_orderby
|
||||||
|
* )
|
||||||
|
* SELECT * FROM query WHERE __hibernate_row_nr__ BEETWIN offset AND offset + last
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param querySqlString
|
||||||
|
* The SQL statement to base the limit query off of.
|
||||||
|
* @param offset
|
||||||
|
* Offset of the first row to be returned by the query (zero-based)
|
||||||
|
* @param limit
|
||||||
|
* Maximum number of rows to be returned by the query
|
||||||
|
*
|
||||||
|
* @return A new SQL statement with the LIMIT clause applied.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getLimitString(String querySqlString, boolean hasOffset) {
|
||||||
|
StringBuilder sb = new StringBuilder(querySqlString.trim().toLowerCase());
|
||||||
|
|
||||||
|
int orderByIndex = sb.indexOf("order by");
|
||||||
|
CharSequence orderby = orderByIndex > 0 ? sb.subSequence(orderByIndex, sb.length())
|
||||||
|
: "ORDER BY CURRENT_TIMESTAMP";
|
||||||
|
|
||||||
|
// Delete the order by clause at the end of the query
|
||||||
|
if (orderByIndex > 0) {
|
||||||
|
sb.delete(orderByIndex, orderByIndex + orderby.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// HHH-5715 bug fix
|
||||||
|
replaceDistinctWithGroupBy(sb);
|
||||||
|
|
||||||
|
insertRowNumberFunction(sb, orderby);
|
||||||
|
|
||||||
|
// Wrap the query within a with statement:
|
||||||
|
sb.insert(0, "WITH query AS (").append(") SELECT * FROM query ");
|
||||||
|
sb.append("WHERE __hibernate_row_nr__ BETWEEN ? AND ?");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method that checks if the given sql query is a select distinct one and if so replaces the distinct select
|
||||||
|
* with an equivalent simple select with a group by clause. See
|
||||||
|
* {@link SQLServer2005DialectTestCase#testReplaceDistinctWithGroupBy()}
|
||||||
|
*
|
||||||
|
* @param sql an sql query
|
||||||
|
*/
|
||||||
|
protected static void replaceDistinctWithGroupBy(StringBuilder sql) {
|
||||||
|
int distinctIndex = sql.indexOf(DISTINCT);
|
||||||
|
if (distinctIndex > 0) {
|
||||||
|
sql.delete(distinctIndex, distinctIndex + DISTINCT.length() + 1);
|
||||||
|
sql.append(" group by").append(getSelectFieldsWithoutAliases(sql));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This utility method searches the given sql query for the fields of the select statement and returns them without
|
||||||
|
* the aliases. See {@link SQLServer2005DialectTestCase#testGetSelectFieldsWithoutAliases()}
|
||||||
|
*
|
||||||
|
* @param an
|
||||||
|
* sql query
|
||||||
|
* @return the fields of the select statement without their alias
|
||||||
|
*/
|
||||||
|
protected static CharSequence getSelectFieldsWithoutAliases(StringBuilder sql) {
|
||||||
|
String select = sql.substring(sql.indexOf(SELECT) + SELECT.length(), sql.indexOf(FROM));
|
||||||
|
|
||||||
|
// Strip the as clauses
|
||||||
|
return stripAliases(select);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method that strips the aliases. See {@link SQLServer2005DialectTestCase#testStripAliases()}
|
||||||
|
*
|
||||||
|
* @param a
|
||||||
|
* string to replace the as statements
|
||||||
|
* @return a string without the as statements
|
||||||
|
*/
|
||||||
|
protected static String stripAliases(String str) {
|
||||||
|
return str.replaceAll("\\sas[^,]+(,?)", "$1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Right after the select statement of a given query we must place the row_number function
|
||||||
|
*
|
||||||
|
* @param sql
|
||||||
|
* the initial sql query without the order by clause
|
||||||
|
* @param orderby
|
||||||
|
* the order by clause of the query
|
||||||
|
*/
|
||||||
|
protected static void insertRowNumberFunction(StringBuilder sql, CharSequence orderby) {
|
||||||
|
// Find the end of the select statement
|
||||||
|
int selectEndIndex = sql.indexOf(SELECT) + SELECT.length();
|
||||||
|
|
||||||
|
// Insert after the select statement the row_number() function:
|
||||||
|
sql.insert(selectEndIndex, " ROW_NUMBER() OVER (" + orderby + ") as __hibernate_row_nr__,");
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ import org.hibernate.type.StandardBasicTypes;
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class SQLServer2008Dialect extends SQLServerDialect {
|
public class SQLServer2008Dialect extends SQLServer2005Dialect {
|
||||||
public SQLServer2008Dialect() {
|
public SQLServer2008Dialect() {
|
||||||
registerColumnType( Types.DATE, "date" );
|
registerColumnType( Types.DATE, "date" );
|
||||||
registerColumnType( Types.TIME, "time" );
|
registerColumnType( Types.TIME, "time" );
|
||||||
|
|
|
@ -26,22 +26,18 @@ package org.hibernate.dialect;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.dialect.function.AnsiTrimEmulationFunction;
|
|
||||||
import org.hibernate.dialect.function.SQLFunctionTemplate;
|
import org.hibernate.dialect.function.SQLFunctionTemplate;
|
||||||
import org.hibernate.dialect.function.StandardSQLFunction;
|
import org.hibernate.dialect.function.StandardSQLFunction;
|
||||||
|
import org.hibernate.dialect.function.AnsiTrimEmulationFunction;
|
||||||
import org.hibernate.type.StandardBasicTypes;
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dialect for Microsoft SQL Server 2000 and 2005
|
* A dialect for Microsoft SQL Server 2000
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class SQLServerDialect extends AbstractTransactSQLDialect {
|
public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
private static final String SELECT = "select";
|
|
||||||
private static final String FROM = "from";
|
|
||||||
private static final String DISTINCT = "distinct";
|
|
||||||
|
|
||||||
|
|
||||||
public SQLServerDialect() {
|
public SQLServerDialect() {
|
||||||
registerColumnType( Types.VARBINARY, "image" );
|
registerColumnType( Types.VARBINARY, "image" );
|
||||||
registerColumnType( Types.VARBINARY, 8000, "varbinary($l)" );
|
registerColumnType( Types.VARBINARY, 8000, "varbinary($l)" );
|
||||||
|
@ -72,103 +68,14 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
return selectIndex + ( selectDistinctIndex == selectIndex ? 15 : 6 );
|
return selectIndex + ( selectDistinctIndex == selectIndex ? 15 : 6 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public String getLimitString(String querySelect, int offset, int limit) {
|
||||||
* Add a LIMIT clause to the given SQL SELECT (HHH-2655: ROW_NUMBER for Paging)
|
if ( offset > 0 ) {
|
||||||
*
|
throw new UnsupportedOperationException( "query result offset is not supported" );
|
||||||
* The LIMIT SQL will look like:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* WITH query AS (SELECT ROW_NUMBER() OVER (ORDER BY orderby) as __hibernate_row_nr__, original_query_without_orderby)
|
|
||||||
* SELECT * FROM query WHERE __hibernate_row_nr__ BEETWIN offset AND offset + last
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param querySqlString The SQL statement to base the limit query off of.
|
|
||||||
* @param offset Offset of the first row to be returned by the query (zero-based)
|
|
||||||
* @param limit Maximum number of rows to be returned by the query
|
|
||||||
*
|
|
||||||
* @return A new SQL statement with the LIMIT clause applied.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getLimitString(String querySqlString, int offset, int limit) {
|
|
||||||
if ( offset == 0 ) {
|
|
||||||
return new StringBuffer( querySqlString.length() + 8 ).append( querySqlString )
|
|
||||||
.insert( getAfterSelectInsertPoint( querySqlString ), " top " + limit )
|
|
||||||
.toString();
|
|
||||||
}
|
}
|
||||||
|
return new StringBuffer( querySelect.length() + 8 )
|
||||||
StringBuilder sb = new StringBuilder( querySqlString.trim().toLowerCase() );
|
.append( querySelect )
|
||||||
|
.insert( getAfterSelectInsertPoint( querySelect ), " top " + limit )
|
||||||
int orderByIndex = sb.indexOf( "order by" );
|
.toString();
|
||||||
CharSequence orderby = orderByIndex > 0 ? sb.subSequence( orderByIndex, sb.length() ) : "ORDER BY CURRENT_TIMESTAMP";
|
|
||||||
|
|
||||||
// Delete the order by clause at the end of the query
|
|
||||||
if ( orderByIndex > 0 ) {
|
|
||||||
sb.delete( orderByIndex, orderByIndex + orderby.length() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// HHH-5715 bug fix
|
|
||||||
replaceDistinctWithGroupBy( sb );
|
|
||||||
|
|
||||||
insertRowNumberFunction( sb, orderby );
|
|
||||||
|
|
||||||
//Wrap the query within a with statement:
|
|
||||||
sb.insert( 0, "WITH query AS (").append(") SELECT * FROM query " );
|
|
||||||
sb.append( "WHERE __hibernate_row_nr__ BETWEEN " ).append(offset + 1).append( " AND " ).append( limit );
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility method that checks if the given sql query is a select distinct one and if so replaces the distinct
|
|
||||||
* select with an equivelant simple select with a group by clause. See {@link SQLServerDialectTestCase#testReplaceDistinctWithGroupBy()}
|
|
||||||
*
|
|
||||||
* @param an sql query
|
|
||||||
*/
|
|
||||||
protected static void replaceDistinctWithGroupBy(StringBuilder sql) {
|
|
||||||
int distinctIndex = sql.indexOf( DISTINCT );
|
|
||||||
if (distinctIndex > 0) {
|
|
||||||
sql.delete(distinctIndex, distinctIndex + DISTINCT.length() + 1);
|
|
||||||
sql.append(" group by").append(getSelectFieldsWithoutAliases(sql));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This utility method searches the given sql query for the fields of the select statement and
|
|
||||||
* returns them without the aliases. See {@link SQLServerDialectTestCase#testGetSelectFieldsWithoutAliases()}
|
|
||||||
*
|
|
||||||
* @param an sql query
|
|
||||||
* @return the fields of the select statement without their alias
|
|
||||||
*/
|
|
||||||
protected static CharSequence getSelectFieldsWithoutAliases(StringBuilder sql) {
|
|
||||||
String select = sql.substring( sql.indexOf(SELECT) + SELECT.length(), sql.indexOf(FROM));
|
|
||||||
|
|
||||||
// Strip the as clauses
|
|
||||||
return stripAliases( select );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility method that strips the aliases. See {@link SQLServerDialectTestCase#testStripAliases()}
|
|
||||||
*
|
|
||||||
* @param a string to replace the as statements
|
|
||||||
* @return a string without the as statements
|
|
||||||
*/
|
|
||||||
protected static String stripAliases(String str) {
|
|
||||||
return str.replaceAll( "\\sas[^,]+(,?)", "$1" );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Right after the select statement of a given query we must place the row_number function
|
|
||||||
*
|
|
||||||
* @param sql the initial sql query without the order by clause
|
|
||||||
* @param orderby the order by clause of the query
|
|
||||||
*/
|
|
||||||
protected static void insertRowNumberFunction(StringBuilder sql, CharSequence orderby) {
|
|
||||||
// Find the end of the select statement
|
|
||||||
int selectEndIndex = sql.indexOf( SELECT ) + SELECT.length();
|
|
||||||
|
|
||||||
// Isert after the select statement the row_number() function:
|
|
||||||
sql.insert( selectEndIndex, " ROW_NUMBER() OVER (" + orderby + ") as __hibernate_row_nr__," );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,11 +94,6 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean supportsLimitOffset() {
|
public boolean supportsLimitOffset() {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean bindLimitParametersFirst() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,9 +111,9 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
|
|
||||||
public String appendLockHint(LockMode mode, String tableName) {
|
public String appendLockHint(LockMode mode, String tableName) {
|
||||||
if ( ( mode == LockMode.UPGRADE ) ||
|
if ( ( mode == LockMode.UPGRADE ) ||
|
||||||
( mode == LockMode.UPGRADE_NOWAIT ) ||
|
( mode == LockMode.UPGRADE_NOWAIT ) ||
|
||||||
( mode == LockMode.PESSIMISTIC_WRITE ) ||
|
( mode == LockMode.PESSIMISTIC_WRITE ) ||
|
||||||
( mode == LockMode.WRITE ) ) {
|
( mode == LockMode.WRITE ) ) {
|
||||||
return tableName + " with (updlock, rowlock)";
|
return tableName + " with (updlock, rowlock)";
|
||||||
}
|
}
|
||||||
else if ( mode == LockMode.PESSIMISTIC_READ ) {
|
else if ( mode == LockMode.PESSIMISTIC_READ ) {
|
||||||
|
@ -224,7 +126,6 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
|
|
||||||
// The current_timestamp is more accurate, but only known to be supported
|
// The current_timestamp is more accurate, but only known to be supported
|
||||||
// in SQL Server 7.0 and later (i.e., Sybase not known to support it at all)
|
// in SQL Server 7.0 and later (i.e., Sybase not known to support it at all)
|
||||||
|
|
||||||
public String getCurrentTimestampSelectString() {
|
public String getCurrentTimestampSelectString() {
|
||||||
return "select current_timestamp";
|
return "select current_timestamp";
|
||||||
}
|
}
|
||||||
|
@ -260,3 +161,4 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ package org.hibernate.dialect;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.util.StringHelper;
|
import org.hibernate.util.StringHelper;
|
||||||
|
@ -65,8 +64,8 @@ import org.hibernate.util.StringHelper;
|
||||||
*/
|
*/
|
||||||
public class TypeNames {
|
public class TypeNames {
|
||||||
|
|
||||||
private HashMap weighted = new HashMap();
|
private Map<Integer, Map<Integer, String>> weighted = new HashMap<Integer, Map<Integer, String>>();
|
||||||
private HashMap defaults = new HashMap();
|
private Map<Integer, String> defaults = new HashMap<Integer, String>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get default type name for specified type
|
* get default type name for specified type
|
||||||
|
@ -74,7 +73,7 @@ public class TypeNames {
|
||||||
* @return the default type name associated with specified key
|
* @return the default type name associated with specified key
|
||||||
*/
|
*/
|
||||||
public String get(int typecode) throws MappingException {
|
public String get(int typecode) throws MappingException {
|
||||||
String result = (String) defaults.get( new Integer(typecode) );
|
String result = defaults.get( new Integer(typecode) );
|
||||||
if (result==null) throw new MappingException("No Dialect mapping for JDBC type: " + typecode);
|
if (result==null) throw new MappingException("No Dialect mapping for JDBC type: " + typecode);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -89,12 +88,10 @@ public class TypeNames {
|
||||||
* if available and the default type name otherwise
|
* if available and the default type name otherwise
|
||||||
*/
|
*/
|
||||||
public String get(int typecode, int size, int precision, int scale) throws MappingException {
|
public String get(int typecode, int size, int precision, int scale) throws MappingException {
|
||||||
Map map = (Map) weighted.get( new Integer(typecode) );
|
Map<Integer, String> map = weighted.get( new Integer(typecode) );
|
||||||
if ( map!=null && map.size()>0 ) {
|
if ( map!=null && map.size()>0 ) {
|
||||||
// iterate entries ordered by capacity to find first fit
|
// iterate entries ordered by capacity to find first fit
|
||||||
Iterator entries = map.entrySet().iterator();
|
for (Map.Entry<Integer, String> entry: map.entrySet()) {
|
||||||
while ( entries.hasNext() ) {
|
|
||||||
Map.Entry entry = (Map.Entry)entries.next();
|
|
||||||
if ( size <= ( (Integer) entry.getKey() ).intValue() ) {
|
if ( size <= ( (Integer) entry.getKey() ).intValue() ) {
|
||||||
return replace( (String) entry.getValue(), size, precision, scale );
|
return replace( (String) entry.getValue(), size, precision, scale );
|
||||||
}
|
}
|
||||||
|
@ -114,9 +111,9 @@ public class TypeNames {
|
||||||
* @param typecode the type key
|
* @param typecode the type key
|
||||||
*/
|
*/
|
||||||
public void put(int typecode, int capacity, String value) {
|
public void put(int typecode, int capacity, String value) {
|
||||||
TreeMap map = (TreeMap)weighted.get( new Integer(typecode) );
|
Map<Integer, String> map = weighted.get( new Integer(typecode) );
|
||||||
if (map == null) {// add new ordered map
|
if (map == null) {// add new ordered map
|
||||||
map = new TreeMap();
|
map = new TreeMap<Integer, String>();
|
||||||
weighted.put( new Integer(typecode), map );
|
weighted.put( new Integer(typecode), map );
|
||||||
}
|
}
|
||||||
map.put(new Integer(capacity), value);
|
map.put(new Integer(capacity), value);
|
||||||
|
|
|
@ -43,6 +43,8 @@ import org.hibernate.dialect.Oracle10gDialect;
|
||||||
import org.hibernate.dialect.Oracle8iDialect;
|
import org.hibernate.dialect.Oracle8iDialect;
|
||||||
import org.hibernate.dialect.Oracle9iDialect;
|
import org.hibernate.dialect.Oracle9iDialect;
|
||||||
import org.hibernate.dialect.PostgreSQLDialect;
|
import org.hibernate.dialect.PostgreSQLDialect;
|
||||||
|
import org.hibernate.dialect.SQLServer2005Dialect;
|
||||||
|
import org.hibernate.dialect.SQLServer2008Dialect;
|
||||||
import org.hibernate.dialect.SQLServerDialect;
|
import org.hibernate.dialect.SQLServerDialect;
|
||||||
import org.hibernate.dialect.SybaseASE15Dialect;
|
import org.hibernate.dialect.SybaseASE15Dialect;
|
||||||
import org.hibernate.dialect.SybaseAnywhereDialect;
|
import org.hibernate.dialect.SybaseAnywhereDialect;
|
||||||
|
@ -88,7 +90,6 @@ public class StandardDialectResolver extends AbstractDialectResolver {
|
||||||
}
|
}
|
||||||
return new IngresDialect();
|
return new IngresDialect();
|
||||||
case 10:
|
case 10:
|
||||||
log.warn( "Ingres " + databaseMajorVersion + " is not yet fully supported; using Ingres 9.3 dialect" );
|
|
||||||
return new Ingres10Dialect();
|
return new Ingres10Dialect();
|
||||||
default:
|
default:
|
||||||
log.warn( "Unknown Ingres major version [" + databaseMajorVersion + "] using Ingres 9.2 dialect" );
|
log.warn( "Unknown Ingres major version [" + databaseMajorVersion + "] using Ingres 9.2 dialect" );
|
||||||
|
@ -97,6 +98,16 @@ public class StandardDialectResolver extends AbstractDialectResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( databaseName.startsWith( "Microsoft SQL Server" ) ) {
|
if ( databaseName.startsWith( "Microsoft SQL Server" ) ) {
|
||||||
|
switch ( databaseMajorVersion ) {
|
||||||
|
case 8:
|
||||||
|
return new SQLServerDialect();
|
||||||
|
case 9:
|
||||||
|
return new SQLServer2005Dialect();
|
||||||
|
case 10:
|
||||||
|
return new SQLServer2008Dialect();
|
||||||
|
default:
|
||||||
|
log.warn( "Unknown Microsoft SQL Server major version [" + databaseMajorVersion + "] using SQL Server 2000 dialect" );
|
||||||
|
}
|
||||||
return new SQLServerDialect();
|
return new SQLServerDialect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +130,6 @@ public class StandardDialectResolver extends AbstractDialectResolver {
|
||||||
if ( "Oracle".equals( databaseName ) ) {
|
if ( "Oracle".equals( databaseName ) ) {
|
||||||
switch ( databaseMajorVersion ) {
|
switch ( databaseMajorVersion ) {
|
||||||
case 11:
|
case 11:
|
||||||
log.warn( "Oracle 11g is not yet fully supported; using 10g dialect" );
|
|
||||||
return new Oracle10gDialect();
|
return new Oracle10gDialect();
|
||||||
case 10:
|
case 10:
|
||||||
return new Oracle10gDialect();
|
return new Oracle10gDialect();
|
||||||
|
|
|
@ -8,17 +8,17 @@ import junit.framework.TestCase;
|
||||||
* @author Valotasion Yoryos
|
* @author Valotasion Yoryos
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class SQLServerDialectTestCase extends TestCase {
|
public class SQLServer2005DialectTestCase extends TestCase {
|
||||||
|
|
||||||
public void testStripAliases() {
|
public void testStripAliases() {
|
||||||
String input = "some_field1 as f1, some_fild2 as f2, _field3 as f3 ";
|
String input = "some_field1 as f1, some_fild2 as f2, _field3 as f3 ";
|
||||||
|
|
||||||
assertEquals( "some_field1, some_fild2, _field3", SQLServerDialect.stripAliases(input) );
|
assertEquals( "some_field1, some_fild2, _field3", SQLServer2005Dialect.stripAliases(input) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetSelectFieldsWithoutAliases() {
|
public void testGetSelectFieldsWithoutAliases() {
|
||||||
StringBuilder input = new StringBuilder( "select some_field1 as f12, some_fild2 as f879, _field3 as _f24674_3 from...." );
|
StringBuilder input = new StringBuilder( "select some_field1 as f12, some_fild2 as f879, _field3 as _f24674_3 from...." );
|
||||||
String output = SQLServerDialect.getSelectFieldsWithoutAliases( input ).toString();
|
String output = SQLServer2005Dialect.getSelectFieldsWithoutAliases( input ).toString();
|
||||||
|
|
||||||
assertEquals( " some_field1, some_fild2, _field3", output );
|
assertEquals( " some_field1, some_fild2, _field3", output );
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ public class SQLServerDialectTestCase extends TestCase {
|
||||||
|
|
||||||
public void testReplaceDistinctWithGroupBy() {
|
public void testReplaceDistinctWithGroupBy() {
|
||||||
StringBuilder input = new StringBuilder( "select distinct f1, f2 as ff, f3 from table where f1 = 5" );
|
StringBuilder input = new StringBuilder( "select distinct f1, f2 as ff, f3 from table where f1 = 5" );
|
||||||
SQLServerDialect.replaceDistinctWithGroupBy( input );
|
SQLServer2005Dialect.replaceDistinctWithGroupBy( input );
|
||||||
|
|
||||||
assertEquals( "select f1, f2 as ff, f3 from table where f1 = 5 group by f1, f2, f3 ", input.toString() );
|
assertEquals( "select f1, f2 as ff, f3 from table where f1 = 5 group by f1, f2, f3 ", input.toString() );
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,7 @@ public class SQLServerDialectTestCase extends TestCase {
|
||||||
public void testGetLimitString() {
|
public void testGetLimitString() {
|
||||||
String input = "select distinct f1 as f53245 from table849752 order by f234, f67 desc";
|
String input = "select distinct f1 as f53245 from table849752 order by f234, f67 desc";
|
||||||
|
|
||||||
SQLServerDialect sqlDialect = new SQLServerDialect();
|
Dialect sqlDialect = new SQLServer2005Dialect();
|
||||||
|
assertEquals( "with query as (select row_number() over (order by f234, f67 desc) as __hibernate_row_nr__, f1 as f53245 from table849752 group by f1) select * from query where __hibernate_row_nr__ between ? and ?", sqlDialect.getLimitString(input, 10, 15).toLowerCase() );
|
||||||
assertEquals( "with query as (select row_number() over (order by f234, f67 desc) as __hibernate_row_nr__, f1 as f53245 from table849752 group by f1) select * from query where __hibernate_row_nr__ between 11 and 15", sqlDialect.getLimitString(input, 10, 15).toLowerCase() );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue