diff --git a/cli/src/java/org/apache/hadoop/hive/cli/CliDriver.java b/cli/src/java/org/apache/hadoop/hive/cli/CliDriver.java index 68741f67da..05a2410a9c 100644 --- a/cli/src/java/org/apache/hadoop/hive/cli/CliDriver.java +++ b/cli/src/java/org/apache/hadoop/hive/cli/CliDriver.java @@ -416,44 +416,53 @@ public void handle(Signal signal) { } } + /** + * Split the line by semicolon by ignoring the ones in the single/double quotes + * + */ public static List splitSemiColon(String line) { - boolean insideSingleQuote = false; - boolean insideDoubleQuote = false; + boolean inQuotes = false; boolean escape = false; - int beginIndex = 0; + List ret = new ArrayList<>(); + + char quoteChar = '"'; + int beginIndex = 0; for (int index = 0; index < line.length(); index++) { - if (line.charAt(index) == '\'') { - // take a look to see if it is escaped - if (!escape) { - // flip the boolean variable - insideSingleQuote = !insideSingleQuote; - } - } else if (line.charAt(index) == '\"') { - // take a look to see if it is escaped - if (!escape) { - // flip the boolean variable - insideDoubleQuote = !insideDoubleQuote; - } - } else if (line.charAt(index) == ';') { - if (insideSingleQuote || insideDoubleQuote) { - // do not split - } else { - // split, do not include ; itself + char c = line.charAt(index); + switch (c) { + case ';': + if (!inQuotes) { ret.add(line.substring(beginIndex, index)); beginIndex = index + 1; } - } else { - // nothing to do + break; + case '"': + case '\'': + if (!escape) { + if (!inQuotes) { + quoteChar = c; + inQuotes = !inQuotes; + } else { + if (c == quoteChar) { + inQuotes = !inQuotes; + } + } + } + break; } - // set the escape + if (escape) { escape = false; - } else if (line.charAt(index) == '\\') { + } else if (c == '\\') { escape = true; } } - ret.add(line.substring(beginIndex)); + + if (beginIndex < line.length()) { + ret.add(line.substring(beginIndex)); + } + return ret; } diff --git a/cli/src/test/org/apache/hadoop/hive/cli/TestCliDriverMethods.java b/cli/src/test/org/apache/hadoop/hive/cli/TestCliDriverMethods.java index c06ec3ea31..8f8f04eb47 100644 --- a/cli/src/test/org/apache/hadoop/hive/cli/TestCliDriverMethods.java +++ b/cli/src/test/org/apache/hadoop/hive/cli/TestCliDriverMethods.java @@ -53,6 +53,7 @@ import org.apache.hadoop.hive.metastore.api.Schema; import org.apache.hadoop.hive.ql.IDriver; import org.apache.hadoop.hive.ql.processors.CommandProcessorResponse; +import org.junit.Test; // Cannot call class TestCliDriver since that's the name of the generated @@ -353,6 +354,28 @@ public void testprocessInitFiles() throws Exception { } } + @Test + public void testCommandSplits() { + // Test double quote in the string + String cmd1 = "insert into escape1 partition (ds='1', part='\"') values (\"!\")"; + assertEquals(cmd1, CliDriver.splitSemiColon(cmd1).get(0)); + assertEquals(cmd1, CliDriver.splitSemiColon(cmd1 + ";").get(0)); + + // Test escape + String cmd2 = "insert into escape1 partition (ds='1', part='\"\\'') values (\"!\")"; + assertEquals(cmd2, CliDriver.splitSemiColon(cmd2).get(0)); + assertEquals(cmd2, CliDriver.splitSemiColon(cmd2 + ";").get(0)); + + // Test multiple commands + List results = CliDriver.splitSemiColon(cmd1 + ";" + cmd2); + assertEquals(cmd1, results.get(0)); + assertEquals(cmd2, results.get(1)); + + results = CliDriver.splitSemiColon(cmd1 + ";" + cmd2 + ";"); + assertEquals(cmd1, results.get(0)); + assertEquals(cmd2, results.get(1)); + } + private static void setEnv(String key, String value) throws Exception { Class[] classes = Collections.class.getDeclaredClasses(); Map env = System.getenv();