commit 672085cf103f0cfaf2059cb68050ef2a251041e0 Author: Vihang Karajgaonkar Date: Wed Jun 29 17:03:14 2016 -0700 HIVE-14135 : beeline output not formatted correctly for large column widths diff --git a/beeline/pom.xml b/beeline/pom.xml index a720d0835314221ec3bd9e8d354d148498ff794c..5503add360b07ccf255097248206958a9471d9a8 100644 --- a/beeline/pom.xml +++ b/beeline/pom.xml @@ -119,6 +119,11 @@ test + org.mockito + mockito-all + test + + postgresql postgresql 9.1-901.jdbc4 diff --git a/beeline/src/java/org/apache/hive/beeline/BeeLineOpts.java b/beeline/src/java/org/apache/hive/beeline/BeeLineOpts.java index 5aaa38527734d46de037352ff51e54e0ae1cede0..e2bbbea28f8d66a88116a9805118ee0ba6f12d87 100644 --- a/beeline/src/java/org/apache/hive/beeline/BeeLineOpts.java +++ b/beeline/src/java/org/apache/hive/beeline/BeeLineOpts.java @@ -58,6 +58,7 @@ PROPERTY_PREFIX + "system.exit"; public static final String DEFAULT_NULL_STRING = "NULL"; public static final char DEFAULT_DELIMITER_FOR_DSV = '|'; + public static final int DEFAULT_MAX_COLUMN_WIDTH = 50; public static String URL_ENV_PREFIX = "BEELINE_URL_"; @@ -80,7 +81,7 @@ private final Terminal terminal = TerminalFactory.get(); private int maxWidth = DEFAULT_MAX_WIDTH; private int maxHeight = DEFAULT_MAX_HEIGHT; - private int maxColumnWidth = 15; + private int maxColumnWidth = DEFAULT_MAX_COLUMN_WIDTH; int timeout = -1; private String isolation = DEFAULT_ISOLATION_LEVEL; private String outputFormat = "table"; diff --git a/beeline/src/java/org/apache/hive/beeline/BufferedRows.java b/beeline/src/java/org/apache/hive/beeline/BufferedRows.java index 962c5319bb7e6e448979e1cef80a086cadd2ecc6..5604742068fd0982c12b49ea6ab0567a8873cb00 100644 --- a/beeline/src/java/org/apache/hive/beeline/BufferedRows.java +++ b/beeline/src/java/org/apache/hive/beeline/BufferedRows.java @@ -33,6 +33,7 @@ class BufferedRows extends Rows { private final LinkedList list; private final Iterator iterator; + private int maxColumnWidth; BufferedRows(BeeLine beeLine, ResultSet rs) throws SQLException { super(beeLine, rs); @@ -43,6 +44,7 @@ list.add(new Row(count, rs)); } iterator = list.iterator(); + maxColumnWidth = beeLine.getOpts().getMaxColumnWidth(); } public boolean hasNext() { @@ -66,7 +68,8 @@ void normalizeWidths() { max = new int[row.values.length]; } for (int j = 0; j < max.length; j++) { - max[j] = Math.max(max[j], row.sizes[j] + 1); + // if the max column width is too large, reset it to max allowed Column width + max[j] = Math.min(Math.max(max[j], row.sizes[j] + 1), maxColumnWidth); } } for (Row row : list) { diff --git a/beeline/src/test/org/apache/hive/beeline/TestBufferedRows.java b/beeline/src/test/org/apache/hive/beeline/TestBufferedRows.java new file mode 100644 index 0000000000000000000000000000000000000000..f3f3d3a20cfd751b544636d86ad95e8ad7a2341d --- /dev/null +++ b/beeline/src/test/org/apache/hive/beeline/TestBufferedRows.java @@ -0,0 +1,121 @@ +/** + * 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 static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Matchers; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +public class TestBufferedRows { + private String[][] mockRowData = { + { "key1", "aaa" }, + { "key2", "bbbbb" }, + { "key3", + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, + { "key4", "ddddddddddddddd" } + }; + private BeeLineOpts mockBeeLineOpts; + private BeeLine mockBeeline; + private ResultSet mockResultSet; + private MockRow mockRow; + + @Test + public void testNormalizeWidths() throws SQLException { + setupMockData(); + + BufferedRows bfRows = new BufferedRows(mockBeeline, mockResultSet); + bfRows.normalizeWidths(); + while (bfRows.hasNext()) { + Rows.Row row = (Rows.Row) bfRows.next(); + for (int colSize : row.sizes) { + Assert.assertTrue(colSize <= mockBeeLineOpts.getMaxColumnWidth()); + } + } + } + + private void setupMockData() throws SQLException { + // Mock BeeLine + mockBeeline = mock(BeeLine.class); + // Mock BeeLineOpts + mockBeeLineOpts = mock(BeeLineOpts.class); + when(mockBeeLineOpts.getMaxColumnWidth()).thenReturn(BeeLineOpts.DEFAULT_MAX_COLUMN_WIDTH); + when(mockBeeLineOpts.getNumberFormat()).thenReturn("default"); + when(mockBeeLineOpts.getNullString()).thenReturn("NULL"); + when(mockBeeline.getOpts()).thenReturn(mockBeeLineOpts); + + // MockResultSet + mockResultSet = mock(ResultSet.class); + + ResultSetMetaData mockResultSetMetaData = mock(ResultSetMetaData.class); + when(mockResultSetMetaData.getColumnCount()).thenReturn(2); + when(mockResultSetMetaData.getColumnLabel(1)).thenReturn("Key"); + when(mockResultSetMetaData.getColumnLabel(2)).thenReturn("Value"); + when(mockResultSet.getMetaData()).thenReturn(mockResultSetMetaData); + + mockRow = new MockRow(); + // returns true as long as there is more data in mockResultData array + when(mockResultSet.next()).thenAnswer(new Answer() { + private int mockRowDataIndex = 0; + + public Boolean answer(InvocationOnMock invocation) { + if (mockRowDataIndex < mockRowData.length) { + mockRow.setCurrentRowData(mockRowData[mockRowDataIndex]); + mockRowDataIndex++; + return true; + } else { + return false; + } + } + }); + + when(mockResultSet.getString(Matchers.anyInt())).thenAnswer(new Answer() { + public String answer(InvocationOnMock invocation) { + Object[] args = invocation.getArguments(); + int index = ((Integer) args[0]).intValue(); + return mockRow.getColumn(index); + } + }); + } + + static class MockRow { + String[] rowData; + + public void setCurrentRowData(String[] rowData) { + this.rowData = rowData; + } + + public String getColumn(int idx) { + return rowData[idx - 1]; + } + } +} \ No newline at end of file