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 2016/07/25 15:18:11 UTC
hive git commit: HIVE-12646: beeline and HIVE CLI do not parse ;
in quote properly (Sahil Takiar, reviewed by Sergio Pena)
Repository: hive
Updated Branches:
refs/heads/master cd5147c7e -> 9938d45da
HIVE-12646: beeline and HIVE CLI do not parse ; in quote properly (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/9938d45d
Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/9938d45d
Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/9938d45d
Branch: refs/heads/master
Commit: 9938d45da0d6bbd74e0adf72ca3e19e58a03c9dd
Parents: cd5147c
Author: Sahil Takiar <ta...@gmail.com>
Authored: Mon Jul 25 10:17:16 2016 -0500
Committer: Sergio Pena <se...@cloudera.com>
Committed: Mon Jul 25 10:17:16 2016 -0500
----------------------------------------------------------------------
.../java/org/apache/hive/beeline/Commands.java | 90 ++++++++++++++++----
.../hive/beeline/TestBeeLineWithArgs.java | 21 +++++
.../org/apache/hadoop/hive/ql/exec/DDLTask.java | 2 +-
3 files changed, 96 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hive/blob/9938d45d/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 387861b..ffd1775 100644
--- a/beeline/src/java/org/apache/hive/beeline/Commands.java
+++ b/beeline/src/java/org/apache/hive/beeline/Commands.java
@@ -1128,22 +1128,7 @@ public class Commands {
}
line = line.trim();
- List<String> cmdList = new ArrayList<String>();
- if (entireLineAsCommand) {
- cmdList.add(line);
- } else {
- StringBuffer command = new StringBuffer();
- for (String cmdpart: line.split(";")) {
- if (cmdpart.endsWith("\\")) {
- command.append(cmdpart.substring(0, cmdpart.length() -1)).append(";");
- continue;
- } else {
- command.append(cmdpart);
- }
- cmdList.add(command.toString());
- command.setLength(0);
- }
- }
+ List<String> cmdList = getCmdList(line, entireLineAsCommand);
for (int i = 0; i < cmdList.size(); i++) {
String sql = cmdList.get(i).trim();
if (sql.length() != 0) {
@@ -1155,6 +1140,79 @@ public class Commands {
return true;
}
+ /**
+ * Helper method to parse input from Beeline and convert it to a {@link List} of commands that
+ * can be executed. This method contains logic for handling semicolons that are placed within
+ * quotations. It iterates through each character in the line and checks to see if it is a ;, ',
+ * or "
+ */
+ private List<String> getCmdList(String line, boolean entireLineAsCommand) {
+ List<String> cmdList = new ArrayList<String>();
+ if (entireLineAsCommand) {
+ cmdList.add(line);
+ } else {
+ StringBuffer command = new StringBuffer();
+
+ boolean hasUnterminatedDoubleQuote = false;
+ boolean hasUntermindatedSingleQuote = false;
+
+ int lastSemiColonIndex = 0;
+ char[] lineChars = line.toCharArray();
+
+ boolean wasPrevEscape = false;
+ int index = 0;
+ for (; index < lineChars.length; index++) {
+ switch (lineChars[index]) {
+ case '\'':
+ if (!hasUnterminatedDoubleQuote && !wasPrevEscape) {
+ hasUntermindatedSingleQuote = !hasUntermindatedSingleQuote;
+ }
+ wasPrevEscape = false;
+ break;
+ case '\"':
+ if (!hasUntermindatedSingleQuote && !wasPrevEscape) {
+ hasUnterminatedDoubleQuote = !hasUnterminatedDoubleQuote;
+ }
+ wasPrevEscape = false;
+ break;
+ case ';':
+ if (!hasUnterminatedDoubleQuote && !hasUntermindatedSingleQuote) {
+ addCmdPart(cmdList, command, line.substring(lastSemiColonIndex, index));
+ lastSemiColonIndex = index + 1;
+ }
+ wasPrevEscape = false;
+ break;
+ case '\\':
+ wasPrevEscape = true;
+ break;
+ default:
+ wasPrevEscape = false;
+ break;
+ }
+ }
+ // 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));
+ }
+ }
+ return cmdList;
+ }
+
+ /**
+ * 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) {
+ if (cmdpart.endsWith("\\")) {
+ command.append(cmdpart.substring(0, cmdpart.length() - 1)).append(";");
+ return;
+ } else {
+ command.append(cmdpart);
+ }
+ cmdList.add(command.toString());
+ command.setLength(0);
+ }
+
private Runnable createLogRunnable(Statement statement) {
if (statement instanceof HiveStatement) {
final HiveStatement hiveStatement = (HiveStatement) statement;
http://git-wip-us.apache.org/repos/asf/hive/blob/9938d45d/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 ecfeddb..3b40d71 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
@@ -863,4 +863,25 @@ public class TestBeeLineWithArgs {
testScriptFile( SCRIPT_TEXT, EXPECTED_PATTERN, true, argList);
}
+
+ /**
+ * Test that Beeline queries don't treat semicolons inside quotations as query-ending characters.
+ */
+ @Test
+ public void testQueryNonEscapedSemiColon() throws Throwable {
+ String SCRIPT_TEXT = "drop table if exists nonEscapedSemiColon;create table nonEscapedSemiColon "
+ + "(key int) ROW FORMAT DELIMITED FIELDS TERMINATED BY ';';show tables;";
+ final String EXPECTED_PATTERN = " nonEscapedSemiColon ";
+ List<String> argList = getBaseArgs(miniHS2.getBaseJdbcURL());
+ testScriptFile(SCRIPT_TEXT, EXPECTED_PATTERN, true, argList);
+ }
+
+ @Test
+ public void testSelectQueryWithNonEscapedSemiColon() throws Throwable {
+ String SCRIPT_TEXT = "select ';', \"';'\", '\";\"', '\\';', ';\\'', '\\\";', ';\\\"' from " + tableName + ";";
+ final String EXPECTED_PATTERN = ";\t';'\t\";\"\t';\t;'\t\";\t;\"";
+ List<String> argList = getBaseArgs(miniHS2.getBaseJdbcURL());
+ argList.add("--outputformat=tsv2");
+ testScriptFile(SCRIPT_TEXT, EXPECTED_PATTERN, true, argList);
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/9938d45d/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java
index 2b8d6a7..39ac7d6 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java
@@ -4346,7 +4346,7 @@ public class DDLTask extends Task<DDLWork> implements Serializable {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i ++) {
char c = str.charAt(i);
- if (c == '\'' || c == ';') {
+ if (c == '\'') {
sb.append('\\');
}
sb.append(c);