| /* |
| * 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. |
| */ |
| |
| /* |
| * This source file is based on code taken from SQLLine 1.0.2 |
| * See SQLLine notice in LICENSE |
| */ |
| package org.apache.hive.beeline; |
| |
| import java.math.BigDecimal; |
| import java.nio.charset.StandardCharsets; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.text.DecimalFormat; |
| import java.text.NumberFormat; |
| import java.util.Arrays; |
| import java.util.Base64; |
| import java.util.Iterator; |
| |
| import org.apache.hadoop.hive.common.cli.EscapeCRLFHelper; |
| |
| /** |
| * Abstract base class representing a set of rows to be displayed. |
| * Holds column values as strings |
| */ |
| abstract class Rows implements Iterator { |
| protected final BeeLine beeLine; |
| final ResultSetMetaData rsMeta; |
| final Boolean[] primaryKeys; |
| final NumberFormat numberFormat; |
| private boolean convertBinaryArrayToString; |
| private final String nullStr; |
| |
| Rows(BeeLine beeLine, ResultSet rs) throws SQLException { |
| this.beeLine = beeLine; |
| nullStr = beeLine.getOpts().getNullString(); |
| rsMeta = rs.getMetaData(); |
| int count = rsMeta.getColumnCount(); |
| primaryKeys = new Boolean[count]; |
| if (beeLine.getOpts().getNumberFormat().equals("default")) { |
| numberFormat = null; |
| } else { |
| numberFormat = new DecimalFormat(beeLine.getOpts().getNumberFormat()); |
| } |
| this.convertBinaryArrayToString = beeLine.getOpts().getConvertBinaryArrayToString(); |
| } |
| |
| @Override |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Update all of the rows to have the same size, set to the |
| * maximum length of each column in the Rows. |
| */ |
| abstract void normalizeWidths(); |
| |
| /** |
| * Return whether the specified column (0-based index) is |
| * a primary key. Since this method depends on whether the |
| * JDBC driver property implements {@link ResultSetMetaData#getTableName} (many do not), it |
| * is not reliable for all databases. |
| */ |
| boolean isPrimaryKey(int col) { |
| if (primaryKeys[col] == null) { |
| try { |
| // this doesn't always work, since some JDBC drivers (e.g., |
| // Oracle's) return a blank string from getDbTableName. |
| String table = rsMeta.getTableName(col + 1); |
| String column = rsMeta.getColumnName(col + 1); |
| |
| if (table == null || table.isEmpty() || column == null || column.isEmpty()) { |
| primaryKeys[col] = Boolean.FALSE; |
| } else { |
| ResultSet pks = beeLine.getDatabaseConnection().getDatabaseMetaData().getPrimaryKeys( |
| beeLine.getDatabaseConnection().getDatabaseMetaData().getConnection().getCatalog(), null, table); |
| |
| primaryKeys[col] = Boolean.FALSE; |
| try { |
| while (pks.next()) { |
| if (column.equalsIgnoreCase(pks.getString("COLUMN_NAME"))) { |
| primaryKeys[col] = Boolean.TRUE; |
| break; |
| } |
| } |
| } finally { |
| pks.close(); |
| } |
| } |
| } catch (SQLException sqle) { |
| primaryKeys[col] = Boolean.FALSE; |
| } |
| } |
| return primaryKeys[col].booleanValue(); |
| } |
| |
| class Row { |
| final String[] values; |
| final boolean isMeta; |
| boolean deleted; |
| boolean inserted; |
| boolean updated; |
| int[] sizes; |
| |
| Row(int size) throws SQLException { |
| isMeta = true; |
| values = new String[size]; |
| sizes = new int[size]; |
| for (int i = 0; i < size; i++) { |
| values[i] = rsMeta.getColumnLabel(i + 1); |
| sizes[i] = values[i] == null ? 1 : values[i].length(); |
| } |
| |
| deleted = false; |
| updated = false; |
| inserted = false; |
| } |
| |
| @Override |
| public String toString(){ |
| return Arrays.asList(values).toString(); |
| } |
| |
| Row(int size, ResultSet rs) throws SQLException { |
| isMeta = false; |
| values = new String[size]; |
| sizes = new int[size]; |
| |
| try { |
| deleted = rs.rowDeleted(); |
| } catch (Throwable t) { |
| } |
| try { |
| updated = rs.rowUpdated(); |
| } catch (Throwable t) { |
| } |
| try { |
| inserted = rs.rowInserted(); |
| } catch (Throwable t) { |
| } |
| |
| for (int i = 0; i < size; i++) { |
| Object o = rs.getObject(i + 1); |
| String value = null; |
| |
| if (o == null) { |
| value = nullStr; |
| } else if (o instanceof Number) { |
| value = numberFormat != null ? numberFormat.format(o) : |
| o instanceof BigDecimal ? ((BigDecimal)o).toPlainString() : o.toString(); |
| } else if (o instanceof byte[]) { |
| value = convertBinaryArrayToString ? new String((byte[])o, StandardCharsets.UTF_8) : Base64.getEncoder().withoutPadding().encodeToString((byte[])o); |
| } else { |
| value = rs.getString(i + 1); |
| } |
| |
| if (beeLine.getOpts().getEscapeCRLF()) { |
| value = EscapeCRLFHelper.escapeCRLF(value); |
| } |
| |
| values[i] = value.intern(); |
| sizes[i] = value.length(); |
| } |
| } |
| } |
| } |