package org.hibernate.dialect;
import java.sql.Types;
import java.util.Locale;
import org.hibernate.LockOptions;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.sql.ANSICaseFragment;
import org.hibernate.sql.CaseFragment;
public class Oracle9iDialect extends Oracle8iDialect {
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow( selection );
sql = sql.trim();
String forUpdateClause = null;
boolean isForUpdate = false;
final int forUpdateIndex = sql.toLowerCase(Locale.ROOT).lastIndexOf( "for update" );
if (forUpdateIndex > -1) {
forUpdateClause = sql.substring( forUpdateIndex );
sql = sql.substring( 0, forUpdateIndex - 1 );
isForUpdate = true;
}
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 );
if (hasOffset) {
pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " );
}
else {
pagingSelect.append( "select * from ( " );
}
pagingSelect.append( sql );
if (hasOffset) {
pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" );
}
else {
pagingSelect.append( " ) where rownum <= ?" );
}
if (isForUpdate) {
pagingSelect.append( " " );
pagingSelect.append( forUpdateClause );
}
return pagingSelect.toString();
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
@Override
public boolean useMaxForLimit() {
return true;
}
};
@Override
protected void registerCharacterTypeMappings() {
registerColumnType( Types.CHAR, "char(1 char)" );
registerColumnType( Types.VARCHAR, 4000, "varchar2($l char)" );
registerColumnType( Types.VARCHAR, "long" );
registerColumnType( Types.NVARCHAR, "nvarchar2($l)" );
registerColumnType( Types.LONGNVARCHAR, "nvarchar2($l)" );
}
@Override
protected void registerDateTimeTypeMappings() {
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "date" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
}
@Override
public CaseFragment createCaseFragment() {
return new ANSICaseFragment();
}
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
}
@Override
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
String forUpdateClause = null;
boolean isForUpdate = false;
final int forUpdateIndex = sql.toLowerCase(Locale.ROOT).lastIndexOf( "for update") ;
if ( forUpdateIndex > -1 ) {
forUpdateClause = sql.substring( forUpdateIndex );
sql = sql.substring( 0, forUpdateIndex-1 );
isForUpdate = true;
}
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 );
if (hasOffset) {
pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " );
}
else {
pagingSelect.append( "select * from ( " );
}
pagingSelect.append( sql );
if (hasOffset) {
pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" );
}
else {
pagingSelect.append( " ) where rownum <= ?" );
}
if ( isForUpdate ) {
pagingSelect.append( " " );
pagingSelect.append( forUpdateClause );
}
return pagingSelect.toString();
}
@Override
public String getSelectClauseNullString(int sqlType) {
return getBasicSelectClauseNullString( sqlType );
}
@Override
public String getCurrentTimestampSelectString() {
return "select systimestamp from dual";
}
@Override
public String getCurrentTimestampSQLFunctionName() {
return "current_timestamp";
}
@Override
public String getForUpdateString() {
return " for update";
}
@Override
public String getWriteLockString(int timeout) {
if ( timeout == LockOptions.NO_WAIT ) {
return " for update nowait";
}
else if ( timeout > 0 ) {
final float seconds = timeout / 1000.0f;
timeout = Math.round( seconds );
return " for update wait " + timeout;
}
else {
return " for update";
}
}
@Override
public String getReadLockString(int timeout) {
return getWriteLockString( timeout );
}
@Override
public boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}
@Override
public boolean supportsTupleDistinctCounts() {
return false;
}
}