[KYUUBI #6221] Fix parameter replacement issue caused by incorrect sql split

# 🔍 Description
## Issue References 🔗

This pull request fixes #6221

## Describe Your Solution 🔧

Fix the static function that split the sql by parameter placeholder '?', add the handling of cases when the placeholder is within the double quote or comment.

## Types of changes 🔖

- [x] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Test Plan 🧪

#### Behavior Without This Pull Request ⚰️

#### Behavior With This Pull Request 🎉

#### Related Unit Tests
org.apache.kyuubi.jdbc.hive.UtilsTest.testSplitSqlStatement

---

# Checklist 📝

- [ ] This patch was not authored or co-authored using [Generative Tooling](https://www.apache.org/legal/generative-tooling.html)

**Be nice. Be informative.**

Closes #6222 from TakawaAkirayo/fix_sql_split_issue.

Closes #6221

a501c38ea [tatian] [KYUUBI #6221] Let UT cover another case
3b9714569 [tatian] [KYUUBI #6221] Fix parameter replacement issue caused by incorrect sql split

Authored-by: tatian <tatian@ebay.com>
Signed-off-by: Cheng Pan <chengpan@apache.org>
(cherry picked from commit 612dd7ac45)
Signed-off-by: Cheng Pan <chengpan@apache.org>
This commit is contained in:
tatian 2024-03-29 10:33:04 +08:00 committed by Cheng Pan
parent 01f7dc07f9
commit 676f111a25
No known key found for this signature in database
GPG Key ID: 8001952629BCC75D
2 changed files with 72 additions and 8 deletions

View File

@ -106,25 +106,47 @@ public class Utils {
*/
static List<String> splitSqlStatement(String sql) {
List<String> parts = new ArrayList<>();
int apCount = 0;
boolean inSingleQuote = false;
boolean inDoubleQuote = false;
boolean inComment = false;
int off = 0;
boolean skip = false;
for (int i = 0; i < sql.length(); i++) {
char c = sql.charAt(i);
if (inComment) {
inComment = (c != '\n');
continue;
}
if (skip) {
skip = false;
continue;
}
switch (c) {
case '\'':
apCount++;
if (!inDoubleQuote) {
inSingleQuote = !inSingleQuote;
}
break;
case '\"':
if (!inSingleQuote) {
inDoubleQuote = !inDoubleQuote;
}
break;
case '-':
if (!inSingleQuote && !inDoubleQuote) {
if (i < sql.length() - 1 && sql.charAt(i + 1) == '-') {
inComment = true;
}
}
break;
case '\\':
skip = true;
if (!inSingleQuote && !inDoubleQuote) {
skip = true;
}
break;
case '?':
if ((apCount & 1) == 0) {
if (!inSingleQuote && !inDoubleQuote) {
parts.add(sql.substring(off, i));
off = i + 1;
}

View File

@ -25,10 +25,7 @@ import com.google.common.collect.ImmutableMap;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.*;
import java.util.regex.Pattern;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -156,4 +153,49 @@ public class UtilsTest {
Pattern pattern = Pattern.compile("^\\d+\\.\\d+\\.\\d+.*");
assert pattern.matcher(Utils.getVersion()).matches();
}
@Test
public void testSplitSqlStatement() {
String simpleSql = "select 1 from ? where a = ?";
List<String> splitSql = Utils.splitSqlStatement(simpleSql);
assertEquals(3, splitSql.size());
assertEquals("select 1 from ", splitSql.get(0));
assertEquals(" where a = ", splitSql.get(1));
assertEquals("", splitSql.get(2));
String placeHolderWithinSingleQuote = "select '?' from ? where a = ?";
splitSql = Utils.splitSqlStatement(placeHolderWithinSingleQuote);
assertEquals(3, splitSql.size());
assertEquals("select '?' from ", splitSql.get(0));
assertEquals(" where a = ", splitSql.get(1));
assertEquals("", splitSql.get(2));
String escapePlaceHolder = "select \\? from ? where a = ?";
splitSql = Utils.splitSqlStatement(escapePlaceHolder);
assertEquals(3, splitSql.size());
assertEquals("select \\? from ", splitSql.get(0));
assertEquals(" where a = ", splitSql.get(1));
assertEquals("", splitSql.get(2));
String inQuoteLikeRegexFunction =
"select "
+ "regexp_extract(field_a, \"[a-zA-Z]+?\", 0) as extracted_a,"
+ "regexp_extract(field_b, '[a-zA-Z]+?', 0) as extracted_b"
+ " from ?";
splitSql = Utils.splitSqlStatement(inQuoteLikeRegexFunction);
assertEquals(2, splitSql.size());
assertEquals(
"select "
+ "regexp_extract(field_a, \"[a-zA-Z]+?\", 0) as extracted_a,"
+ "regexp_extract(field_b, '[a-zA-Z]+?', 0) as extracted_b from ",
splitSql.get(0));
assertEquals("", splitSql.get(1));
String inCommentBlock = "--comments\n" + "select --? \n" + "? from ?";
splitSql = Utils.splitSqlStatement(inCommentBlock);
assertEquals(3, splitSql.size());
assertEquals("--comments\n" + "select --? \n", splitSql.get(0));
assertEquals(" from ", splitSql.get(1));
assertEquals("", splitSql.get(2));
}
}