HHH-17759 Avoid need for undocumented escaping of colon characters in native queries
This commit is contained in:
parent
adbf8946da
commit
b9aa76625b
|
@ -7,9 +7,10 @@
|
||||||
package org.hibernate.query.sql.internal;
|
package org.hibernate.query.sql.internal;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
import java.util.Map;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.QueryParameterException;
|
import org.hibernate.QueryParameterException;
|
||||||
|
import org.hibernate.internal.log.DeprecationLogger;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.query.ParameterLabelException;
|
import org.hibernate.query.ParameterLabelException;
|
||||||
import org.hibernate.query.sql.spi.ParameterRecognizer;
|
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 {
|
public static void parse(String sqlString, ParameterRecognizer recognizer, boolean nativeJdbcParametersIgnored) throws QueryException {
|
||||||
checkIsNotAFunctionCall( sqlString );
|
checkIsNotAFunctionCall( sqlString );
|
||||||
|
sqlString = preprocessing(sqlString);
|
||||||
final int stringLength = sqlString.length();
|
final int stringLength = sqlString.length();
|
||||||
|
|
||||||
boolean inSingleQuotes = false;
|
boolean inSingleQuotes = false;
|
||||||
|
@ -128,12 +130,8 @@ public class ParameterParser {
|
||||||
}
|
}
|
||||||
// otherwise
|
// otherwise
|
||||||
else {
|
else {
|
||||||
if ( c == ':' && indx < stringLength - 1 && sqlString.charAt( indx + 1 ) == ':') {
|
if ( c == ':' && indx < stringLength - 1 && Character.isJavaIdentifierStart( sqlString.charAt( indx + 1 ) )
|
||||||
// colon character has been escaped
|
&& !(0 < indx && sqlString.charAt( indx - 1 ) == ':')) {
|
||||||
recognizer.other( c );
|
|
||||||
indx++;
|
|
||||||
}
|
|
||||||
else if ( c == ':' ) {
|
|
||||||
// named parameter
|
// named parameter
|
||||||
final int right = StringHelper.firstIndexOfChar( sqlString, HQL_SEPARATORS_BITSET, indx + 1 );
|
final int right = StringHelper.firstIndexOfChar( sqlString, HQL_SEPARATORS_BITSET, indx + 1 );
|
||||||
final int chopLocation = right < 0 ? sqlString.length() : right;
|
final int chopLocation = right < 0 ? sqlString.length() : right;
|
||||||
|
@ -178,6 +176,19 @@ public class ParameterParser {
|
||||||
recognizer.complete();
|
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 {
|
public static void parse(String sqlString, ParameterRecognizer recognizer) throws QueryException {
|
||||||
parse( sqlString, recognizer, false );
|
parse( sqlString, recognizer, false );
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,50 @@ public class ParameterParserTest {
|
||||||
recognizer.complete();
|
recognizer.complete();
|
||||||
assertEquals("SELECT @a,(@a:=20) FROM tbl_name", captured.toString());
|
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
|
@Test
|
||||||
public void testParseNamedParameter() {
|
public void testParseNamedParameter() {
|
||||||
ExtendedParameterRecognizer recognizer = createRecognizer();
|
ExtendedParameterRecognizer recognizer = createRecognizer();
|
||||||
|
|
Loading…
Reference in New Issue