HHH-17759 Avoid need for undocumented escaping of colon characters in native queries

This commit is contained in:
dgh 2024-02-28 10:50:11 +09:00 committed by Christian Beikov
parent adbf8946da
commit b9aa76625b
2 changed files with 62 additions and 8 deletions

View File

@ -7,9 +7,10 @@
package org.hibernate.query.sql.internal;
import java.util.BitSet;
import java.util.Map;
import org.hibernate.QueryException;
import org.hibernate.QueryParameterException;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.query.ParameterLabelException;
import org.hibernate.query.sql.spi.ParameterRecognizer;
@ -52,6 +53,7 @@ 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;
@ -128,12 +130,8 @@ public class ParameterParser {
}
// otherwise
else {
if ( c == ':' && indx < stringLength - 1 && sqlString.charAt( indx + 1 ) == ':') {
// colon character has been escaped
recognizer.other( c );
indx++;
}
else if ( c == ':' ) {
if ( c == ':' && indx < stringLength - 1 && Character.isJavaIdentifierStart( sqlString.charAt( indx + 1 ) )
&& !(0 < indx && 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;
@ -178,6 +176,19 @@ 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 );
}

View File

@ -169,7 +169,50 @@ public class ParameterParserTest {
recognizer.complete();
assertEquals("SELECT @a,(@a:=20) FROM tbl_name", captured.toString());
}
@Test
@JiraKey( value = "HHH-17759")
public void testParseColonCharacterTypeCasting() {
final StringBuilder captured = new StringBuilder();
ParameterRecognizer recognizer = new ParameterRecognizer() {
@Override
public void ordinalParameter(int position) {
// don't care
}
@Override
public void namedParameter(String name, int position) {
// don't care
}
@Override
public void jpaPositionalParameter(int name, int position) {
// don't care
}
@Override
public void other(char character) {
captured.append(character);
}
@Override
public void complete() {
}
};
String expectedQuery = "SELECT column_name::text FROM table_name";
ParameterParser.parse("SELECT column_name::text FROM table_name", recognizer);
recognizer.complete();
assertEquals(expectedQuery, captured.toString());
captured.setLength(0); // clear for new test
ParameterParser.parse("SELECT column_name::::text FROM table_name", recognizer);
recognizer.complete();
assertEquals(expectedQuery, captured.toString());
}
@Test
public void testParseNamedParameter() {
ExtendedParameterRecognizer recognizer = createRecognizer();