HHH-17759 Avoid costly string search and replace
This commit is contained in:
parent
b9aa76625b
commit
1d1278e58d
|
@ -283,4 +283,11 @@ public interface DeprecationLogger extends BasicLogger {
|
|||
)
|
||||
void deprecatedSettingNoReplacement(String settingName);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(
|
||||
id = 90000031,
|
||||
value = "The native query colon escaping used for the [%s] operator is deprecated and will be removed. Use [%s] instead."
|
||||
)
|
||||
void deprecatedNativeQueryColonEscaping(String oldOperator, String newOperator);
|
||||
|
||||
}
|
||||
|
|
|
@ -53,7 +53,6 @@ public class ParameterParser {
|
|||
*/
|
||||
public static void parse(String sqlString, ParameterRecognizer recognizer, boolean nativeJdbcParametersIgnored) throws QueryException {
|
||||
checkIsNotAFunctionCall( sqlString );
|
||||
sqlString = preprocessing(sqlString);
|
||||
final int stringLength = sqlString.length();
|
||||
|
||||
boolean inSingleQuotes = false;
|
||||
|
@ -130,8 +129,8 @@ public class ParameterParser {
|
|||
}
|
||||
// otherwise
|
||||
else {
|
||||
if ( c == ':' && indx < stringLength - 1 && Character.isJavaIdentifierStart( sqlString.charAt( indx + 1 ) )
|
||||
&& !(0 < indx && sqlString.charAt( indx - 1 ) == ':')) {
|
||||
if ( c == ':' ) {
|
||||
if ( indx < stringLength - 1 && Character.isJavaIdentifierStart( sqlString.charAt( indx + 1 ) ) ) {
|
||||
// named parameter
|
||||
final int right = StringHelper.firstIndexOfChar( sqlString, HQL_SEPARATORS_BITSET, indx + 1 );
|
||||
final int chopLocation = right < 0 ? sqlString.length() : right;
|
||||
|
@ -145,6 +144,38 @@ public class ParameterParser {
|
|||
recognizer.namedParameter( param, indx );
|
||||
indx = chopLocation - 1;
|
||||
}
|
||||
else {
|
||||
// For backwards compatibility, allow some known operators in the escaped form
|
||||
if ( indx < stringLength - 3
|
||||
&& sqlString.charAt( indx + 1 ) == ':'
|
||||
&& sqlString.charAt( indx + 2 ) == ':'
|
||||
&& sqlString.charAt( indx + 3 ) == ':' ) {
|
||||
// Detect the :: operator, escaped as ::::
|
||||
DeprecationLogger.DEPRECATION_LOGGER.deprecatedNativeQueryColonEscaping( "::::", "::" );
|
||||
recognizer.other( ':' );
|
||||
recognizer.other( ':' );
|
||||
indx += 3;
|
||||
}
|
||||
else if ( indx < stringLength - 2
|
||||
&& sqlString.charAt( indx + 1 ) == ':'
|
||||
&& sqlString.charAt( indx + 2 ) == '=' ) {
|
||||
// Detect the := operator, escaped as ::=
|
||||
DeprecationLogger.DEPRECATION_LOGGER.deprecatedNativeQueryColonEscaping( "::=", ":=" );
|
||||
recognizer.other( ':' );
|
||||
recognizer.other( '=' );
|
||||
indx += 2;
|
||||
}
|
||||
else {
|
||||
recognizer.other( ':' );
|
||||
// Consume all following colons as they are eagerly to not confuse named parameter detection
|
||||
while ( indx < stringLength - 1
|
||||
&& sqlString.charAt( indx + 1 ) == ':' ) {
|
||||
indx++;
|
||||
recognizer.other( ':' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( c == '?' ) {
|
||||
// could be either a positional or JPA-style ordinal parameter
|
||||
if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
|
||||
|
@ -176,19 +207,6 @@ public class ParameterParser {
|
|||
recognizer.complete();
|
||||
}
|
||||
|
||||
private static String preprocessing(String sqlString) {
|
||||
final Map<String, String> preprocessingExchangeMap = Map.of("::=", ":=", "::::", "::");
|
||||
for (Map.Entry<String, String> entry : preprocessingExchangeMap.entrySet()) {
|
||||
final String preprocessedSqlString = sqlString.replace(entry.getKey(), entry.getValue());
|
||||
if (!sqlString.equals(preprocessedSqlString)) {
|
||||
DeprecationLogger.DEPRECATION_LOGGER.warn(
|
||||
String.format("An unconventional syntax has been used in the SQL statement. It is recommended to use '%s' instead of '%s'.", entry.getValue(), entry.getKey()));
|
||||
sqlString = preprocessedSqlString;
|
||||
}
|
||||
}
|
||||
return sqlString;
|
||||
}
|
||||
|
||||
public static void parse(String sqlString, ParameterRecognizer recognizer) throws QueryException {
|
||||
parse( sqlString, recognizer, false );
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.hibernate.engine.query.ParameterRecognitionException;
|
|||
import org.hibernate.engine.query.internal.NativeQueryInterpreterStandardImpl;
|
||||
import org.hibernate.query.sql.internal.ParameterParser;
|
||||
import org.hibernate.query.sql.spi.ParameterRecognizer;
|
||||
|
||||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -216,7 +217,10 @@ public class ParameterParserTest {
|
|||
@Test
|
||||
public void testParseNamedParameter() {
|
||||
ExtendedParameterRecognizer recognizer = createRecognizer();
|
||||
NATIVE_QUERY_INTERPRETER.recognizeParameters("from Stock s where s.stockCode = :stockCode and s.xyz = :pxyz", recognizer);
|
||||
NATIVE_QUERY_INTERPRETER.recognizeParameters(
|
||||
"from Stock s where s.stockCode = :stockCode and s.xyz = :pxyz",
|
||||
recognizer
|
||||
);
|
||||
recognizer.complete();
|
||||
recognizer.validate();
|
||||
|
||||
|
@ -289,8 +293,11 @@ public class ParameterParserTest {
|
|||
|
||||
private interface ExtendedParameterRecognizer extends org.hibernate.query.sql.spi.ParameterRecognizer {
|
||||
void validate();
|
||||
|
||||
int getOrdinalParameterCount();
|
||||
|
||||
int getJpaPositionalParameterCount();
|
||||
|
||||
Set<String> getNamedParameters();
|
||||
}
|
||||
|
||||
|
@ -346,7 +353,8 @@ public class ParameterParserTest {
|
|||
}
|
||||
|
||||
private ParameterRecognitionException mixedParamStrategy() {
|
||||
throw new ParameterRecognitionException( "Mixed parameter strategies - use just one of named, positional or JPA-ordinal strategy" );
|
||||
throw new ParameterRecognitionException(
|
||||
"Mixed parameter strategies - use just one of named, positional or JPA-ordinal strategy" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue