Skip to content

Commit

Permalink
Add support for MySQL backticks
Browse files Browse the repository at this point in the history
This commit makes sure that content within backticks are skipped
when parsing a SQL statement using NamedParameterUtils. This harmonizes
the current behavior of ignoring special characters that are wrapped
in backticks.

Closes spring-projectsgh-31944
  • Loading branch information
snicoll committed Jan 31, 2024
1 parent a4db0e7 commit 6e217ce
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -44,12 +44,12 @@ public abstract class NamedParameterUtils {
/**
* Set of characters that qualify as comment or quotes starting characters.
*/
private static final String[] START_SKIP = new String[] {"'", "\"", "--", "/*"};
private static final String[] START_SKIP = new String[] {"'", "\"", "--", "/*", "`"};

/**
* Set of characters that at are the corresponding comment or quotes ending characters.
*/
private static final String[] STOP_SKIP = new String[] {"'", "\"", "\n", "*/"};
private static final String[] STOP_SKIP = new String[] {"'", "\"", "\n", "*/", "`"};

/**
* Set of characters that qualify as parameter separators,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,6 +21,8 @@
import java.util.Map;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.SqlParameterValue;
Expand Down Expand Up @@ -285,25 +287,14 @@ public void variableAssignmentOperator() {
assertThat(newSql).isEqualTo(expectedSql);
}

@Test // SPR-8280
public void parseSqlStatementWithQuotedSingleQuote() {
String sql = "SELECT ':foo'':doo', :xxx FROM DUAL";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getTotalParameterCount()).isEqualTo(1);
assertThat(parsedSql.getParameterNames()).containsExactly("xxx");
}

@Test
void parseSqlStatementWithQuotesAndCommentBefore() {
String sql = "SELECT /*:doo*/':foo', :xxx FROM DUAL";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getTotalParameterCount()).isEqualTo(1);
assertThat(parsedSql.getParameterNames()).containsExactly("xxx");
}

@Test
void parseSqlStatementWithQuotesAndCommentAfter() {
String sql = "SELECT ':foo'/*:doo*/, :xxx FROM DUAL";
@ParameterizedTest // SPR-8280 and others
@ValueSource(strings = {
"SELECT ':foo'':doo', :xxx FROM DUAL",
"SELECT /*:doo*/':foo', :xxx FROM DUAL",
"SELECT ':foo'/*:doo*/, :xxx FROM DUAL",
"SELECT \":foo\"\":doo\", :xxx FROM DUAL",
"SELECT `:foo``:doo`, :xxx FROM DUAL",})
void parseSqlStatementWithParametersInsideQuote(String sql) {
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getTotalParameterCount()).isEqualTo(1);
assertThat(parsedSql.getParameterNames()).containsExactly("xxx");
Expand Down Expand Up @@ -361,6 +352,14 @@ public Map<String, Object> getHeaders() {
assertThat(sqlToUse).isEqualTo("insert into foos (id) values (?)");
}

@Test // gh-31944
void parseSqlStatementWithBackticks() {
String sql = "select * from `tb&user` where id = :id";
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getParameterNames()).containsExactly("id");
assertThat(substituteNamedParameters(parsedSql)).isEqualTo("select * from `tb&user` where id = ?");
}

private static String substituteNamedParameters(ParsedSql parsedSql) {
return NamedParameterUtils.substituteNamedParameters(parsedSql, null);
}
Expand Down

0 comments on commit 6e217ce

Please sign in to comment.