some cleanups in OracleDialect

This commit is contained in:
Gavin 2022-12-28 11:27:59 +01:00 committed by Gavin King
parent 81851dc985
commit 33fec62a56
4 changed files with 69 additions and 68 deletions

View File

@ -48,7 +48,6 @@ import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Sequence;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.aggregate.AggregateSupport;
import org.hibernate.dialect.aggregate.AggregateSupportImpl;
import org.hibernate.dialect.function.CastFunction;
@ -192,6 +191,9 @@ import jakarta.persistence.TemporalType;
import static java.lang.Math.ceil;
import static java.lang.Math.log;
import static org.hibernate.cfg.AvailableSettings.NON_CONTEXTUAL_LOB_CREATION;
import static org.hibernate.cfg.AvailableSettings.STATEMENT_BATCH_SIZE;
import static org.hibernate.cfg.AvailableSettings.USE_GET_GENERATED_KEYS;
import static org.hibernate.internal.util.StringHelper.parseCommaSeparatedString;
import static org.hibernate.type.SqlTypes.ARRAY;
import static org.hibernate.type.SqlTypes.BIGINT;
@ -345,11 +347,11 @@ public abstract class Dialect implements ConversionContext {
* Set appropriate default values for configuration properties.
*/
protected void initDefaultProperties() {
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE,
getDefaultProperties().setProperty( STATEMENT_BATCH_SIZE,
Integer.toString( getDefaultStatementBatchSize() ) );
getDefaultProperties().setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION,
getDefaultProperties().setProperty( NON_CONTEXTUAL_LOB_CREATION,
Boolean.toString( getDefaultNonContextualLobCreation() ) );
getDefaultProperties().setProperty( Environment.USE_GET_GENERATED_KEYS,
getDefaultProperties().setProperty( USE_GET_GENERATED_KEYS,
Boolean.toString( getDefaultUseGetGeneratedKeys() ) );
}
@ -1388,7 +1390,7 @@ public abstract class Dialect implements ConversionContext {
/**
* The default value to use for the configuration property
* {@value Environment#STATEMENT_BATCH_SIZE}.
* {@value org.hibernate.cfg.Environment#STATEMENT_BATCH_SIZE}.
*/
public int getDefaultStatementBatchSize() {
return 1;
@ -1396,7 +1398,7 @@ public abstract class Dialect implements ConversionContext {
/**
* The default value to use for the configuration property
* {@value Environment#NON_CONTEXTUAL_LOB_CREATION}.
* {@value org.hibernate.cfg.Environment#NON_CONTEXTUAL_LOB_CREATION}.
*/
public boolean getDefaultNonContextualLobCreation() {
return false;
@ -1404,7 +1406,7 @@ public abstract class Dialect implements ConversionContext {
/**
* The default value to use for the configuration property
* {@value Environment#USE_GET_GENERATED_KEYS}.
* {@value org.hibernate.cfg.Environment#USE_GET_GENERATED_KEYS}.
*/
public boolean getDefaultUseGetGeneratedKeys() {
return true;

View File

@ -11,14 +11,12 @@ import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.LockOptions;
import org.hibernate.QueryTimeoutException;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.aggregate.AggregateSupport;
import org.hibernate.dialect.aggregate.OracleAggregateSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
@ -47,7 +45,6 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
@ -91,7 +88,10 @@ import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.TemporalType;
import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static org.hibernate.cfg.AvailableSettings.BATCH_VERSIONED_DATA;
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.query.sqm.TemporalUnit.DAY;
import static org.hibernate.query.sqm.TemporalUnit.HOUR;
import static org.hibernate.query.sqm.TemporalUnit.MINUTE;
@ -128,11 +128,14 @@ import static org.hibernate.type.SqlTypes.VARCHAR;
*/
public class OracleDialect extends Dialect {
private static final Pattern DISTINCT_KEYWORD_PATTERN = Pattern.compile( "\\bdistinct\\b" );
private static final Pattern GROUP_BY_KEYWORD_PATTERN = Pattern.compile( "\\bgroup\\sby\\b" );
private static final Pattern ORDER_BY_KEYWORD_PATTERN = Pattern.compile( "\\border\\sby\\b" );
private static final Pattern UNION_KEYWORD_PATTERN = Pattern.compile( "\\bunion\\b" );
private static final Pattern SQL_STATEMENT_TYPE_PATTERN = Pattern.compile("^(?:/\\*.*?\\*/)?\\s*(select|insert|update|delete)\\s+.*?", Pattern.CASE_INSENSITIVE);
private static final Pattern DISTINCT_KEYWORD_PATTERN = Pattern.compile( "\\bdistinct\\b", CASE_INSENSITIVE );
private static final Pattern GROUP_BY_KEYWORD_PATTERN = Pattern.compile( "\\bgroup\\s+by\\b", CASE_INSENSITIVE );
private static final Pattern ORDER_BY_KEYWORD_PATTERN = Pattern.compile( "\\border\\s+by\\b", CASE_INSENSITIVE );
private static final Pattern UNION_KEYWORD_PATTERN = Pattern.compile( "\\bunion\\b", CASE_INSENSITIVE );
private static final Pattern SQL_STATEMENT_TYPE_PATTERN =
Pattern.compile( "^(?:/\\*.*?\\*/)?\\s*(select|insert|update|delete)\\s+.*?", CASE_INSENSITIVE );
private static final int PARAM_LIST_SIZE_LIMIT = 1000;
public static final String PREFER_LONG_RAW = "hibernate.dialect.oracle.prefer_long_raw";
@ -683,7 +686,8 @@ public class OracleDialect extends Dialect {
@Override
protected void initDefaultProperties() {
super.initDefaultProperties();
getDefaultProperties().setProperty( Environment.BATCH_VERSIONED_DATA, Boolean.toString( getVersion().isSameOrAfter( 12 ) ) );
getDefaultProperties().setProperty( BATCH_VERSIONED_DATA,
Boolean.toString( getVersion().isSameOrAfter( 12 ) ) );
}
@Override
@ -1066,50 +1070,35 @@ public class OracleDialect extends Dialect {
}
/**
* For Oracle, the FOR UPDATE clause cannot be applied when using ORDER BY, DISTINCT or views.
* The {@code FOR UPDATE} clause cannot be applied when using {@code ORDER BY}, {@code DISTINCT} or views.
*
* @see <a href="https://docs.oracle.com/database/121/SQLRF/statements_10002.htm#SQLRF01702">Oracle FOR UPDATE restrictions</a>
* @see <a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/SELECT.html">Oracle FOR UPDATE restrictions</a>
*/
@Override
public boolean useFollowOnLocking(String sql, QueryOptions queryOptions) {
if ( StringHelper.isEmpty( sql ) || queryOptions == null ) {
if ( isEmpty( sql ) || queryOptions == null ) {
// ugh, used by DialectFeatureChecks (gotta be a better way)
return true;
}
sql = sql.toLowerCase( Locale.ROOT );
return DISTINCT_KEYWORD_PATTERN.matcher( sql ).find()
|| GROUP_BY_KEYWORD_PATTERN.matcher( sql ).find()
|| UNION_KEYWORD_PATTERN.matcher( sql ).find()
|| (
queryOptions.hasLimit()
&& (
ORDER_BY_KEYWORD_PATTERN.matcher( sql ).find()
|| queryOptions.getLimit().getFirstRow() != null
)
);
|| GROUP_BY_KEYWORD_PATTERN.matcher( sql ).find()
|| UNION_KEYWORD_PATTERN.matcher( sql ).find()
|| ORDER_BY_KEYWORD_PATTERN.matcher( sql ).find() && queryOptions.hasLimit()
|| queryOptions.hasLimit() && queryOptions.getLimit().getFirstRow() != null;
}
@Override
public String getQueryHintString(String sql, String hints) {
String statementType = statementType(sql);
final int pos = sql.indexOf( statementType );
if ( pos > -1 ) {
final StringBuilder buffer = new StringBuilder( sql.length() + hints.length() + 8 );
if ( pos > 0 ) {
buffer.append( sql, 0, pos );
}
buffer
.append( statementType )
.append( " /*+ " )
.append( hints )
.append( " */" )
.append( sql.substring( pos + statementType.length() ) );
sql = buffer.toString();
final String statementType = statementType( sql );
final int start = sql.indexOf( statementType );
if ( start < 0 ) {
return sql;
}
else {
int end = start + statementType.length();
return sql.substring( 0, end ) + " /*+ " + hints + " */" + sql.substring( end );
}
return sql;
}
@Override
@ -1147,13 +1136,13 @@ public class OracleDialect extends Dialect {
}
private String statementType(String sql) {
Matcher matcher = SQL_STATEMENT_TYPE_PATTERN.matcher( sql );
final Matcher matcher = SQL_STATEMENT_TYPE_PATTERN.matcher( sql );
if ( matcher.matches() && matcher.groupCount() == 1 ) {
return matcher.group(1);
}
throw new IllegalArgumentException( "Can't determine SQL statement type for statement: " + sql );
else {
throw new IllegalArgumentException( "Can't determine SQL statement type for statement: " + sql );
}
}
@Override

View File

@ -18,7 +18,7 @@ public enum JdbcLockStrategy {
*/
AUTO,
/**
* Use follow on locking.
* Use follow-on locking.
*/
FOLLOW_ON,
/**

View File

@ -20,7 +20,6 @@ import org.hibernate.dialect.pagination.NoopLimitHandler;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.query.spi.Limit;
@ -92,20 +91,11 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess {
}
final LockOptions lockOptions = queryOptions.getLockOptions();
boolean followOnLocking = false;
if ( lockOptions != null && !lockOptions.isEmpty() && jdbcSelect.getLockStrategy() != JdbcLockStrategy.NONE ) {
switch ( jdbcSelect.getLockStrategy() ) {
case FOLLOW_ON:
followOnLocking = true;
break;
case AUTO:
if ( lockOptions.getFollowOnLocking() == null && dialect.useFollowOnLocking( sql, queryOptions )
|| Boolean.TRUE.equals( lockOptions.getFollowOnLocking() ) ) {
followOnLocking = true;
}
break;
}
if ( followOnLocking ) {
final JdbcLockStrategy jdbcLockStrategy = jdbcSelect.getLockStrategy();
if ( jdbcLockStrategy != JdbcLockStrategy.NONE
&& lockOptions != null && !lockOptions.isEmpty() ) {
usesFollowOnLocking = useFollowOnLocking( jdbcLockStrategy, sql, queryOptions, lockOptions, dialect );
if ( usesFollowOnLocking ) {
final LockMode lockMode = determineFollowOnLockMode( lockOptions );
if ( lockMode != LockMode.UPGRADE_SKIPLOCKED ) {
// Dialect prefers to perform locking in a separate step
@ -131,7 +121,9 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess {
sql = dialect.applyLocksToSql( sql, lockOptions, Collections.emptyMap() );
}
}
usesFollowOnLocking = followOnLocking;
else {
usesFollowOnLocking = false;
}
finalSql = dialect.addSqlHintOrComment(
sql,
queryOptions,
@ -140,6 +132,24 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess {
}
}
private static boolean useFollowOnLocking(
JdbcLockStrategy jdbcLockStrategy,
String sql,
QueryOptions queryOptions,
LockOptions lockOptions,
Dialect dialect) {
switch ( jdbcLockStrategy ) {
case FOLLOW_ON:
return true;
case AUTO:
return lockOptions.getFollowOnLocking() == null
? dialect.useFollowOnLocking( sql, queryOptions )
: lockOptions.getFollowOnLocking();
default:
return false;
}
}
public LimitHandler getLimitHandler() {
return limitHandler;
}