SQLServer2005Dialect: supports sql server 2005 but not 2000
This commit is contained in:
parent
2ec009440e
commit
e3ad6c881e
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* 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 org.hibernate.dialect.function.NoArgSQLFunction;
|
||||||
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dialect for Microsoft SQL 2005
|
||||||
|
*
|
||||||
|
* @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";
|
||||||
|
|
||||||
|
public SQLServer2005Dialect() {
|
||||||
|
registerFunction("row_number", new NoArgSQLFunction("row_number", StandardBasicTypes.INTEGER, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, int offset, int limit) {
|
||||||
|
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 ").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 SQLServer2005DialectTestCase#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 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();
|
||||||
|
|
||||||
|
// Isert after the select statement the row_number() function:
|
||||||
|
sql.insert(selectEndIndex, " ROW_NUMBER() OVER (" + orderby + ") as __hibernate_row_nr__,");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsLimit() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useMaxForLimit() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsLimitOffset() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean bindLimitParametersFirst() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supportsVariableLimit() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue