some cleanups in OracleDialect
This commit is contained in:
parent
81851dc985
commit
33fec62a56
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -18,7 +18,7 @@ public enum JdbcLockStrategy {
|
|||
*/
|
||||
AUTO,
|
||||
/**
|
||||
* Use follow on locking.
|
||||
* Use follow-on locking.
|
||||
*/
|
||||
FOLLOW_ON,
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue