From 676f111a254b574bbd94b6075edea63021074009 Mon Sep 17 00:00:00 2001 From: tatian Date: Fri, 29 Mar 2024 10:33:04 +0800 Subject: [PATCH] [KYUUBI #6221] Fix parameter replacement issue caused by incorrect sql split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # :mag: 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 :bookmark: - [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 :coffin: #### Behavior With This Pull Request :tada: #### 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 Signed-off-by: Cheng Pan (cherry picked from commit 612dd7ac450324db94589b2a161fb1324bc552f4) Signed-off-by: Cheng Pan --- .../org/apache/kyuubi/jdbc/hive/Utils.java | 30 +++++++++-- .../apache/kyuubi/jdbc/hive/UtilsTest.java | 50 +++++++++++++++++-- 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/kyuubi-hive-jdbc/src/main/java/org/apache/kyuubi/jdbc/hive/Utils.java b/kyuubi-hive-jdbc/src/main/java/org/apache/kyuubi/jdbc/hive/Utils.java index 2a0462aed..881a96027 100644 --- a/kyuubi-hive-jdbc/src/main/java/org/apache/kyuubi/jdbc/hive/Utils.java +++ b/kyuubi-hive-jdbc/src/main/java/org/apache/kyuubi/jdbc/hive/Utils.java @@ -106,25 +106,47 @@ public class Utils { */ static List splitSqlStatement(String sql) { List 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; } diff --git a/kyuubi-hive-jdbc/src/test/java/org/apache/kyuubi/jdbc/hive/UtilsTest.java b/kyuubi-hive-jdbc/src/test/java/org/apache/kyuubi/jdbc/hive/UtilsTest.java index fc4a55d9f..87f1a78de 100644 --- a/kyuubi-hive-jdbc/src/test/java/org/apache/kyuubi/jdbc/hive/UtilsTest.java +++ b/kyuubi-hive-jdbc/src/test/java/org/apache/kyuubi/jdbc/hive/UtilsTest.java @@ -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 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)); + } }