diff --git a/beeline/src/java/org/apache/hive/beeline/Commands.java b/beeline/src/java/org/apache/hive/beeline/Commands.java index 6a3ad42be61298ce6b94e4d5a8f9befe8de35443..962ddf7d7bac4d64f5e89ff3470d769b5ae720f8 100644 --- a/beeline/src/java/org/apache/hive/beeline/Commands.java +++ b/beeline/src/java/org/apache/hive/beeline/Commands.java @@ -65,6 +65,8 @@ import org.apache.hive.jdbc.Utils; import org.apache.hive.jdbc.Utils.JdbcConnectionParams; +import com.google.common.annotations.VisibleForTesting; + public class Commands { private final BeeLine beeLine; @@ -1042,11 +1044,39 @@ private boolean executeInternal(String sql, boolean call) { return true; } + //startQuote use array type in order to pass int type as input/output parameter. + //This method remove comment from current line of a query. + //It does not remove comment like strings inside quotes. + @VisibleForTesting + String removeComments(String line, int[] startQuote) { + if (line == null || line.isEmpty()) return line; + if (startQuote[0] == -1 && beeLine.isComment(line)) return ""; //assume # can only be used at the beginning of line. + StringBuilder builder = new StringBuilder(); + for (int index = 0; index < line.length(); index++) { + if (startQuote[0] == -1 && index < line.length() - 1 && line.charAt(index) == '-' && line.charAt(index + 1) =='-') { + return builder.toString().trim(); + } + + char letter = line.charAt(index); + if (startQuote[0] == letter && (index == 0 || line.charAt(index -1) != '\\') ) { + startQuote[0] = -1; // Turn escape off. + } else if (startQuote[0] == -1 && (letter == '\'' || letter == '"') && (index == 0 || line.charAt(index -1) != '\\')) { + startQuote[0] = letter; // Turn escape on. + } + + builder.append(letter); + } + + return builder.toString().trim(); + } + /* * Check if the input line is a multi-line command which needs to read further */ public String handleMultiLineCmd(String line) throws IOException { //When using -e, console reader is not initialized and command is always a single line + int[] startQuote = {-1}; + line = removeComments(line,startQuote); while (isMultiLine(line) && beeLine.getOpts().isAllowMultiLineCommand()) { StringBuilder prompt = new StringBuilder(beeLine.getPrompt()); if (!beeLine.getOpts().isSilent()) { @@ -1071,7 +1101,8 @@ public String handleMultiLineCmd(String line) throws IOException { if (extra == null) { //it happens when using -f and the line of cmds does not end with ; break; } - if (!beeLine.isComment(extra)) { + extra = removeComments(extra,startQuote); + if (extra != null && !extra.isEmpty()) { line += "\n" + extra; } } diff --git a/beeline/src/test/org/apache/hive/beeline/TestCommands.java b/beeline/src/test/org/apache/hive/beeline/TestCommands.java new file mode 100644 index 0000000000000000000000000000000000000000..04c939a04c7a56768286743c2bb9c9797507e3aa --- /dev/null +++ b/beeline/src/test/org/apache/hive/beeline/TestCommands.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hive.beeline; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class TestCommands { + + @Test + public void testLinesEndingWithComments() { + BeeLine beeline = new BeeLine(); + Commands commands = new Commands(beeline); + int[] escape = {-1}; + assertEquals("show tables;", commands.removeComments("show tables;",escape)); + assertEquals("show tables;", commands.removeComments("show tables; --comments",escape)); + assertEquals("show tables;", commands.removeComments("show tables; -------comments",escape)); + assertEquals("show tables;", commands.removeComments("show tables; -------comments;one;two;three;;;;",escape)); + assertEquals("show", commands.removeComments("show-- tables; -------comments",escape)); + assertEquals("show", commands.removeComments("show --tables; -------comments",escape)); + assertEquals("s", commands.removeComments("s--how --tables; -------comments",escape)); + assertEquals("", commands.removeComments("-- show tables; -------comments",escape)); + + assertEquals("\"show tables\"", commands.removeComments("\"show tables\" --comments",escape)); + assertEquals("\"show --comments tables\"", commands.removeComments("\"show --comments tables\" --comments",escape)); + assertEquals("\"'show --comments' tables\"", commands.removeComments("\"'show --comments' tables\" --comments",escape)); + assertEquals("'show --comments tables'", commands.removeComments("'show --comments tables' --comments",escape)); + assertEquals("'\"show --comments tables\"'", commands.removeComments("'\"show --comments tables\"' --comments",escape)); + } +} + diff --git a/ql/src/test/queries/clientpositive/cmdwithcomments.q b/ql/src/test/queries/clientpositive/cmdwithcomments.q new file mode 100644 index 0000000000000000000000000000000000000000..e9c0d434c613d3fca09d2cad70935305002a9127 --- /dev/null +++ b/ql/src/test/queries/clientpositive/cmdwithcomments.q @@ -0,0 +1,13 @@ +create table if not exists numt --comment1 + (idx int); --comment2 +insert into numt values(1); --comment3 +insert into numt values(2); +--comment4 +select idx from numt where --comment5 +idx = 1; --comment6 +select idx from numt where idx = 2 --comment6 +limit 1; +--comment7 +select "this is +another --string value" from numt where idx =2; --comment8 +drop table numt; diff --git a/ql/src/test/results/clientpositive/cmdwithcomments.q.out b/ql/src/test/results/clientpositive/cmdwithcomments.q.out new file mode 100644 index 0000000000000000000000000000000000000000..93c9431334fd47e7d47f800e5bf44b1311e4e2b7 --- /dev/null +++ b/ql/src/test/results/clientpositive/cmdwithcomments.q.out @@ -0,0 +1,74 @@ +PREHOOK: query: create table if not exists numt --comment1 + (idx int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@numt +POSTHOOK: query: create table if not exists numt --comment1 + (idx int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@numt +PREHOOK: query: --comment2 +insert into numt values(1) +PREHOOK: type: QUERY +PREHOOK: Output: default@numt +POSTHOOK: query: --comment2 +insert into numt values(1) +POSTHOOK: type: QUERY +POSTHOOK: Output: default@numt +POSTHOOK: Lineage: numt.idx EXPRESSION [(values__tmp__table__1)values__tmp__table__1.FieldSchema(name:tmp_values_col1, type:string, comment:), ] +PREHOOK: query: --comment3 +insert into numt values(2) +PREHOOK: type: QUERY +PREHOOK: Output: default@numt +POSTHOOK: query: --comment3 +insert into numt values(2) +POSTHOOK: type: QUERY +POSTHOOK: Output: default@numt +POSTHOOK: Lineage: numt.idx EXPRESSION [(values__tmp__table__2)values__tmp__table__2.FieldSchema(name:tmp_values_col1, type:string, comment:), ] +PREHOOK: query: select idx from numt where --comment5 +idx = 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@numt +#### A masked pattern was here #### +POSTHOOK: query: select idx from numt where --comment5 +idx = 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@numt +#### A masked pattern was here #### +1 +PREHOOK: query: --comment6 +select idx from numt where idx = 2 --comment6 +limit 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@numt +#### A masked pattern was here #### +POSTHOOK: query: --comment6 +select idx from numt where idx = 2 --comment6 +limit 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@numt +#### A masked pattern was here #### +2 +PREHOOK: query: select "this is +another --string value" from numt where idx =2 +PREHOOK: type: QUERY +PREHOOK: Input: default@numt +#### A masked pattern was here #### +POSTHOOK: query: select "this is +another --string value" from numt where idx =2 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@numt +#### A masked pattern was here #### +this is +another --string value +PREHOOK: query: --comment8 +drop table numt +PREHOOK: type: DROPTABLE +PREHOOK: Input: default@numt +PREHOOK: Output: default@numt +POSTHOOK: query: --comment8 +drop table numt +POSTHOOK: type: DROPTABLE +POSTHOOK: Input: default@numt +POSTHOOK: Output: default@numt