You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by sp...@apache.org on 2017/03/23 17:41:04 UTC

hive git commit: HIVE-14606: Beeline fails if quoted string ends with \\ (Sahil Takiar, reviewed by Sergio Pena)

Repository: hive
Updated Branches:
  refs/heads/master 60795505b -> 4812486a1


HIVE-14606: Beeline fails if quoted string ends with \\ (Sahil Takiar, reviewed by Sergio Pena)


Project: http://git-wip-us.apache.org/repos/asf/hive/repo
Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/4812486a
Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/4812486a
Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/4812486a

Branch: refs/heads/master
Commit: 4812486a13a73002f94b69d02e25ca076a7ac157
Parents: 6079550
Author: Sahil Takiar <ta...@gmail.com>
Authored: Thu Mar 23 12:40:31 2017 -0500
Committer: Sergio Pena <se...@cloudera.com>
Committed: Thu Mar 23 12:40:58 2017 -0500

----------------------------------------------------------------------
 .../java/org/apache/hive/beeline/Commands.java  | 31 +++++++++++++++-----
 .../hive/beeline/TestBeeLineWithArgs.java       | 13 ++++++++
 2 files changed, 36 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hive/blob/4812486a/beeline/src/java/org/apache/hive/beeline/Commands.java
----------------------------------------------------------------------
diff --git a/beeline/src/java/org/apache/hive/beeline/Commands.java b/beeline/src/java/org/apache/hive/beeline/Commands.java
index 99ee82c..2578728 100644
--- a/beeline/src/java/org/apache/hive/beeline/Commands.java
+++ b/beeline/src/java/org/apache/hive/beeline/Commands.java
@@ -1221,46 +1221,61 @@ public class Commands {
     if (entireLineAsCommand) {
       cmdList.add(line);
     } else {
-      StringBuffer command = new StringBuffer();
+      StringBuilder command = new StringBuilder();
 
+      // Marker to track if there is starting double quote without an ending double quote
       boolean hasUnterminatedDoubleQuote = false;
-      boolean hasUntermindatedSingleQuote = false;
 
+      // Marker to track if there is starting single quote without an ending double quote
+      boolean hasUnterminatedSingleQuote = false;
+
+      // Index of the last seen semicolon in the given line
       int lastSemiColonIndex = 0;
       char[] lineChars = line.toCharArray();
 
+      // Marker to track if the previous character was an escape character
       boolean wasPrevEscape = false;
+
       int index = 0;
+
+      // Iterate through the line and invoke the addCmdPart method whenever a semicolon is seen that is not inside a
+      // quoted string
       for (; index < lineChars.length; index++) {
         switch (lineChars[index]) {
           case '\'':
+            // If a single quote is seen and the index is not inside a double quoted string and the previous character
+            // was not an escape, then update the hasUnterminatedSingleQuote flag
             if (!hasUnterminatedDoubleQuote && !wasPrevEscape) {
-              hasUntermindatedSingleQuote = !hasUntermindatedSingleQuote;
+              hasUnterminatedSingleQuote = !hasUnterminatedSingleQuote;
             }
             wasPrevEscape = false;
             break;
           case '\"':
-            if (!hasUntermindatedSingleQuote && !wasPrevEscape) {
+            // If a double quote is seen and the index is not inside a single quoted string and the previous character
+            // was not an escape, then update the hasUnterminatedDoubleQuote flag
+            if (!hasUnterminatedSingleQuote && !wasPrevEscape) {
               hasUnterminatedDoubleQuote = !hasUnterminatedDoubleQuote;
             }
             wasPrevEscape = false;
             break;
           case ';':
-            if (!hasUnterminatedDoubleQuote && !hasUntermindatedSingleQuote) {
+            // If a semicolon is seen, and the line isn't inside a quoted string, then treat
+            // line[lastSemiColonIndex] to line[index] as a single command
+            if (!hasUnterminatedDoubleQuote && !hasUnterminatedSingleQuote) {
               addCmdPart(cmdList, command, line.substring(lastSemiColonIndex, index));
               lastSemiColonIndex = index + 1;
             }
             wasPrevEscape = false;
             break;
           case '\\':
-            wasPrevEscape = true;
+            wasPrevEscape = !wasPrevEscape;
             break;
           default:
             wasPrevEscape = false;
             break;
         }
       }
-      // if the line doesn't end with a ; or if the line is empty, add the cmd part
+      // If the line doesn't end with a ; or if the line is empty, add the cmd part
       if (lastSemiColonIndex != index || lineChars.length == 0) {
         addCmdPart(cmdList, command, line.substring(lastSemiColonIndex, index));
       }
@@ -1272,7 +1287,7 @@ public class Commands {
    * Given a cmdpart (e.g. if a command spans multiple lines), add to the current command, and if
    * applicable add that command to the {@link List} of commands
    */
-  private void addCmdPart(List<String> cmdList, StringBuffer command, String cmdpart) {
+  private void addCmdPart(List<String> cmdList, StringBuilder command, String cmdpart) {
     if (cmdpart.endsWith("\\")) {
       command.append(cmdpart.substring(0, cmdpart.length() - 1)).append(";");
       return;

http://git-wip-us.apache.org/repos/asf/hive/blob/4812486a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java
----------------------------------------------------------------------
diff --git a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java b/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java
index 650c4b7..75f46ec 100644
--- a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java
+++ b/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java
@@ -1069,4 +1069,17 @@ public class TestBeeLineWithArgs {
       this.shouldMatch = shouldMatch;
     }
   }
+
+  /**
+   * Test that Beeline can handle \\ characters within a string literal. Either at the beginning, middle, or end of the
+   * literal.
+   */
+  @Test
+  public void testBackslashInLiteral() throws Throwable {
+    String SCRIPT_TEXT = "select 'hello\\\\', '\\\\hello', 'hel\\\\lo', '\\\\' as literal;";
+    final String EXPECTED_PATTERN = "hello\\\\\t\\\\hello\thel\\\\lo\t\\\\";
+    List<String> argList = getBaseArgs(miniHS2.getBaseJdbcURL());
+    argList.add("--outputformat=tsv2");
+    testScriptFile(SCRIPT_TEXT, argList, EXPECTED_PATTERN, true);
+  }
 }