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

View File

@ -11,14 +11,12 @@
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.QueryTimeoutException; import org.hibernate.QueryTimeoutException;
import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.aggregate.AggregateSupport; import org.hibernate.dialect.aggregate.AggregateSupport;
import org.hibernate.dialect.aggregate.OracleAggregateSupport; import org.hibernate.dialect.aggregate.OracleAggregateSupport;
import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.function.CommonFunctionFactory;
@ -47,7 +45,6 @@
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor; import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.StandardCallableStatementSupport; import org.hibernate.procedure.internal.StandardCallableStatementSupport;
@ -91,7 +88,10 @@
import jakarta.persistence.TemporalType; 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.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.DAY;
import static org.hibernate.query.sqm.TemporalUnit.HOUR; import static org.hibernate.query.sqm.TemporalUnit.HOUR;
import static org.hibernate.query.sqm.TemporalUnit.MINUTE; import static org.hibernate.query.sqm.TemporalUnit.MINUTE;
@ -128,11 +128,14 @@
*/ */
public class OracleDialect extends Dialect { public class OracleDialect extends Dialect {
private static final Pattern DISTINCT_KEYWORD_PATTERN = Pattern.compile( "\\bdistinct\\b" ); private static final Pattern DISTINCT_KEYWORD_PATTERN = Pattern.compile( "\\bdistinct\\b", CASE_INSENSITIVE );
private static final Pattern GROUP_BY_KEYWORD_PATTERN = Pattern.compile( "\\bgroup\\sby\\b" ); 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\\sby\\b" ); 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" ); 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+.*?", Pattern.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; private static final int PARAM_LIST_SIZE_LIMIT = 1000;
public static final String PREFER_LONG_RAW = "hibernate.dialect.oracle.prefer_long_raw"; public static final String PREFER_LONG_RAW = "hibernate.dialect.oracle.prefer_long_raw";
@ -683,7 +686,8 @@ public TimeZoneSupport getTimeZoneSupport() {
@Override @Override
protected void initDefaultProperties() { protected void initDefaultProperties() {
super.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 @Override
@ -1066,50 +1070,35 @@ public String getTemporaryTableCreateOptions() {
} }
/** /**
* 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 @Override
public boolean useFollowOnLocking(String sql, QueryOptions queryOptions) { 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; return true;
} }
sql = sql.toLowerCase( Locale.ROOT );
return DISTINCT_KEYWORD_PATTERN.matcher( sql ).find() return DISTINCT_KEYWORD_PATTERN.matcher( sql ).find()
|| GROUP_BY_KEYWORD_PATTERN.matcher( sql ).find() || GROUP_BY_KEYWORD_PATTERN.matcher( sql ).find()
|| UNION_KEYWORD_PATTERN.matcher( sql ).find() || UNION_KEYWORD_PATTERN.matcher( sql ).find()
|| ( || ORDER_BY_KEYWORD_PATTERN.matcher( sql ).find() && queryOptions.hasLimit()
queryOptions.hasLimit() || queryOptions.hasLimit() && queryOptions.getLimit().getFirstRow() != null;
&& (
ORDER_BY_KEYWORD_PATTERN.matcher( sql ).find()
|| queryOptions.getLimit().getFirstRow() != null
)
);
} }
@Override @Override
public String getQueryHintString(String sql, String hints) { public String getQueryHintString(String sql, String hints) {
String statementType = statementType(sql); final String statementType = statementType( sql );
final int start = sql.indexOf( statementType );
final int pos = sql.indexOf( statementType ); if ( start < 0 ) {
if ( pos > -1 ) { return sql;
final StringBuilder buffer = new StringBuilder( sql.length() + hints.length() + 8 ); }
if ( pos > 0 ) { else {
buffer.append( sql, 0, pos ); int end = start + statementType.length();
} return sql.substring( 0, end ) + " /*+ " + hints + " */" + sql.substring( end );
buffer
.append( statementType )
.append( " /*+ " )
.append( hints )
.append( " */" )
.append( sql.substring( pos + statementType.length() ) );
sql = buffer.toString();
} }
return sql;
} }
@Override @Override
@ -1147,13 +1136,13 @@ public boolean supportsPartitionBy() {
} }
private String statementType(String sql) { 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 ) { if ( matcher.matches() && matcher.groupCount() == 1 ) {
return matcher.group(1); return matcher.group(1);
} }
else {
throw new IllegalArgumentException( "Can't determine SQL statement type for statement: " + sql ); throw new IllegalArgumentException( "Can't determine SQL statement type for statement: " + sql );
}
} }
@Override @Override

View File

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

View File

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