| /* |
| * 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.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.lang.reflect.Method; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.sql.CallableStatement; |
| import java.sql.Connection; |
| import java.sql.DatabaseMetaData; |
| import java.sql.Driver; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.SQLWarning; |
| import java.sql.Statement; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.TreeSet; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| |
| import org.apache.hadoop.hive.common.cli.ShellCmdExecutor; |
| import org.apache.hadoop.hive.conf.HiveConf; |
| import org.apache.hadoop.hive.conf.HiveVariableSource; |
| import org.apache.hadoop.hive.conf.SystemVariables; |
| import org.apache.hadoop.hive.conf.VariableSubstitution; |
| import org.apache.hadoop.io.IOUtils; |
| import org.apache.hive.beeline.logs.BeelineInPlaceUpdateStream; |
| import org.apache.hive.common.util.HiveStringUtils; |
| import org.apache.hive.jdbc.HiveStatement; |
| import org.apache.hive.jdbc.Utils; |
| import org.apache.hive.jdbc.Utils.JdbcConnectionParams; |
| import org.apache.hive.jdbc.logs.InPlaceUpdateStream; |
| |
| public class Commands { |
| |
| private final BeeLine beeLine; |
| private static final int DEFAULT_QUERY_PROGRESS_INTERVAL = 1000; |
| private static final int DEFAULT_QUERY_PROGRESS_THREAD_TIMEOUT = 10 * 1000; |
| |
| /** |
| * @param beeLine |
| */ |
| Commands(BeeLine beeLine) { |
| this.beeLine = beeLine; |
| } |
| |
| |
| public boolean metadata(String line) { |
| beeLine.debug(line); |
| |
| String[] parts = beeLine.split(line); |
| List<String> params = new LinkedList<String>(Arrays.asList(parts)); |
| if (parts == null || parts.length == 0) { |
| return dbinfo(""); |
| } |
| |
| params.remove(0); |
| params.remove(0); |
| beeLine.debug(params.toString()); |
| return metadata(parts[1], |
| params.toArray(new String[0])); |
| } |
| |
| |
| public boolean metadata(String cmd, String[] args) { |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| |
| try { |
| Method[] m = beeLine.getDatabaseMetaData().getClass().getMethods(); |
| Set<String> methodNames = new TreeSet<String>(); |
| Set<String> methodNamesUpper = new TreeSet<String>(); |
| for (int i = 0; i < m.length; i++) { |
| methodNames.add(m[i].getName()); |
| methodNamesUpper.add(m[i].getName().toUpperCase()); |
| } |
| |
| if (!methodNamesUpper.contains(cmd.toUpperCase())) { |
| beeLine.error(beeLine.loc("no-such-method", cmd)); |
| beeLine.error(beeLine.loc("possible-methods")); |
| for (Iterator<String> i = methodNames.iterator(); i.hasNext();) { |
| beeLine.error(" " + i.next()); |
| } |
| return false; |
| } |
| |
| Object res = beeLine.getReflector().invoke(beeLine.getDatabaseMetaData(), |
| DatabaseMetaData.class, cmd, Arrays.asList(args)); |
| |
| if (res instanceof ResultSet) { |
| ResultSet rs = (ResultSet) res; |
| if (rs != null) { |
| try { |
| beeLine.print(rs); |
| } finally { |
| rs.close(); |
| } |
| } |
| } else if (res != null) { |
| beeLine.output(res.toString()); |
| } |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| |
| return true; |
| } |
| |
| public boolean addlocaldrivername(String line) { |
| String driverName = arg1(line, "driver class name"); |
| try { |
| beeLine.setDrivers(beeLine.scanDrivers()); |
| } catch (IOException e) { |
| beeLine.error("Fail to scan drivers due to the exception:" + e); |
| beeLine.error(e); |
| } |
| for (Driver d : beeLine.getDrivers()) { |
| if (driverName.equals(d.getClass().getName())) { |
| beeLine.addLocalDriverClazz(driverName); |
| return true; |
| } |
| } |
| beeLine.error("Fail to find a driver which contains the driver class"); |
| return false; |
| } |
| |
| public boolean addlocaldriverjar(String line) { |
| // If jar file is in the hdfs, it should be downloaded first. |
| String jarPath = arg1(line, "jar path"); |
| File p = new File(jarPath); |
| if (!p.exists()) { |
| beeLine.error("The jar file in the path " + jarPath + " can't be found!"); |
| return false; |
| } |
| |
| ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); |
| try { |
| beeLine.debug(jarPath + " is added to the local beeline."); |
| URLClassLoader newClassLoader = new URLClassLoader(new URL[]{p.toURL()}, classLoader); |
| |
| Thread.currentThread().setContextClassLoader(newClassLoader); |
| beeLine.setDrivers(beeLine.scanDrivers()); |
| } catch (Exception e) { |
| beeLine.error("Fail to add local jar due to the exception:" + e); |
| beeLine.error(e); |
| } |
| return true; |
| } |
| |
| public boolean history(String line) { |
| Iterator hist = beeLine.getConsoleReader().getHistory().entries(); |
| String[] tmp; |
| while(hist.hasNext()){ |
| tmp = hist.next().toString().split(":", 2); |
| tmp[0] = Integer.toString(Integer.parseInt(tmp[0]) + 1); |
| beeLine.output(beeLine.getColorBuffer().pad(tmp[0], 6) |
| .append(":" + tmp[1])); |
| } |
| return true; |
| } |
| |
| |
| String arg1(String line, String paramname) { |
| return arg1(line, paramname, null); |
| } |
| |
| |
| String arg1(String line, String paramname, String def) { |
| String[] ret = beeLine.split(line); |
| |
| if (ret == null || ret.length != 2) { |
| if (def != null) { |
| return def; |
| } |
| throw new IllegalArgumentException(beeLine.loc("arg-usage", |
| new Object[] {ret == null || ret.length == 0 ? "" : ret[0], |
| paramname})); |
| } |
| return ret[1]; |
| } |
| |
| |
| public boolean indexes(String line) throws Exception { |
| return metadata("getIndexInfo", new String[] { |
| beeLine.getConnection().getCatalog(), null, |
| arg1(line, "table name"), |
| false + "", |
| true + ""}); |
| } |
| |
| |
| public boolean primarykeys(String line) throws Exception { |
| return metadata("getPrimaryKeys", new String[] { |
| beeLine.getConnection().getCatalog(), null, |
| arg1(line, "table name"),}); |
| } |
| |
| |
| public boolean exportedkeys(String line) throws Exception { |
| return metadata("getExportedKeys", |
| new String[] { beeLine.getConnection().getCatalog(), null, arg1(line, "table name"), }); |
| } |
| |
| |
| public boolean importedkeys(String line) throws Exception { |
| return metadata("getImportedKeys", new String[] { |
| beeLine.getConnection().getCatalog(), null, |
| arg1(line, "table name"),}); |
| } |
| |
| |
| public boolean procedures(String line) throws Exception { |
| return metadata("getProcedures", new String[] { |
| beeLine.getConnection().getCatalog(), null, |
| arg1(line, "procedure name pattern", "%"),}); |
| } |
| |
| |
| public boolean tables(String line) throws Exception { |
| return metadata("getTables", new String[] { |
| beeLine.getConnection().getCatalog(), null, |
| arg1(line, "table name", "%"), null}); |
| } |
| |
| |
| public boolean typeinfo(String line) throws Exception { |
| return metadata("getTypeInfo", new String[0]); |
| } |
| |
| |
| public boolean nativesql(String sql) throws Exception { |
| if (sql.startsWith(BeeLine.COMMAND_PREFIX)) { |
| sql = sql.substring(1); |
| } |
| if (sql.startsWith("native")) { |
| sql = sql.substring("native".length() + 1); |
| } |
| String nat = beeLine.getConnection().nativeSQL(sql); |
| beeLine.output(nat); |
| return true; |
| } |
| |
| |
| public boolean columns(String line) throws Exception { |
| return metadata("getColumns", new String[] { |
| beeLine.getConnection().getCatalog(), null, |
| arg1(line, "table name"), "%"}); |
| } |
| |
| |
| public boolean dropall(String line) { |
| if (beeLine.getDatabaseConnection() == null || beeLine.getDatabaseConnection().getUrl() == null) { |
| return beeLine.error(beeLine.loc("no-current-connection")); |
| } |
| try { |
| if (!(beeLine.getConsoleReader().readLine(beeLine.loc("really-drop-all")).equals("y"))) { |
| return beeLine.error("abort-drop-all"); |
| } |
| |
| List<String> cmds = new LinkedList<String>(); |
| ResultSet rs = beeLine.getTables(); |
| try { |
| while (rs.next()) { |
| cmds.add("DROP TABLE " |
| + rs.getString("TABLE_NAME") + beeLine.getOpts().getDelimiter()); |
| } |
| } finally { |
| try { |
| rs.close(); |
| } catch (Exception e) { |
| beeLine.error(e); |
| } |
| } |
| // run as a batch |
| return beeLine.runCommands(cmds) == cmds.size(); |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| } |
| |
| |
| public boolean reconnect(String line) { |
| if (beeLine.getDatabaseConnection() == null || beeLine.getDatabaseConnection().getUrl() == null) { |
| // First, let's try connecting using the last successful url - if that fails, then we error out. |
| String lastConnectedUrl = beeLine.getOpts().getLastConnectedUrl(); |
| if (lastConnectedUrl != null){ |
| Properties props = new Properties(); |
| props.setProperty("url",lastConnectedUrl); |
| try { |
| return connect(props); |
| } catch (IOException e) { |
| return beeLine.error(e); |
| } |
| } else { |
| return beeLine.error(beeLine.loc("no-current-connection")); |
| } |
| } |
| beeLine.info(beeLine.loc("reconnecting", beeLine.getDatabaseConnection().getUrl())); |
| try { |
| beeLine.getDatabaseConnection().reconnect(); |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| return true; |
| } |
| |
| |
| public boolean scan(String line) throws IOException { |
| TreeSet<String> names = new TreeSet<String>(); |
| |
| if (beeLine.getDrivers() == null) { |
| beeLine.setDrivers(beeLine.scanDrivers()); |
| } |
| |
| beeLine.info(beeLine.loc("drivers-found-count", beeLine.getDrivers().size())); |
| |
| // unique the list |
| for (Iterator<Driver> i = beeLine.getDrivers().iterator(); i.hasNext();) { |
| names.add(i.next().getClass().getName()); |
| } |
| |
| beeLine.output(beeLine.getColorBuffer() |
| .bold(beeLine.getColorBuffer().pad(beeLine.loc("compliant"), 10).getMono()) |
| .bold(beeLine.getColorBuffer().pad(beeLine.loc("jdbc-version"), 8).getMono()) |
| .bold(beeLine.getColorBuffer(beeLine.loc("driver-class")).getMono())); |
| |
| for (Iterator<String> i = names.iterator(); i.hasNext();) { |
| String name = i.next().toString(); |
| try { |
| Driver driver = (Driver) Class.forName(name).newInstance(); |
| ColorBuffer msg = beeLine.getColorBuffer() |
| .pad(driver.jdbcCompliant() ? "yes" : "no", 10) |
| .pad(driver.getMajorVersion() + "." |
| + driver.getMinorVersion(), 8) |
| .append(name); |
| if (driver.jdbcCompliant()) { |
| beeLine.output(msg); |
| } else { |
| beeLine.output(beeLine.getColorBuffer().red(msg.getMono())); |
| } |
| } catch (Throwable t) { |
| beeLine.output(beeLine.getColorBuffer().red(name)); // error with driver |
| } |
| } |
| return true; |
| } |
| |
| |
| public boolean save(String line) throws IOException { |
| beeLine.info(beeLine.loc("saving-options", beeLine.getOpts().getPropertiesFile())); |
| beeLine.getOpts().save(); |
| return true; |
| } |
| |
| |
| public boolean load(String line) throws IOException { |
| beeLine.getOpts().load(); |
| beeLine.info(beeLine.loc("loaded-options", beeLine.getOpts().getPropertiesFile())); |
| return true; |
| } |
| |
| |
| public boolean config(String line) { |
| try { |
| Properties props = beeLine.getOpts().toProperties(); |
| Set keys = new TreeSet(props.keySet()); |
| for (Iterator i = keys.iterator(); i.hasNext();) { |
| String key = (String) i.next(); |
| beeLine.output(beeLine.getColorBuffer() |
| .green(beeLine.getColorBuffer().pad(key.substring( |
| beeLine.getOpts().PROPERTY_PREFIX.length()), 20) |
| .getMono()) |
| .append(props.getProperty(key))); |
| } |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| return true; |
| } |
| |
| |
| public boolean set(String line) { |
| if (line == null || line.trim().equals("set") |
| || line.length() == 0) { |
| return config(null); |
| } |
| |
| String[] parts = beeLine.split(line, 3, "Usage: set <key> <value>"); |
| if (parts == null) { |
| return false; |
| } |
| |
| String key = parts[1]; |
| String value = parts[2]; |
| boolean success = beeLine.getOpts().set(key, value, false); |
| // if we autosave, then save |
| if (success && beeLine.getOpts().getAutosave()) { |
| try { |
| beeLine.getOpts().save(); |
| } catch (Exception saveException) { |
| } |
| } |
| return success; |
| } |
| |
| |
| public boolean commit(String line) throws SQLException { |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| if (!(beeLine.assertAutoCommit())) { |
| return false; |
| } |
| try { |
| long start = System.currentTimeMillis(); |
| beeLine.getDatabaseConnection().getConnection().commit(); |
| long end = System.currentTimeMillis(); |
| beeLine.showWarnings(); |
| beeLine.info(beeLine.loc("commit-complete") |
| + " " + beeLine.locElapsedTime(end - start)); |
| return true; |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| } |
| |
| |
| public boolean rollback(String line) throws SQLException { |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| if (!(beeLine.assertAutoCommit())) { |
| return false; |
| } |
| try { |
| long start = System.currentTimeMillis(); |
| beeLine.getDatabaseConnection().getConnection().rollback(); |
| long end = System.currentTimeMillis(); |
| beeLine.showWarnings(); |
| beeLine.info(beeLine.loc("rollback-complete") |
| + " " + beeLine.locElapsedTime(end - start)); |
| return true; |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| } |
| |
| |
| public boolean autocommit(String line) throws SQLException { |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| if (line.endsWith("on")) { |
| beeLine.getDatabaseConnection().getConnection().setAutoCommit(true); |
| } else if (line.endsWith("off")) { |
| beeLine.getDatabaseConnection().getConnection().setAutoCommit(false); |
| } |
| beeLine.showWarnings(); |
| beeLine.autocommitStatus(beeLine.getDatabaseConnection().getConnection()); |
| return true; |
| } |
| |
| |
| public boolean dbinfo(String line) { |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| |
| beeLine.showWarnings(); |
| int padlen = 50; |
| |
| String[] m = new String[] { |
| "allProceduresAreCallable", |
| "allTablesAreSelectable", |
| "dataDefinitionCausesTransactionCommit", |
| "dataDefinitionIgnoredInTransactions", |
| "doesMaxRowSizeIncludeBlobs", |
| "getCatalogSeparator", |
| "getCatalogTerm", |
| "getDatabaseProductName", |
| "getDatabaseProductVersion", |
| "getDefaultTransactionIsolation", |
| "getDriverMajorVersion", |
| "getDriverMinorVersion", |
| "getDriverName", |
| "getDriverVersion", |
| "getExtraNameCharacters", |
| "getIdentifierQuoteString", |
| "getMaxBinaryLiteralLength", |
| "getMaxCatalogNameLength", |
| "getMaxCharLiteralLength", |
| "getMaxColumnNameLength", |
| "getMaxColumnsInGroupBy", |
| "getMaxColumnsInIndex", |
| "getMaxColumnsInOrderBy", |
| "getMaxColumnsInSelect", |
| "getMaxColumnsInTable", |
| "getMaxConnections", |
| "getMaxCursorNameLength", |
| "getMaxIndexLength", |
| "getMaxProcedureNameLength", |
| "getMaxRowSize", |
| "getMaxSchemaNameLength", |
| "getMaxStatementLength", |
| "getMaxStatements", |
| "getMaxTableNameLength", |
| "getMaxTablesInSelect", |
| "getMaxUserNameLength", |
| "getNumericFunctions", |
| "getProcedureTerm", |
| "getSchemaTerm", |
| "getSearchStringEscape", |
| "getSQLKeywords", |
| "getStringFunctions", |
| "getSystemFunctions", |
| "getTimeDateFunctions", |
| "getURL", |
| "getUserName", |
| "isCatalogAtStart", |
| "isReadOnly", |
| "nullPlusNonNullIsNull", |
| "nullsAreSortedAtEnd", |
| "nullsAreSortedAtStart", |
| "nullsAreSortedHigh", |
| "nullsAreSortedLow", |
| "storesLowerCaseIdentifiers", |
| "storesLowerCaseQuotedIdentifiers", |
| "storesMixedCaseIdentifiers", |
| "storesMixedCaseQuotedIdentifiers", |
| "storesUpperCaseIdentifiers", |
| "storesUpperCaseQuotedIdentifiers", |
| "supportsAlterTableWithAddColumn", |
| "supportsAlterTableWithDropColumn", |
| "supportsANSI92EntryLevelSQL", |
| "supportsANSI92FullSQL", |
| "supportsANSI92IntermediateSQL", |
| "supportsBatchUpdates", |
| "supportsCatalogsInDataManipulation", |
| "supportsCatalogsInIndexDefinitions", |
| "supportsCatalogsInPrivilegeDefinitions", |
| "supportsCatalogsInProcedureCalls", |
| "supportsCatalogsInTableDefinitions", |
| "supportsColumnAliasing", |
| "supportsConvert", |
| "supportsCoreSQLGrammar", |
| "supportsCorrelatedSubqueries", |
| "supportsDataDefinitionAndDataManipulationTransactions", |
| "supportsDataManipulationTransactionsOnly", |
| "supportsDifferentTableCorrelationNames", |
| "supportsExpressionsInOrderBy", |
| "supportsExtendedSQLGrammar", |
| "supportsFullOuterJoins", |
| "supportsGroupBy", |
| "supportsGroupByBeyondSelect", |
| "supportsGroupByUnrelated", |
| "supportsIntegrityEnhancementFacility", |
| "supportsLikeEscapeClause", |
| "supportsLimitedOuterJoins", |
| "supportsMinimumSQLGrammar", |
| "supportsMixedCaseIdentifiers", |
| "supportsMixedCaseQuotedIdentifiers", |
| "supportsMultipleResultSets", |
| "supportsMultipleTransactions", |
| "supportsNonNullableColumns", |
| "supportsOpenCursorsAcrossCommit", |
| "supportsOpenCursorsAcrossRollback", |
| "supportsOpenStatementsAcrossCommit", |
| "supportsOpenStatementsAcrossRollback", |
| "supportsOrderByUnrelated", |
| "supportsOuterJoins", |
| "supportsPositionedDelete", |
| "supportsPositionedUpdate", |
| "supportsSchemasInDataManipulation", |
| "supportsSchemasInIndexDefinitions", |
| "supportsSchemasInPrivilegeDefinitions", |
| "supportsSchemasInProcedureCalls", |
| "supportsSchemasInTableDefinitions", |
| "supportsSelectForUpdate", |
| "supportsStoredProcedures", |
| "supportsSubqueriesInComparisons", |
| "supportsSubqueriesInExists", |
| "supportsSubqueriesInIns", |
| "supportsSubqueriesInQuantifieds", |
| "supportsTableCorrelationNames", |
| "supportsTransactions", |
| "supportsUnion", |
| "supportsUnionAll", |
| "usesLocalFilePerTable", |
| "usesLocalFiles", |
| }; |
| |
| for (int i = 0; i < m.length; i++) { |
| try { |
| beeLine.output(beeLine.getColorBuffer().pad(m[i], padlen).append( |
| "" + beeLine.getReflector().invoke(beeLine.getDatabaseMetaData(), |
| m[i], new Object[0]))); |
| } catch (Exception e) { |
| beeLine.output(beeLine.getColorBuffer().pad(m[i], padlen), false); |
| beeLine.handleException(e); |
| } |
| } |
| return true; |
| } |
| |
| |
| public boolean verbose(String line) { |
| beeLine.info("verbose: on"); |
| return set("set verbose true"); |
| } |
| |
| |
| public boolean outputformat(String line) { |
| return set("set " + line); |
| } |
| |
| |
| public boolean brief(String line) { |
| beeLine.info("verbose: off"); |
| return set("set verbose false"); |
| } |
| |
| |
| public boolean isolation(String line) throws SQLException { |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| |
| int i; |
| |
| if (line.endsWith("TRANSACTION_NONE")) { |
| i = Connection.TRANSACTION_NONE; |
| } else if (line.endsWith("TRANSACTION_READ_COMMITTED")) { |
| i = Connection.TRANSACTION_READ_COMMITTED; |
| } else if (line.endsWith("TRANSACTION_READ_UNCOMMITTED")) { |
| i = Connection.TRANSACTION_READ_UNCOMMITTED; |
| } else if (line.endsWith("TRANSACTION_REPEATABLE_READ")) { |
| i = Connection.TRANSACTION_REPEATABLE_READ; |
| } else if (line.endsWith("TRANSACTION_SERIALIZABLE")) { |
| i = Connection.TRANSACTION_SERIALIZABLE; |
| } else { |
| return beeLine.error("Usage: isolation <TRANSACTION_NONE " |
| + "| TRANSACTION_READ_COMMITTED " |
| + "| TRANSACTION_READ_UNCOMMITTED " |
| + "| TRANSACTION_REPEATABLE_READ " |
| + "| TRANSACTION_SERIALIZABLE>"); |
| } |
| |
| beeLine.getDatabaseConnection().getConnection().setTransactionIsolation(i); |
| |
| int isol = beeLine.getDatabaseConnection().getConnection().getTransactionIsolation(); |
| final String isoldesc; |
| switch (i) |
| { |
| case Connection.TRANSACTION_NONE: |
| isoldesc = "TRANSACTION_NONE"; |
| break; |
| case Connection.TRANSACTION_READ_COMMITTED: |
| isoldesc = "TRANSACTION_READ_COMMITTED"; |
| break; |
| case Connection.TRANSACTION_READ_UNCOMMITTED: |
| isoldesc = "TRANSACTION_READ_UNCOMMITTED"; |
| break; |
| case Connection.TRANSACTION_REPEATABLE_READ: |
| isoldesc = "TRANSACTION_REPEATABLE_READ"; |
| break; |
| case Connection.TRANSACTION_SERIALIZABLE: |
| isoldesc = "TRANSACTION_SERIALIZABLE"; |
| break; |
| default: |
| isoldesc = "UNKNOWN"; |
| } |
| |
| beeLine.info(beeLine.loc("isolation-status", isoldesc)); |
| return true; |
| } |
| |
| |
| public boolean batch(String line) { |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| if (beeLine.getBatch() == null) { |
| beeLine.setBatch(new LinkedList<String>()); |
| beeLine.info(beeLine.loc("batch-start")); |
| return true; |
| } else { |
| beeLine.info(beeLine.loc("running-batch")); |
| try { |
| beeLine.runBatch(beeLine.getBatch()); |
| return true; |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } finally { |
| beeLine.setBatch(null); |
| } |
| } |
| } |
| |
| public boolean sql(String line) { |
| return execute(line, false, false); |
| } |
| |
| /** |
| * This method is used for retrieving the latest configuration from hive server2. |
| * It uses the set command processor. |
| * |
| * @return |
| */ |
| private Map<String, String> getHiveVariables() { |
| Map<String, String> result = new HashMap<>(); |
| BufferedRows rows = getConfInternal(true); |
| if (rows != null) { |
| while (rows.hasNext()) { |
| Rows.Row row = (Rows.Row) rows.next(); |
| if (!row.isMeta) { |
| result.put(row.values[0], row.values[1]); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * This method should only be used in CLI mode. |
| * |
| * @return the hive configuration from server side |
| */ |
| public HiveConf getHiveConf(boolean call) { |
| HiveConf hiveConf = beeLine.getOpts().getConf(); |
| if (hiveConf != null && call) { |
| return hiveConf; |
| } else { |
| return getHiveConfHelper(call); |
| } |
| } |
| |
| public HiveConf getHiveConfHelper(boolean call) { |
| HiveConf conf = new HiveConf(); |
| BufferedRows rows = getConfInternal(call); |
| while (rows != null && rows.hasNext()) { |
| addConf((Rows.Row) rows.next(), conf); |
| } |
| return conf; |
| } |
| |
| /** |
| * Use call statement to retrieve the configurations for substitution and sql for the substitution. |
| * |
| * @param call |
| * @return |
| */ |
| private BufferedRows getConfInternal(boolean call) { |
| Statement stmnt = null; |
| BufferedRows rows = null; |
| ResultSet rs = null; |
| try { |
| boolean hasResults = false; |
| DatabaseConnection dbconn = beeLine.getDatabaseConnection(); |
| Connection conn = null; |
| if (dbconn != null) |
| conn = dbconn.getConnection(); |
| if (conn != null) { |
| if (call) { |
| stmnt = conn.prepareCall("set"); |
| hasResults = ((CallableStatement) stmnt).execute(); |
| } else { |
| stmnt = beeLine.createStatement(); |
| hasResults = stmnt.execute("set"); |
| } |
| } |
| if (hasResults) { |
| rs = stmnt.getResultSet(); |
| rows = new BufferedRows(beeLine, rs); |
| } |
| } catch (SQLException e) { |
| beeLine.error(e); |
| } finally { |
| if (rs != null) { |
| try { |
| rs.close(); |
| } catch (SQLException e1) { |
| beeLine.error(e1); |
| } |
| } |
| if (stmnt != null) { |
| try { |
| stmnt.close(); |
| } catch (SQLException e2) { |
| beeLine.error(e2); |
| } |
| } |
| } |
| return rows; |
| } |
| |
| private void addConf(Rows.Row r, HiveConf hiveConf) { |
| if (r.isMeta) { |
| return; |
| } |
| if (r.values == null || r.values[0] == null || r.values[0].isEmpty()) { |
| return; |
| } |
| String val = r.values[0]; |
| if (r.values[0].startsWith(SystemVariables.SYSTEM_PREFIX) || r.values[0] |
| .startsWith(SystemVariables.ENV_PREFIX)) { |
| return; |
| } else { |
| String[] kv = val.split("=", 2); |
| if (kv.length == 2) |
| hiveConf.set(kv[0], kv[1]); |
| } |
| } |
| |
| /** |
| * Extract and clean up the first command in the input. |
| */ |
| private String getFirstCmd(String cmd, int length) { |
| return cmd.substring(length).trim(); |
| } |
| |
| private String[] tokenizeCmd(String cmd) { |
| return cmd.split("\\s+"); |
| } |
| |
| private boolean isSourceCMD(String cmd) { |
| if (cmd == null || cmd.isEmpty()) |
| return false; |
| String[] tokens = tokenizeCmd(cmd); |
| return tokens[0].equalsIgnoreCase("source"); |
| } |
| |
| private boolean sourceFile(String cmd) { |
| String[] tokens = tokenizeCmd(cmd); |
| String cmd_1 = getFirstCmd(cmd, tokens[0].length()); |
| |
| cmd_1 = substituteVariables(getHiveConf(false), cmd_1); |
| File sourceFile = new File(cmd_1); |
| if (!sourceFile.isFile()) { |
| return false; |
| } else { |
| boolean ret; |
| try { |
| ret = sourceFileInternal(sourceFile); |
| } catch (IOException e) { |
| beeLine.error(e); |
| return false; |
| } |
| return ret; |
| } |
| } |
| |
| private boolean sourceFileInternal(File sourceFile) throws IOException { |
| BufferedReader reader = null; |
| try { |
| reader = new BufferedReader(new FileReader(sourceFile)); |
| String lines = null, extra; |
| while ((extra = reader.readLine()) != null) { |
| if (beeLine.isComment(extra)) { |
| continue; |
| } |
| if (lines == null) { |
| lines = extra; |
| } else { |
| lines += "\n" + extra; |
| } |
| } |
| String[] cmds = lines.split(beeLine.getOpts().getDelimiter()); |
| for (String c : cmds) { |
| c = c.trim(); |
| if (!executeInternal(c, false)) { |
| return false; |
| } |
| } |
| } finally { |
| if (reader != null) { |
| reader.close(); |
| } |
| } |
| return true; |
| } |
| |
| public String cliToBeelineCmd(String cmd) { |
| if (cmd == null) |
| return null; |
| if (cmd.toLowerCase().equals("quit") || cmd.toLowerCase().equals("exit")) { |
| return BeeLine.COMMAND_PREFIX + cmd; |
| } else if (cmd.startsWith("!")) { |
| String shell_cmd = cmd.substring(1); |
| return "!sh " + shell_cmd; |
| } else { // local mode |
| // command like dfs |
| return cmd; |
| } |
| } |
| |
| // Return false only occurred error when execution the sql and the sql should follow the rules |
| // of beeline. |
| private boolean executeInternal(String sql, boolean call) { |
| if (!beeLine.isBeeLine()) { |
| sql = cliToBeelineCmd(sql); |
| } |
| |
| if (sql == null || sql.length() == 0) { |
| return true; |
| } |
| |
| if (beeLine.isComment(sql)) { |
| //skip this and rest cmds in the line |
| return true; |
| } |
| |
| // is source CMD |
| if (isSourceCMD(sql)) { |
| return sourceFile(sql); |
| } |
| |
| if (sql.startsWith(BeeLine.COMMAND_PREFIX)) { |
| return beeLine.execCommandWithPrefix(sql); |
| } |
| |
| String prefix = call ? "call" : "sql"; |
| |
| if (sql.startsWith(prefix)) { |
| sql = sql.substring(prefix.length()); |
| } |
| |
| // batch statements? |
| if (beeLine.getBatch() != null) { |
| beeLine.getBatch().add(sql); |
| return true; |
| } |
| |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| |
| ClientHook hook = ClientCommandHookFactory.get().getHook(beeLine, sql); |
| |
| try { |
| Statement stmnt = null; |
| boolean hasResults; |
| Thread logThread = null; |
| |
| try { |
| long start = System.currentTimeMillis(); |
| |
| if (call) { |
| stmnt = beeLine.getDatabaseConnection().getConnection().prepareCall(sql); |
| hasResults = ((CallableStatement) stmnt).execute(); |
| } else { |
| stmnt = beeLine.createStatement(); |
| // In test mode we want the operation logs regardless of the settings |
| if (!beeLine.isTestMode() && beeLine.getOpts().isSilent()) { |
| hasResults = stmnt.execute(sql); |
| } else { |
| InPlaceUpdateStream.EventNotifier eventNotifier = |
| new InPlaceUpdateStream.EventNotifier(); |
| logThread = new Thread(createLogRunnable(stmnt, eventNotifier)); |
| logThread.setDaemon(true); |
| logThread.start(); |
| if (stmnt instanceof HiveStatement) { |
| HiveStatement hiveStatement = (HiveStatement) stmnt; |
| hiveStatement.setInPlaceUpdateStream( |
| new BeelineInPlaceUpdateStream( |
| beeLine.getErrorStream(), |
| eventNotifier |
| )); |
| } |
| hasResults = stmnt.execute(sql); |
| logThread.interrupt(); |
| logThread.join(DEFAULT_QUERY_PROGRESS_THREAD_TIMEOUT); |
| } |
| } |
| |
| beeLine.showWarnings(); |
| |
| if (hasResults) { |
| OutputFile outputFile = beeLine.getRecordOutputFile(); |
| if (beeLine.isTestMode() && outputFile != null && outputFile.isActiveConverter()) { |
| outputFile.fetchStarted(); |
| if (!sql.trim().toLowerCase().startsWith("explain")) { |
| outputFile.foundQuery(true); |
| } else { |
| outputFile.foundQuery(false); |
| } |
| } |
| do { |
| ResultSet rs = stmnt.getResultSet(); |
| try { |
| int count = beeLine.print(rs); |
| long end = System.currentTimeMillis(); |
| |
| if (showReport()) { |
| beeLine.output(beeLine.loc("rows-selected", count) + " " + beeLine.locElapsedTime(end - start), |
| true, beeLine.getErrorStream()); |
| } |
| } finally { |
| if (logThread != null) { |
| logThread.join(DEFAULT_QUERY_PROGRESS_THREAD_TIMEOUT); |
| showRemainingLogsIfAny(stmnt); |
| logThread = null; |
| } |
| rs.close(); |
| } |
| } while (BeeLine.getMoreResults(stmnt)); |
| if (beeLine.isTestMode() && outputFile != null && outputFile.isActiveConverter()) { |
| outputFile.fetchFinished(); |
| } |
| } else { |
| int count = stmnt.getUpdateCount(); |
| long end = System.currentTimeMillis(); |
| |
| if (showReport()) { |
| beeLine.output(beeLine.loc("rows-affected", count) + " " + beeLine.locElapsedTime(end - start), |
| true, beeLine.getErrorStream()); |
| } |
| } |
| } finally { |
| if (logThread != null) { |
| if (!logThread.isInterrupted()) { |
| logThread.interrupt(); |
| } |
| logThread.join(DEFAULT_QUERY_PROGRESS_THREAD_TIMEOUT); |
| if (stmnt != null) { |
| showRemainingLogsIfAny(stmnt); |
| } |
| } |
| if (stmnt != null) { |
| stmnt.close(); |
| } |
| } |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| beeLine.showWarnings(); |
| if (hook != null) { |
| hook.postHook(beeLine); |
| } |
| return true; |
| } |
| |
| private boolean showReport() { |
| if (beeLine.getOpts().isReport() != null) { |
| return beeLine.getOpts().isReport(); |
| } |
| return !beeLine.getOpts().isSilent(); |
| } |
| |
| /* |
| * Check if the input line is a multi-line command which needs to read further |
| */ |
| public String handleMultiLineCmd(String line) throws IOException { |
| line = HiveStringUtils.removeComments(line); |
| Character mask = (System.getProperty("jline.terminal", "").equals("jline.UnsupportedTerminal")) ? null |
| : jline.console.ConsoleReader.NULL_MASK; |
| |
| while (isMultiLine(line) && beeLine.getOpts().isAllowMultiLineCommand()) { |
| StringBuilder prompt = new StringBuilder(beeLine.getPrompt()); |
| if (!beeLine.getOpts().isSilent()) { |
| for (int i = 0; i < prompt.length() - 1; i++) { |
| if (prompt.charAt(i) != '>') { |
| prompt.setCharAt(i, i % 2 == 0 ? '.' : ' '); |
| } |
| } |
| } |
| String extra; |
| //avoid NPE below if for some reason -e argument has multi-line command |
| if (beeLine.getConsoleReader() == null) { |
| throw new RuntimeException("Console reader not initialized. This could happen when there " |
| + "is a multi-line command using -e option and which requires further reading from console"); |
| } |
| if (beeLine.getOpts().isSilent() && beeLine.getOpts().getScriptFile() != null) { |
| extra = beeLine.getConsoleReader().readLine(null, mask); |
| } else { |
| extra = beeLine.getConsoleReader().readLine(prompt.toString()); |
| } |
| |
| if (extra == null) { //it happens when using -f and the line of cmds does not end with ; |
| break; |
| } |
| extra = HiveStringUtils.removeComments(extra); |
| if (extra != null && !extra.isEmpty()) { |
| line += "\n" + extra; |
| } |
| } |
| return line; |
| } |
| |
| //returns true if statement represented by line is |
| //not complete and needs additional reading from |
| //console. Used in handleMultiLineCmd method |
| //assumes line would never be null when this method is called |
| private boolean isMultiLine(String line) { |
| line = line.trim(); |
| if (line.endsWith(beeLine.getOpts().getDelimiter()) || beeLine.isComment(line)) { |
| return false; |
| } |
| // handles the case like line = show tables; --test comment |
| List<String> cmds = getCmdList(line, false); |
| if (!cmds.isEmpty() && cmds.get(cmds.size() - 1).trim().startsWith("--")) { |
| return false; |
| } |
| return true; |
| } |
| |
| public boolean sql(String line, boolean entireLineAsCommand) { |
| return execute(line, false, entireLineAsCommand); |
| } |
| |
| public String substituteVariables(HiveConf conf, String line) { |
| if (!beeLine.isBeeLine()) { |
| // Substitution is only supported in non-beeline mode. |
| return new VariableSubstitution(new HiveVariableSource() { |
| @Override |
| public Map<String, String> getHiveVariable() { |
| return getHiveVariables(); |
| } |
| }).substitute(conf, line); |
| } |
| return line; |
| } |
| |
| public boolean sh(String line) { |
| if (line == null || line.length() == 0) { |
| return false; |
| } |
| |
| if (!line.startsWith("sh")) { |
| return false; |
| } |
| |
| line = line.substring("sh".length()).trim(); |
| if (!beeLine.isBeeLine()) |
| line = substituteVariables(getHiveConf(false), line.trim()); |
| |
| try { |
| ShellCmdExecutor executor = new ShellCmdExecutor(line, beeLine.getOutputStream(), |
| beeLine.getErrorStream()); |
| int ret = executor.execute(); |
| if (ret != 0) { |
| beeLine.output("Command failed with exit code = " + ret); |
| return false; |
| } |
| return true; |
| } catch (Exception e) { |
| beeLine.error("Exception raised from Shell command " + e); |
| return false; |
| } |
| } |
| |
| public boolean call(String line) { |
| return execute(line, true, false); |
| } |
| |
| private boolean execute(String line, boolean call, boolean entireLineAsCommand) { |
| if (line == null || line.length() == 0) { |
| return false; // ??? |
| } |
| |
| // ### FIXME: doing the multi-line handling down here means |
| // higher-level logic never sees the extra lines. So, |
| // for example, if a script is being saved, it won't include |
| // the continuation lines! This is logged as sf.net |
| // bug 879518. |
| |
| // use multiple lines for statements not terminated by the delimiter |
| try { |
| line = handleMultiLineCmd(line); |
| } catch (Exception e) { |
| beeLine.handleException(e); |
| } |
| |
| line = line.trim(); |
| List<String> cmdList = getCmdList(line, entireLineAsCommand); |
| for (int i = 0; i < cmdList.size(); i++) { |
| String sql = cmdList.get(i).trim(); |
| if (sql.length() != 0) { |
| if (!executeInternal(sql, call)) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| private enum SectionType { |
| SINGLE_QUOTED, DOUBLE_QUOTED, LINE_COMMENT, BLOCK_COMMENT |
| } |
| |
| /** |
| * 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 delimiters that are placed within |
| * quotations. It iterates through each character in the line and checks to see if it is the delimiter, ', |
| * or " |
| */ |
| List<String> getCmdList(String line, boolean entireLineAsCommand) { |
| if (entireLineAsCommand) { |
| return Stream.of(line).collect(Collectors.toList()); |
| } |
| List<String> cmdList = new ArrayList<String>(); |
| StringBuilder command = new StringBuilder(); |
| |
| // Marker to track if there is a special section open |
| SectionType sectionType = null; |
| |
| // Index of the last seen delimiter in the given line |
| int lastDelimiterIndex = 0; |
| |
| // 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 the delimiter is seen that is not inside a |
| // quoted string |
| for (; index < line.length();) { |
| if (!wasPrevEscape && sectionType == null && line.startsWith("'", index)) { |
| // Opening non-escaped single quote |
| sectionType = SectionType.SINGLE_QUOTED; |
| index++; |
| } else if (!wasPrevEscape && sectionType == SectionType.SINGLE_QUOTED && line.startsWith("'", index)) { |
| // Closing non-escaped single quote |
| sectionType = null; |
| index++; |
| } else if (!wasPrevEscape && sectionType == null && line.startsWith("\"", index)) { |
| // Opening non-escaped double quote |
| sectionType = SectionType.DOUBLE_QUOTED; |
| index++; |
| } else if (!wasPrevEscape && sectionType == SectionType.DOUBLE_QUOTED && line.startsWith("\"", index)) { |
| // Closing non-escaped double quote |
| sectionType = null; |
| index++; |
| } else if (sectionType == null && line.startsWith("--", index)) { |
| // Opening line comment with (non-escapable?) double-dash |
| sectionType = SectionType.LINE_COMMENT; |
| wasPrevEscape = false; |
| index += 2; |
| } else if (sectionType == SectionType.LINE_COMMENT && line.startsWith("\n", index)) { |
| // Closing line comment with (non-escapable?) newline |
| sectionType = null; |
| wasPrevEscape = false; |
| index++; |
| } else if (sectionType == null && line.startsWith("/*", index)) { |
| // Opening block comment with (non-escapable?) /* |
| sectionType = SectionType.BLOCK_COMMENT; |
| wasPrevEscape = false; |
| index += 2; |
| } else if (sectionType == SectionType.BLOCK_COMMENT && line.startsWith("*/", index)) { |
| // Closing line comment with (non-escapable?) newline |
| sectionType = null; |
| wasPrevEscape = false; |
| index += 2; |
| } else if (line.startsWith("\\", index)) { |
| // Escape character seen (anywhere) |
| wasPrevEscape = !wasPrevEscape; |
| index++; |
| } else if (sectionType == null && line.startsWith(beeLine.getOpts().getDelimiter(), index)) { |
| // If the delimiter is seen, and the line isn't inside a section, then treat |
| // line[lastDelimiterIndex] to line[index] as a single command |
| addCmdPart(cmdList, command, line.substring(lastDelimiterIndex, index)); |
| index += beeLine.getOpts().getDelimiter().length(); |
| lastDelimiterIndex = index; |
| wasPrevEscape = false; |
| } else { |
| wasPrevEscape = false; |
| index++; |
| } |
| } |
| // If the line doesn't end with the delimiter or if the line is empty, add the cmd part |
| if (lastDelimiterIndex != index || line.length() == 0) { |
| addCmdPart(cmdList, command, line.substring(lastDelimiterIndex, 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, StringBuilder command, String cmdpart) { |
| if (cmdpart.endsWith("\\")) { |
| command.append(cmdpart.substring(0, cmdpart.length() - 1)).append(beeLine.getOpts().getDelimiter()); |
| return; |
| } else { |
| command.append(cmdpart); |
| } |
| cmdList.add(command.toString()); |
| command.setLength(0); |
| } |
| |
| private Runnable createLogRunnable(final Statement statement, |
| InPlaceUpdateStream.EventNotifier eventNotifier) { |
| if (statement instanceof HiveStatement) { |
| return new LogRunnable(this, (HiveStatement) statement, DEFAULT_QUERY_PROGRESS_INTERVAL, |
| eventNotifier); |
| } else { |
| beeLine.debug( |
| "The statement instance is not HiveStatement type: " + statement |
| .getClass()); |
| return new Runnable() { |
| @Override |
| public void run() { |
| // do nothing. |
| } |
| }; |
| } |
| } |
| |
| private void error(Throwable throwable) { |
| beeLine.error(throwable); |
| } |
| |
| private void debug(String message) { |
| beeLine.debug(message); |
| } |
| |
| static class LogRunnable implements Runnable { |
| private final Commands commands; |
| private final HiveStatement hiveStatement; |
| private final long queryProgressInterval; |
| private final InPlaceUpdateStream.EventNotifier notifier; |
| |
| LogRunnable(Commands commands, HiveStatement hiveStatement, |
| long queryProgressInterval, InPlaceUpdateStream.EventNotifier eventNotifier) { |
| this.hiveStatement = hiveStatement; |
| this.commands = commands; |
| this.queryProgressInterval = queryProgressInterval; |
| this.notifier = eventNotifier; |
| } |
| |
| private void updateQueryLog() { |
| try { |
| List<String> queryLogs = hiveStatement.getQueryLog(); |
| for (String log : queryLogs) { |
| if (!commands.beeLine.isTestMode()) { |
| commands.beeLine.info(log); |
| } else { |
| // In test mode print the logs to the output |
| commands.beeLine.output(log); |
| } |
| } |
| if (!queryLogs.isEmpty()) { |
| notifier.operationLogShowedToUser(); |
| } |
| } catch (SQLException e) { |
| commands.error(new SQLWarning(e)); |
| } |
| } |
| |
| @Override public void run() { |
| try { |
| while (hiveStatement.hasMoreLogs()) { |
| /* |
| get the operation logs once and print it, then wait till progress bar update is complete |
| before printing the remaining logs. |
| */ |
| if (notifier.canOutputOperationLogs()) { |
| commands.debug("going to print operations logs"); |
| updateQueryLog(); |
| commands.debug("printed operations logs"); |
| } |
| Thread.sleep(queryProgressInterval); |
| } |
| } catch (InterruptedException e) { |
| commands.debug("Getting log thread is interrupted, since query is done!"); |
| } finally { |
| commands.showRemainingLogsIfAny(hiveStatement); |
| } |
| } |
| } |
| |
| private void showRemainingLogsIfAny(Statement statement) { |
| if (statement instanceof HiveStatement) { |
| HiveStatement hiveStatement = (HiveStatement) statement; |
| List<String> logs = null; |
| do { |
| try { |
| logs = hiveStatement.getQueryLog(); |
| } catch (SQLException e) { |
| beeLine.error(new SQLWarning(e)); |
| return; |
| } |
| for (String log : logs) { |
| if (!beeLine.isTestMode()) { |
| beeLine.info(log); |
| } else { |
| // In test mode print the logs to the output |
| beeLine.output(log); |
| } |
| } |
| } while (logs.size() > 0); |
| } else { |
| beeLine.debug("The statement instance is not HiveStatement type: " + statement.getClass()); |
| } |
| } |
| |
| public boolean quit(String line) { |
| beeLine.setExit(true); |
| close(null); |
| return true; |
| } |
| |
| public boolean exit(String line) { |
| return quit(line); |
| } |
| |
| /** |
| * Close all connections. |
| */ |
| public boolean closeall(String line) { |
| if (close(null)) { |
| while (close(null)) { |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Close the current connection. |
| */ |
| public boolean close(String line) { |
| if (beeLine.getDatabaseConnection() == null) { |
| return false; |
| } |
| try { |
| if (beeLine.getDatabaseConnection().getCurrentConnection() != null |
| && !(beeLine.getDatabaseConnection().getCurrentConnection().isClosed())) { |
| int index = beeLine.getDatabaseConnections().getIndex(); |
| beeLine.info(beeLine.loc("closing", index, beeLine.getDatabaseConnection())); |
| beeLine.getDatabaseConnection().getCurrentConnection().close(); |
| } else { |
| beeLine.info(beeLine.loc("already-closed")); |
| } |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| beeLine.getDatabaseConnections().remove(); |
| return true; |
| } |
| |
| |
| /** |
| * Connect to the database defined in the specified properties file. |
| */ |
| public boolean properties(String line) throws Exception { |
| String example = ""; |
| example += "Usage: properties <properties file>" + BeeLine.getSeparator(); |
| |
| String[] parts = beeLine.split(line); |
| if (parts.length < 2) { |
| return beeLine.error(example); |
| } |
| |
| int successes = 0; |
| |
| for (int i = 1; i < parts.length; i++) { |
| Properties props = new Properties(); |
| InputStream stream = new FileInputStream(parts[i]); |
| try { |
| props.load(stream); |
| } finally { |
| IOUtils.closeStream(stream); |
| } |
| if (connect(props)) { |
| successes++; |
| } |
| } |
| |
| if (successes != (parts.length - 1)) { |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| |
| public boolean connect(String line) throws Exception { |
| String example = "Usage: connect <url> <username> <password> [driver]" |
| + BeeLine.getSeparator(); |
| |
| String[] parts = beeLine.split(line); |
| if (parts == null) { |
| return false; |
| } |
| |
| if (parts.length < 2) { |
| return beeLine.error(example); |
| } |
| |
| String url = parts.length < 2 ? null : parts[1]; |
| String user = parts.length < 3 ? null : parts[2]; |
| String pass = parts.length < 4 ? null : parts[3]; |
| String driver = parts.length < 5 ? null : parts[4]; |
| |
| Properties props = new Properties(); |
| if (url != null) { |
| String saveUrl = getUrlToUse(url); |
| props.setProperty(JdbcConnectionParams.PROPERTY_URL, saveUrl); |
| } |
| |
| String value = null; |
| if (driver != null) { |
| props.setProperty(JdbcConnectionParams.PROPERTY_DRIVER, driver); |
| } else { |
| value = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.PROPERTY_DRIVER); |
| if (value != null) { |
| props.setProperty(JdbcConnectionParams.PROPERTY_DRIVER, value); |
| } |
| } |
| |
| if (user != null) { |
| props.setProperty(JdbcConnectionParams.AUTH_USER, user); |
| } else { |
| value = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_USER); |
| if (value != null) { |
| props.setProperty(JdbcConnectionParams.AUTH_USER, value); |
| } |
| } |
| |
| if (pass != null) { |
| props.setProperty(JdbcConnectionParams.AUTH_PASSWD, pass); |
| } else { |
| value = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_PASSWD); |
| if (value != null) { |
| props.setProperty(JdbcConnectionParams.AUTH_PASSWD, value); |
| } |
| } |
| |
| value = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_TYPE); |
| if (value != null) { |
| props.setProperty(JdbcConnectionParams.AUTH_TYPE, value); |
| } |
| return connect(props); |
| } |
| |
| private String getUrlToUse(String urlParam) { |
| boolean useIndirectUrl = false; |
| // If the url passed to us is a valid url with a protocol, we use it as-is |
| // Otherwise, we assume it is a name of parameter that we have to get the url from |
| try { |
| URI tryParse = new URI(urlParam); |
| if (tryParse.getScheme() == null){ |
| // param had no scheme, so not a URL |
| useIndirectUrl = true; |
| } |
| } catch (URISyntaxException e){ |
| // param did not parse as a URL, so not a URL |
| useIndirectUrl = true; |
| } |
| if (useIndirectUrl){ |
| // Use url param indirectly - as the name of an env var that contains the url |
| // If the urlParam is "default", we would look for a BEELINE_URL_DEFAULT url |
| String envUrl = beeLine.getOpts().getEnv().get( |
| BeeLineOpts.URL_ENV_PREFIX + urlParam.toUpperCase()); |
| if (envUrl != null){ |
| return envUrl; |
| } |
| } |
| return urlParam; // default return the urlParam passed in as-is. |
| } |
| |
| private String getProperty(Properties props, String[] keys) { |
| for (int i = 0; i < keys.length; i++) { |
| String val = props.getProperty(keys[i]); |
| if (val != null) { |
| return val; |
| } |
| } |
| |
| for (Iterator i = props.keySet().iterator(); i.hasNext();) { |
| String key = (String) i.next(); |
| for (int j = 0; j < keys.length; j++) { |
| if (key.endsWith(keys[j])) { |
| return props.getProperty(key); |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| public boolean connect(Properties props) throws IOException { |
| String url = getProperty(props, new String[] { |
| JdbcConnectionParams.PROPERTY_URL, |
| "javax.jdo.option.ConnectionURL", |
| "ConnectionURL", |
| }); |
| String driver = getProperty(props, new String[] { |
| JdbcConnectionParams.PROPERTY_DRIVER, |
| "javax.jdo.option.ConnectionDriverName", |
| "ConnectionDriverName", |
| }); |
| String username = getProperty(props, new String[] { |
| JdbcConnectionParams.AUTH_USER, |
| "javax.jdo.option.ConnectionUserName", |
| "ConnectionUserName", |
| }); |
| String password = getProperty(props, new String[] { |
| JdbcConnectionParams.AUTH_PASSWD, |
| "javax.jdo.option.ConnectionPassword", |
| "ConnectionPassword", |
| }); |
| |
| if (url == null || url.length() == 0) { |
| return beeLine.error("Property \"url\" is required"); |
| } |
| if (driver == null || driver.length() == 0) { |
| if (!beeLine.scanForDriver(url)) { |
| return beeLine.error(beeLine.loc("no-driver", url)); |
| } |
| } |
| |
| String auth = getProperty(props, new String[] {JdbcConnectionParams.AUTH_TYPE}); |
| if (auth == null) { |
| auth = beeLine.getOpts().getAuthType(); |
| if (auth != null) { |
| props.setProperty(JdbcConnectionParams.AUTH_TYPE, auth); |
| } |
| } |
| |
| beeLine.info("Connecting to " + url); |
| if (Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_PRINCIPAL) == null |
| && !JdbcConnectionParams.AUTH_SSO_BROWSER_MODE.equals(auth)) { |
| String urlForPrompt = url.substring(0, url.contains(";") ? url.indexOf(';') : url.length()); |
| if (username == null) { |
| username = beeLine.getConsoleReader().readLine("Enter username for " + urlForPrompt + ": "); |
| } |
| props.setProperty(JdbcConnectionParams.AUTH_USER, username); |
| if (password == null) { |
| password = beeLine.getConsoleReader().readLine("Enter password for " + urlForPrompt + ": ", |
| new Character('*')); |
| } |
| props.setProperty(JdbcConnectionParams.AUTH_PASSWD, password); |
| } |
| |
| try { |
| beeLine.getDatabaseConnections().setConnection( |
| new DatabaseConnection(beeLine, driver, url, props)); |
| beeLine.getDatabaseConnection().getConnection(); |
| |
| if (!beeLine.isBeeLine()) { |
| beeLine.updateOptsForCli(); |
| } |
| |
| int initScriptExecutionResult = beeLine.runInit(); |
| |
| //if execution of the init script(s) return anything other than ERRNO_OK from beeline |
| //exit beeline with error unless --force is set |
| if(initScriptExecutionResult != 0 && !beeLine.getOpts().getForce()) { |
| return beeLine.error("init script execution failed."); |
| } |
| |
| beeLine.setCompletions(); |
| beeLine.getOpts().setLastConnectedUrl(url); |
| return true; |
| } catch (SQLException sqle) { |
| beeLine.getDatabaseConnections().remove(); |
| return beeLine.error(sqle); |
| } catch (IOException ioe) { |
| return beeLine.error(ioe); |
| } |
| } |
| |
| public boolean rehash(String line) { |
| try { |
| if (!(beeLine.assertConnection())) { |
| return false; |
| } |
| if (beeLine.getDatabaseConnection() != null) { |
| beeLine.getDatabaseConnection().setCompletions(false); |
| } |
| return true; |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| } |
| |
| |
| /** |
| * List the current connections |
| */ |
| public boolean list(String line) { |
| int index = 0; |
| beeLine.info(beeLine.loc("active-connections", beeLine.getDatabaseConnections().size())); |
| |
| for (Iterator<DatabaseConnection> i = beeLine.getDatabaseConnections().iterator(); i.hasNext(); index++) { |
| DatabaseConnection c = i.next(); |
| boolean closed = false; |
| try { |
| closed = c.getConnection().isClosed(); |
| } catch (Exception e) { |
| closed = true; |
| } |
| |
| beeLine.output(beeLine.getColorBuffer().pad(" #" + index + "", 5) |
| .pad(closed ? beeLine.loc("closed") : beeLine.loc("open"), 9) |
| .append(c.getUrl())); |
| } |
| |
| return true; |
| } |
| |
| public boolean all(String line) { |
| int index = beeLine.getDatabaseConnections().getIndex(); |
| boolean success = true; |
| |
| for (int i = 0; i < beeLine.getDatabaseConnections().size(); i++) { |
| beeLine.getDatabaseConnections().setIndex(i); |
| beeLine.output(beeLine.loc("executing-con", beeLine.getDatabaseConnection())); |
| // ### FIXME: this is broken for multi-line SQL |
| success = sql(line.substring("all ".length())) && success; |
| } |
| |
| // restore index |
| beeLine.getDatabaseConnections().setIndex(index); |
| return success; |
| } |
| |
| |
| public boolean go(String line) { |
| String[] parts = beeLine.split(line, 2, "Usage: go <connection index>"); |
| if (parts == null) { |
| return false; |
| } |
| int index = Integer.parseInt(parts[1]); |
| if (!(beeLine.getDatabaseConnections().setIndex(index))) { |
| beeLine.error(beeLine.loc("invalid-connection", "" + index)); |
| list(""); // list the current connections |
| return false; |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Save or stop saving a script to a file |
| */ |
| public boolean script(String line) { |
| if (beeLine.getScriptOutputFile() == null) { |
| return startScript(line); |
| } else { |
| return stopScript(line); |
| } |
| } |
| |
| |
| /** |
| * Stop writing to the script file and close the script. |
| */ |
| private boolean stopScript(String line) { |
| try { |
| beeLine.getScriptOutputFile().close(); |
| } catch (Exception e) |
| { |
| beeLine.handleException(e); |
| } |
| |
| beeLine.output(beeLine.loc("script-closed", beeLine.getScriptOutputFile())); |
| beeLine.setScriptOutputFile(null); |
| return true; |
| } |
| |
| |
| /** |
| * Start writing to the specified script file. |
| */ |
| private boolean startScript(String line) { |
| if (beeLine.getScriptOutputFile() != null) { |
| return beeLine.error(beeLine.loc("script-already-running", beeLine.getScriptOutputFile())); |
| } |
| |
| String[] parts = beeLine.split(line, 2, "Usage: script <filename>"); |
| if (parts == null) { |
| return false; |
| } |
| |
| try { |
| beeLine.setScriptOutputFile(new OutputFile(parts[1])); |
| beeLine.output(beeLine.loc("script-started", beeLine.getScriptOutputFile())); |
| return true; |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| } |
| |
| |
| /** |
| * Run a script from the specified file. |
| */ |
| public boolean run(String line) { |
| String[] parts = beeLine.split(line, 2, "Usage: run <scriptfile>"); |
| if (parts == null) { |
| return false; |
| } |
| |
| try { |
| String[] cmds = beeLine.getCommands(new File(parts[1])); |
| // success only if all the commands were successful |
| return beeLine.runCommands(cmds) == cmds.length; |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| } |
| |
| |
| /** |
| * Save or stop saving all output to a file. |
| */ |
| public boolean record(String line) { |
| if (beeLine.getRecordOutputFile() == null) { |
| return startRecording(line); |
| } else { |
| return stopRecording(line); |
| } |
| } |
| |
| |
| /** |
| * Stop writing output to the record file. |
| */ |
| private boolean stopRecording(String line) { |
| try { |
| beeLine.getRecordOutputFile().close(); |
| } catch (Exception e) { |
| beeLine.handleException(e); |
| } |
| beeLine.setRecordOutputFile(null); |
| beeLine.output(beeLine.loc("record-closed", beeLine.getRecordOutputFile())); |
| return true; |
| } |
| |
| |
| /** |
| * Start writing to the specified record file. |
| */ |
| private boolean startRecording(String line) { |
| if (beeLine.getRecordOutputFile() != null) { |
| return beeLine.error(beeLine.loc("record-already-running", beeLine.getRecordOutputFile())); |
| } |
| |
| String[] parts = beeLine.split(line, 2, "Usage: record <filename>"); |
| if (parts == null) { |
| return false; |
| } |
| |
| try { |
| OutputFile recordOutput = new OutputFile(parts[1]); |
| beeLine.output(beeLine.loc("record-started", recordOutput)); |
| beeLine.setRecordOutputFile(recordOutput); |
| return true; |
| } catch (Exception e) { |
| return beeLine.error(e); |
| } |
| } |
| |
| |
| |
| |
| public boolean describe(String line) throws SQLException { |
| String[] table = beeLine.split(line, 2, "Usage: describe <table name>"); |
| if (table == null) { |
| return false; |
| } |
| |
| ResultSet rs; |
| |
| if (table[1].equals("tables")) { |
| rs = beeLine.getTables(); |
| } else { |
| rs = beeLine.getColumns(table[1]); |
| } |
| |
| if (rs == null) { |
| return false; |
| } |
| |
| beeLine.print(rs); |
| rs.close(); |
| return true; |
| } |
| |
| |
| public boolean help(String line) { |
| String[] parts = beeLine.split(line); |
| String cmd = parts.length > 1 ? parts[1] : ""; |
| int count = 0; |
| TreeSet<ColorBuffer> clist = new TreeSet<ColorBuffer>(); |
| |
| for (int i = 0; i < beeLine.commandHandlers.length; i++) { |
| if (cmd.length() == 0 || |
| Arrays.asList(beeLine.commandHandlers[i].getNames()).contains(cmd)) { |
| clist.add(beeLine.getColorBuffer().pad("!" + beeLine.commandHandlers[i].getName(), 20) |
| .append(beeLine.wrap(beeLine.commandHandlers[i].getHelpText(), 60, 20))); |
| } |
| } |
| |
| for (Iterator<ColorBuffer> i = clist.iterator(); i.hasNext();) { |
| beeLine.output(i.next()); |
| } |
| |
| if (cmd.length() == 0) { |
| beeLine.output(""); |
| beeLine.output(beeLine.loc("comments", beeLine.getApplicationContactInformation())); |
| } |
| |
| return true; |
| } |
| |
| |
| public boolean manual(String line) throws IOException { |
| InputStream in = BeeLine.class.getResourceAsStream("manual.txt"); |
| if (in == null) { |
| return beeLine.error(beeLine.loc("no-manual")); |
| } |
| |
| BufferedReader breader = new BufferedReader( |
| new InputStreamReader(in)); |
| String man; |
| int index = 0; |
| while ((man = breader.readLine()) != null) { |
| index++; |
| beeLine.output(man); |
| |
| // silly little pager |
| if (index % (beeLine.getOpts().getMaxHeight() - 1) == 0) { |
| String ret = beeLine.getConsoleReader().readLine(beeLine.loc("enter-for-more")); |
| if (ret != null && ret.startsWith("q")) { |
| break; |
| } |
| } |
| } |
| breader.close(); |
| return true; |
| } |
| |
| public boolean delimiter(String line) { |
| return set("set " + line); |
| } |
| } |