| /* |
| * 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.ByteArrayInputStream; |
| import java.io.Closeable; |
| import java.io.EOFException; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.PrintStream; |
| import java.io.SequenceInputStream; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.net.JarURLConnection; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.sql.Connection; |
| import java.sql.DatabaseMetaData; |
| import java.sql.Driver; |
| import java.sql.DriverManager; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.SQLWarning; |
| import java.sql.Statement; |
| import java.text.ChoiceFormat; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Objects; |
| import java.util.Properties; |
| import java.util.ResourceBundle; |
| import java.util.ServiceLoader; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.StringTokenizer; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| import java.util.concurrent.TimeUnit; |
| import java.util.jar.Attributes; |
| import java.util.jar.Manifest; |
| import java.util.stream.Collectors; |
| import java.util.stream.StreamSupport; |
| |
| import org.apache.commons.cli.CommandLine; |
| import org.apache.commons.cli.GnuParser; |
| import org.apache.commons.cli.OptionBuilder; |
| import org.apache.commons.cli.Options; |
| import org.apache.commons.cli.ParseException; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.FSDataInputStream; |
| import org.apache.hadoop.fs.FileSystem; |
| import org.apache.hadoop.hive.conf.Constants; |
| import org.apache.hadoop.hive.conf.HiveConf; |
| import org.apache.hadoop.io.IOUtils; |
| import org.apache.hive.beeline.cli.CliOptionsProcessor; |
| import org.apache.hive.beeline.hs2connection.BeelineConfFileParseException; |
| import org.apache.hive.beeline.hs2connection.BeelineSiteParseException; |
| import org.apache.hive.beeline.hs2connection.BeelineSiteParser; |
| import org.apache.hive.beeline.hs2connection.HS2ConnectionFileParser; |
| import org.apache.hive.beeline.hs2connection.HS2ConnectionFileUtils; |
| import org.apache.hive.beeline.hs2connection.HiveSiteHS2ConnectionFileParser; |
| import org.apache.hive.beeline.hs2connection.UserHS2ConnectionFileParser; |
| import org.apache.hive.common.util.ShutdownHookManager; |
| import org.apache.hive.common.util.HiveStringUtils; |
| import org.apache.hive.jdbc.HiveConnection; |
| import org.apache.hive.jdbc.JdbcUriParseException; |
| import org.apache.hive.jdbc.Utils; |
| import org.apache.hive.jdbc.Utils.JdbcConnectionParams; |
| import org.apache.thrift.transport.TTransportException; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| |
| import jline.console.ConsoleReader; |
| import jline.console.completer.Completer; |
| import jline.console.completer.FileNameCompleter; |
| import jline.console.completer.StringsCompleter; |
| import jline.console.history.FileHistory; |
| |
| /** |
| * A console SQL shell with command completion. |
| * <p> |
| * TODO: |
| * <ul> |
| * <li>User-friendly connection prompts</li> |
| * <li>Page results</li> |
| * <li>Handle binary data (blob fields)</li> |
| * <li>Implement command aliases</li> |
| * <li>Stored procedure execution</li> |
| * <li>Binding parameters to prepared statements</li> |
| * <li>Scripting language</li> |
| * <li>XA transactions</li> |
| * </ul> |
| * |
| */ |
| @SuppressWarnings("static-access") |
| public class BeeLine implements Closeable { |
| private static final ResourceBundle resourceBundle = |
| ResourceBundle.getBundle(BeeLine.class.getSimpleName()); |
| private final BeeLineSignalHandler signalHandler; |
| private final Runnable shutdownHook; |
| private static final String separator = System.getProperty("line.separator"); |
| private boolean exit = false; |
| private final DatabaseConnections connections = new DatabaseConnections(); |
| public static final String COMMAND_PREFIX = "!"; |
| private Collection<Driver> drivers = null; |
| private final BeeLineOpts opts = new BeeLineOpts(this, System.getProperties()); |
| private String lastProgress = null; |
| private final Map<SQLWarning, Date> seenWarnings = new HashMap<SQLWarning, Date>(); |
| private final Commands commands = new Commands(this); |
| private OutputFile scriptOutputFile = null; |
| private OutputFile recordOutputFile = null; |
| private PrintStream outputStream = new PrintStream(System.out, true); |
| private PrintStream errorStream = new PrintStream(System.err, true); |
| private InputStream inputStream = System.in; |
| private ConsoleReader consoleReader; |
| private List<String> batch = null; |
| private final Reflector reflector = new Reflector(this); |
| private String dbName = null; |
| private String currentDatabase = null; |
| |
| private FileHistory history; |
| // Indicates if this instance of beeline is running in compatibility mode, or beeline mode |
| private boolean isBeeLine = true; |
| |
| // Indicates that we are in test mode. |
| // Print only the errors, the operation log and the query results. |
| private boolean isTestMode = false; |
| |
| private static final Options options = new Options(); |
| |
| public static final String BEELINE_DEFAULT_JDBC_DRIVER = "org.apache.hive.jdbc.HiveDriver"; |
| public static final String DEFAULT_DATABASE_NAME = "default"; |
| |
| private static final String SCRIPT_OUTPUT_PREFIX = ">>>"; |
| private static final int SCRIPT_OUTPUT_PAD_SIZE = 5; |
| |
| private static final int ERRNO_OK = 0; |
| private static final int ERRNO_ARGS = 1; |
| private static final int ERRNO_OTHER = 2; |
| |
| private static final String HIVE_VAR_PREFIX = "--hivevar"; |
| private static final String HIVE_CONF_PREFIX = "--hiveconf"; |
| private static final String PROP_FILE_PREFIX = "--property-file"; |
| public static final String PASSWD_MASK = "[passwd stripped]"; |
| |
| private final Map<Object, Object> formats = map(new Object[] { |
| "vertical", new VerticalOutputFormat(this), |
| "table", new TableOutputFormat(this), |
| "csv2", new SeparatedValuesOutputFormat(this, ','), |
| "tsv2", new SeparatedValuesOutputFormat(this, '\t'), |
| "dsv", new SeparatedValuesOutputFormat(this, BeeLineOpts.DEFAULT_DELIMITER_FOR_DSV), |
| "csv", new DeprecatedSeparatedValuesOutputFormat(this, ','), |
| "tsv", new DeprecatedSeparatedValuesOutputFormat(this, '\t'), |
| "xmlattr", new XMLAttributeOutputFormat(this), |
| "xmlelements", new XMLElementOutputFormat(this), |
| "json", new JSONOutputFormat(this), |
| "jsonfile", new JSONFileOutputFormat(this), |
| }); |
| |
| private List<String> supportedLocalDriver = |
| new ArrayList<String>(Arrays.asList("com.mysql.jdbc.Driver", "org.postgresql.Driver")); |
| |
| final CommandHandler[] commandHandlers = new CommandHandler[] { |
| new ReflectiveCommandHandler(this, new String[] {"quit", "done", "exit"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"connect", "open"}, |
| new Completer[] {new StringsCompleter(getConnectionURLExamples())}), |
| new ReflectiveCommandHandler(this, new String[] {"describe"}, |
| new Completer[] {new TableNameCompletor(this)}), |
| new ReflectiveCommandHandler(this, new String[] {"indexes"}, |
| new Completer[] {new TableNameCompletor(this)}), |
| new ReflectiveCommandHandler(this, new String[] {"primarykeys"}, |
| new Completer[] {new TableNameCompletor(this)}), |
| new ReflectiveCommandHandler(this, new String[] {"exportedkeys"}, |
| new Completer[] {new TableNameCompletor(this)}), |
| new ReflectiveCommandHandler(this, new String[] {"manual"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"importedkeys"}, |
| new Completer[] {new TableNameCompletor(this)}), |
| new ReflectiveCommandHandler(this, new String[] {"procedures"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"tables"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"typeinfo"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"columns"}, |
| new Completer[] {new TableNameCompletor(this)}), |
| new ReflectiveCommandHandler(this, new String[] {"reconnect"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"dropall"}, |
| new Completer[] {new TableNameCompletor(this)}), |
| new ReflectiveCommandHandler(this, new String[] {"history"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"metadata"}, |
| new Completer[] { |
| new StringsCompleter(getMetadataMethodNames())}), |
| new ReflectiveCommandHandler(this, new String[] {"nativesql"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"dbinfo"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"rehash"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"verbose"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"run"}, |
| new Completer[] {new FileNameCompleter()}), |
| new ReflectiveCommandHandler(this, new String[] {"batch"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"list"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"all"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"go", "#"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"script"}, |
| new Completer[] {new FileNameCompleter()}), |
| new ReflectiveCommandHandler(this, new String[] {"record"}, |
| new Completer[] {new FileNameCompleter()}), |
| new ReflectiveCommandHandler(this, new String[] {"brief"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"close"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"closeall"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"isolation"}, |
| new Completer[] {new StringsCompleter(getIsolationLevels())}), |
| new ReflectiveCommandHandler(this, new String[] {"outputformat"}, |
| new Completer[] {new StringsCompleter( |
| formats.keySet().toArray(new String[0]))}), |
| new ReflectiveCommandHandler(this, new String[] {"autocommit"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"commit"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"properties"}, |
| new Completer[] {new FileNameCompleter()}), |
| new ReflectiveCommandHandler(this, new String[] {"rollback"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"help", "?"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"set"}, |
| getOpts().optionCompleters()), |
| new ReflectiveCommandHandler(this, new String[] {"save"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"scan"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"sql"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"sh"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"call"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[] {"nullemptystring"}, |
| new Completer[] {new BooleanCompleter()}), |
| new ReflectiveCommandHandler(this, new String[]{"addlocaldriverjar"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[]{"addlocaldrivername"}, |
| null), |
| new ReflectiveCommandHandler(this, new String[]{"delimiter"}, |
| null) |
| }; |
| |
| private final Completer beeLineCommandCompleter = new BeeLineCommandCompleter(Arrays.asList(commandHandlers)); |
| |
| static final SortedSet<String> KNOWN_DRIVERS = new TreeSet<String>(Arrays.asList( |
| new String[] { |
| "org.apache.hive.jdbc.HiveDriver", |
| "org.apache.hadoop.hive.jdbc.HiveDriver", |
| })); |
| |
| static { |
| try { |
| Class.forName("jline.console.ConsoleReader"); |
| } catch (Throwable t) { |
| throw new ExceptionInInitializerError("jline-missing"); |
| } |
| } |
| |
| static { |
| // -d <driver class> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withArgName("driver class") |
| .withDescription("The driver class to use") |
| .create('d')); |
| |
| // -u <database url> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withArgName("database url") |
| .withDescription("The JDBC URL to connect to") |
| .create('u')); |
| |
| // -c <named url in the beeline-hs2-connection.xml> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withArgName("named JDBC URL in beeline-site.xml") |
| .withDescription("The named JDBC URL to connect to, which should be present in " |
| + "beeline-site.xml as the value of beeline.hs2.jdbc.url.<namedUrl>") |
| .create('c')); |
| |
| // -r |
| options.addOption(OptionBuilder |
| .withLongOpt("reconnect") |
| .withDescription("Reconnect to last saved connect url (in conjunction with !save)") |
| .create('r')); |
| |
| // -n <username> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withArgName("username") |
| .withDescription("The username to connect as") |
| .create('n')); |
| |
| // -p <password> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withArgName("password") |
| .withDescription("The password to connect as") |
| .hasOptionalArg() |
| .create('p')); |
| |
| // -w (or) --password-file <file> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withArgName("password-file") |
| .withDescription("The password file to read password from") |
| .withLongOpt("password-file") |
| .create('w')); |
| |
| // -a <authType> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withArgName("authType") |
| .withDescription("The authentication type") |
| .create('a')); |
| |
| // -i <init file> |
| options.addOption(OptionBuilder |
| .hasArgs() |
| .withArgName("init") |
| .withDescription("The script file for initialization") |
| .create('i')); |
| |
| // -e <query> |
| options.addOption(OptionBuilder |
| .hasArgs() |
| .withArgName("query") |
| .withDescription("The query that should be executed") |
| .create('e')); |
| |
| // -f <script file> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withArgName("file") |
| .withDescription("The script file that should be executed") |
| .create('f')); |
| |
| // -help |
| options.addOption(OptionBuilder |
| .withLongOpt("help") |
| .withDescription("Display this message") |
| .create('h')); |
| |
| // -getUrlsFromBeelineSite |
| options.addOption(OptionBuilder |
| .withLongOpt("getUrlsFromBeelineSite") |
| .withDescription("Print all urls from beeline-site.xml, if it is present in the classpath") |
| .create()); |
| |
| // Substitution option --hivevar |
| options.addOption(OptionBuilder |
| .withValueSeparator() |
| .hasArgs(2) |
| .withArgName("key=value") |
| .withLongOpt("hivevar") |
| .withDescription("Hive variable name and value") |
| .create()); |
| |
| //hive conf option --hiveconf |
| options.addOption(OptionBuilder |
| .withValueSeparator() |
| .hasArgs(2) |
| .withArgName("property=value") |
| .withLongOpt("hiveconf") |
| .withDescription("Use value for given property") |
| .create()); |
| |
| // --property-file <file> |
| options.addOption(OptionBuilder |
| .hasArg() |
| .withLongOpt("property-file") |
| .withDescription("The file to read configuration properties from") |
| .create()); |
| } |
| |
| |
| static Manifest getManifest() throws IOException { |
| URL base = BeeLine.class.getResource("/META-INF/MANIFEST.MF"); |
| URLConnection c = base.openConnection(); |
| if (c instanceof JarURLConnection) { |
| return ((JarURLConnection) c).getManifest(); |
| } |
| return null; |
| } |
| |
| |
| String getManifestAttribute(String name) { |
| try { |
| Manifest m = getManifest(); |
| if (m == null) { |
| return "??"; |
| } |
| |
| Attributes attrs = m.getAttributes("beeline"); |
| if (attrs == null) { |
| return "???"; |
| } |
| |
| String val = attrs.getValue(name); |
| if (val == null || "".equals(val)) { |
| return "????"; |
| } |
| |
| return val; |
| } catch (Exception e) { |
| e.printStackTrace(errorStream); |
| return "?????"; |
| } |
| } |
| |
| |
| String getApplicationTitle() { |
| Package pack = BeeLine.class.getPackage(); |
| |
| return loc("app-introduction", new Object[] { "Beeline", |
| pack.getImplementationVersion() == null ? "???" : pack.getImplementationVersion(), |
| "Apache Hive", |
| // getManifestAttribute ("Specification-Title"), |
| // getManifestAttribute ("Implementation-Version"), |
| // getManifestAttribute ("Implementation-ReleaseDate"), |
| // getManifestAttribute ("Implementation-Vendor"), |
| // getManifestAttribute ("Implementation-License"), |
| }); |
| } |
| |
| String getApplicationContactInformation() { |
| return getManifestAttribute("Implementation-Vendor"); |
| } |
| |
| String loc(String res) { |
| return loc(res, new Object[0]); |
| } |
| |
| String loc(String res, int param) { |
| try { |
| return MessageFormat.format( |
| new ChoiceFormat(resourceBundle.getString(res)).format(param), |
| new Object[] {Integer.valueOf(param)}); |
| } catch (Exception e) { |
| return res + ": " + param; |
| } |
| } |
| |
| String loc(String res, Object param1) { |
| return loc(res, new Object[] {param1}); |
| } |
| |
| String loc(String res, Object param1, Object param2) { |
| return loc(res, new Object[] {param1, param2}); |
| } |
| |
| String loc(String res, Object[] params) { |
| try { |
| return MessageFormat.format(resourceBundle.getString(res), params); |
| } catch (Exception e) { |
| e.printStackTrace(getErrorStream()); |
| try { |
| return res + ": " + Arrays.asList(params); |
| } catch (Exception e2) { |
| return res; |
| } |
| } |
| } |
| |
| protected String locElapsedTime(long milliseconds) { |
| if (getOpts().getShowElapsedTime()) { |
| return loc("time-ms", new Object[] {Double.valueOf(milliseconds / 1000d)}); |
| } |
| return ""; |
| } |
| |
| |
| /** |
| * Starts the program. |
| */ |
| public static void main(String[] args) throws IOException { |
| mainWithInputRedirection(args, null); |
| } |
| |
| /** |
| * Starts the program with redirected input. For redirected output, |
| * setOutputStream() and setErrorStream can be used. |
| * Exits with 0 on success, 1 on invalid arguments, and 2 on any other error |
| * |
| * @param args |
| * same as main() |
| * |
| * @param inputStream |
| * redirected input, or null to use standard input |
| */ |
| public static void mainWithInputRedirection(String[] args, InputStream inputStream) |
| throws IOException { |
| BeeLine beeLine = new BeeLine(); |
| try { |
| int status = beeLine.begin(args, inputStream); |
| |
| if (!Boolean.getBoolean(BeeLineOpts.PROPERTY_NAME_EXIT)) { |
| System.exit(status); |
| } |
| } finally { |
| beeLine.close(); |
| } |
| } |
| |
| public BeeLine() { |
| this(true); |
| } |
| |
| public BeeLine(boolean isBeeLine) { |
| this.isBeeLine = isBeeLine; |
| this.signalHandler = new SunSignalHandler(this); |
| this.shutdownHook = new Runnable() { |
| @Override |
| public void run() { |
| try { |
| if (history != null) { |
| history.setMaxSize(getOpts().getMaxHistoryRows()); |
| history.flush(); |
| } |
| } catch (IOException e) { |
| error(e); |
| } finally { |
| close(); |
| } |
| } |
| }; |
| } |
| |
| DatabaseConnection getDatabaseConnection() { |
| return getDatabaseConnections().current(); |
| } |
| |
| Connection getConnection() throws SQLException { |
| if (getDatabaseConnections().current() == null |
| || getDatabaseConnections().current().getConnection() == null) { |
| throw new IllegalArgumentException(loc("no-current-connection")); |
| } |
| |
| return getDatabaseConnections().current().getConnection(); |
| } |
| |
| |
| DatabaseMetaData getDatabaseMetaData() { |
| if (getDatabaseConnections().current() == null) { |
| throw new IllegalArgumentException(loc("no-current-connection")); |
| } |
| if (getDatabaseConnections().current().getDatabaseMetaData() == null) { |
| throw new IllegalArgumentException(loc("no-current-connection")); |
| } |
| return getDatabaseConnections().current().getDatabaseMetaData(); |
| } |
| |
| |
| public String[] getIsolationLevels() { |
| return new String[] { |
| "TRANSACTION_NONE", |
| "TRANSACTION_READ_COMMITTED", |
| "TRANSACTION_READ_UNCOMMITTED", |
| "TRANSACTION_REPEATABLE_READ", |
| "TRANSACTION_SERIALIZABLE", |
| }; |
| } |
| |
| |
| public String[] getMetadataMethodNames() { |
| try { |
| TreeSet<String> mnames = new TreeSet<String>(); |
| Method[] m = DatabaseMetaData.class.getDeclaredMethods(); |
| for (int i = 0; m != null && i < m.length; i++) { |
| mnames.add(m[i].getName()); |
| } |
| return mnames.toArray(new String[0]); |
| } catch (Throwable t) { |
| return new String[0]; |
| } |
| } |
| |
| |
| public String[] getConnectionURLExamples() { |
| return new String[] { |
| "jdbc:JSQLConnect://<hostname>/database=<database>", |
| "jdbc:cloudscape:<database>;create=true", |
| "jdbc:twtds:sqlserver://<hostname>/<database>", |
| "jdbc:daffodilDB_embedded:<database>;create=true", |
| "jdbc:datadirect:db2://<hostname>:50000;databaseName=<database>", |
| "jdbc:inetdae:<hostname>:1433", |
| "jdbc:datadirect:oracle://<hostname>:1521;SID=<database>;MaxPooledStatements=0", |
| "jdbc:datadirect:sqlserver://<hostname>:1433;SelectMethod=cursor;DatabaseName=<database>", |
| "jdbc:datadirect:sybase://<hostname>:5000", |
| "jdbc:db2://<hostname>/<database>", |
| "jdbc:hive2://<hostname>", |
| "jdbc:hsqldb:<database>", |
| "jdbc:idb:<database>.properties", |
| "jdbc:informix-sqli://<hostname>:1526/<database>:INFORMIXSERVER=<database>", |
| "jdbc:interbase://<hostname>//<database>.gdb", |
| "jdbc:microsoft:sqlserver://<hostname>:1433;DatabaseName=<database>;SelectMethod=cursor", |
| "jdbc:mysql://<hostname>/<database>?autoReconnect=true", |
| "jdbc:oracle:thin:@<hostname>:1521:<database>", |
| "jdbc:pointbase:<database>,database.home=<database>,create=true", |
| "jdbc:postgresql://<hostname>:5432/<database>", |
| "jdbc:postgresql:net//<hostname>/<database>", |
| "jdbc:sybase:Tds:<hostname>:4100/<database>?ServiceName=<database>", |
| "jdbc:weblogic:mssqlserver4:<database>@<hostname>:1433", |
| "jdbc:odbc:<database>", |
| "jdbc:sequelink://<hostname>:4003/[Oracle]", |
| "jdbc:sequelink://<hostname>:4004/[Informix];Database=<database>", |
| "jdbc:sequelink://<hostname>:4005/[Sybase];Database=<database>", |
| "jdbc:sequelink://<hostname>:4006/[SQLServer];Database=<database>", |
| "jdbc:sequelink://<hostname>:4011/[ODBC MS Access];Database=<database>", |
| "jdbc:openlink://<hostname>/DSN=SQLServerDB/UID=sa/PWD=", |
| "jdbc:solid://<hostname>:<port>/<UID>/<PWD>", |
| "jdbc:dbaw://<hostname>:8889/<database>", |
| }; |
| } |
| |
| /** |
| * Entry point to creating a {@link ColorBuffer} with color |
| * enabled or disabled depending on the value of {@link BeeLineOpts#getColor}. |
| */ |
| ColorBuffer getColorBuffer() { |
| return new ColorBuffer(getOpts().getColor()); |
| } |
| |
| |
| /** |
| * Entry point to creating a {@link ColorBuffer} with color |
| * enabled or disabled depending on the value of {@link BeeLineOpts#getColor}. |
| */ |
| ColorBuffer getColorBuffer(String msg) { |
| return new ColorBuffer(msg, getOpts().getColor()); |
| } |
| |
| |
| public class BeelineParser extends GnuParser { |
| private boolean isPasswordOptionSet = false; |
| |
| @Override |
| protected void processOption(String arg, final ListIterator iter) throws ParseException { |
| if (isBeeLineOpt(arg)) { |
| processBeeLineOpt(arg); |
| } else { |
| //-p with the next argument being for BeeLineOpts |
| if ("-p".equals(arg)) { |
| isPasswordOptionSet = true; |
| if(iter.hasNext()) { |
| String next = (String) iter.next(); |
| if(isBeeLineOpt(next)) { |
| processBeeLineOpt(next); |
| return; |
| } else { |
| iter.previous(); |
| } |
| } |
| } |
| super.processOption(arg, iter); |
| } |
| } |
| |
| private void processBeeLineOpt(final String arg) { |
| String stripped = arg.substring(2, arg.length()); |
| String[] parts = split(stripped, "="); |
| debug(loc("setting-prop", Arrays.asList(parts))); |
| if (parts.length >= 2) { |
| getOpts().set(parts[0], parts[1], true); |
| } else { |
| getOpts().set(parts[0], "true", true); |
| } |
| } |
| |
| private boolean isBeeLineOpt(String arg) { |
| return arg.startsWith("--") && !(HIVE_VAR_PREFIX.equals(arg) || (HIVE_CONF_PREFIX.equals(arg)) |
| || "--help".equals(arg) || PROP_FILE_PREFIX.equals(arg) || "--getUrlsFromBeelineSite".equals(arg)); |
| } |
| } |
| |
| int initArgsFromCliVars(String[] args) { |
| List<String> commands = Collections.emptyList(); |
| |
| CliOptionsProcessor optionsProcessor = new CliOptionsProcessor(); |
| if (!optionsProcessor.process(args)) { |
| return 1; |
| } |
| CommandLine commandLine = optionsProcessor.getCommandLine(); |
| |
| |
| Properties confProps = commandLine.getOptionProperties("hiveconf"); |
| for (String propKey : confProps.stringPropertyNames()) { |
| setHiveConfVar(propKey, confProps.getProperty(propKey)); |
| } |
| |
| Properties hiveVars = commandLine.getOptionProperties("define"); |
| for (String propKey : hiveVars.stringPropertyNames()) { |
| getOpts().getHiveConfVariables().put(propKey, hiveVars.getProperty(propKey)); |
| } |
| |
| Properties hiveVars2 = commandLine.getOptionProperties("hivevar"); |
| for (String propKey : hiveVars2.stringPropertyNames()) { |
| getOpts().getHiveConfVariables().put(propKey, hiveVars2.getProperty(propKey)); |
| } |
| |
| getOpts().setScriptFile(commandLine.getOptionValue("f")); |
| |
| if (commandLine.getOptionValues("i") != null) { |
| getOpts().setInitFiles(commandLine.getOptionValues("i")); |
| } |
| |
| dbName = commandLine.getOptionValue("database"); |
| getOpts().setVerbose(Boolean.parseBoolean(commandLine.getOptionValue("verbose"))); |
| getOpts().setSilent(Boolean.parseBoolean(commandLine.getOptionValue("silent"))); |
| |
| int code = 0; |
| if (commandLine.getOptionValues("e") != null) { |
| commands = Arrays.asList(commandLine.getOptionValues("e")); |
| } |
| |
| if (!commands.isEmpty() && getOpts().getScriptFile() != null) { |
| System.err.println("The '-e' and '-f' options cannot be specified simultaneously"); |
| optionsProcessor.printCliUsage(); |
| return 1; |
| } |
| |
| if (!commands.isEmpty()) { |
| embeddedConnect(); |
| connectDBInEmbededMode(); |
| for (Iterator<String> i = commands.iterator(); i.hasNext(); ) { |
| String command = i.next().toString(); |
| debug(loc("executing-command", command)); |
| if (!dispatch(command)) { |
| code++; |
| } |
| } |
| exit = true; // execute and exit |
| } |
| return code; |
| } |
| |
| int initArgs(String[] args) { |
| List<String> commands = Collections.emptyList(); |
| |
| CommandLine cl; |
| BeelineParser beelineParser; |
| |
| try { |
| beelineParser = new BeelineParser(); |
| cl = beelineParser.parse(options, args); |
| } catch (ParseException e1) { |
| output(e1.getMessage()); |
| usage(); |
| return -1; |
| } |
| |
| boolean connSuccessful = connectUsingArgs(beelineParser, cl); |
| // checks if default hs2 connection configuration file is present |
| // and uses it to connect if found |
| // no-op if the file is not present |
| if(!connSuccessful && !exit) { |
| connSuccessful = defaultBeelineConnect(cl); |
| } |
| if (exit) { |
| return 1; |
| } |
| |
| int code = 0; |
| if (cl.getOptionValues('e') != null) { |
| commands = Arrays.asList(cl.getOptionValues('e')); |
| opts.setAllowMultiLineCommand(false); //When using -e, command is always a single line |
| |
| } |
| |
| if (!commands.isEmpty() && getOpts().getScriptFile() != null) { |
| error("The '-e' and '-f' options cannot be specified simultaneously"); |
| return 1; |
| } else if(!commands.isEmpty() && !connSuccessful) { |
| error("Cannot run commands specified using -e. No current connection"); |
| return 1; |
| } |
| if (!commands.isEmpty()) { |
| for (Iterator<String> i = commands.iterator(); i.hasNext();) { |
| String command = i.next().toString(); |
| debug(loc("executing-command", command)); |
| if (!dispatch(command)) { |
| code++; |
| } |
| } |
| exit = true; // execute and exit |
| } |
| return code; |
| } |
| |
| |
| /* |
| * Connects using the command line arguments. There are two |
| * possible ways to connect here 1. using the cmd line arguments like -u |
| * or using !properties <property-file> |
| */ |
| private boolean connectUsingArgs(BeelineParser beelineParser, CommandLine cl) { |
| String driver = null, user = null, pass = "", url = null; |
| String auth = null; |
| |
| |
| if (cl.hasOption("help")) { |
| usage(); |
| getOpts().setHelpAsked(true); |
| return true; |
| } |
| |
| if (cl.hasOption("getUrlsFromBeelineSite")) { |
| printBeelineSiteUrls(); |
| getOpts().setBeelineSiteUrlsAsked(true); |
| return true; |
| } |
| |
| Properties hiveVars = cl.getOptionProperties("hivevar"); |
| for (String key : hiveVars.stringPropertyNames()) { |
| getOpts().getHiveVariables().put(key, hiveVars.getProperty(key)); |
| } |
| |
| Properties hiveConfs = cl.getOptionProperties("hiveconf"); |
| for (String key : hiveConfs.stringPropertyNames()) { |
| setHiveConfVar(key, hiveConfs.getProperty(key)); |
| } |
| |
| driver = cl.getOptionValue("d"); |
| auth = cl.getOptionValue("a"); |
| user = cl.getOptionValue("n"); |
| getOpts().setAuthType(auth); |
| if (cl.hasOption("w")) { |
| pass = obtainPasswordFromFile(cl.getOptionValue("w")); |
| } else { |
| if (beelineParser.isPasswordOptionSet) { |
| pass = cl.getOptionValue("p"); |
| } |
| } |
| url = cl.getOptionValue("u"); |
| if ((url == null) && cl.hasOption("reconnect")){ |
| // If url was not specified with -u, but -r was present, use that. |
| url = getOpts().getLastConnectedUrl(); |
| } |
| getOpts().setInitFiles(cl.getOptionValues("i")); |
| getOpts().setScriptFile(cl.getOptionValue("f")); |
| |
| if (url != null) { |
| String hplSqlMode = Utils.parsePropertyFromUrl(url, Constants.MODE); |
| if ("HPLSQL".equalsIgnoreCase(hplSqlMode)) { |
| getOpts().setDelimiter("/"); |
| getOpts().setEntireLineAsCommand(true); |
| } |
| // Specifying username/password/driver explicitly will override the values from the url; |
| // make sure we don't override the values present in the url with empty values. |
| if (user == null) { |
| user = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_USER); |
| } |
| if (pass == null) { |
| pass = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_PASSWD); |
| } |
| if (driver == null) { |
| driver = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.PROPERTY_DRIVER); |
| } |
| |
| String com; |
| String comForDebug; |
| if(pass != null) { |
| com = constructCmd(url, user, pass, driver, false); |
| comForDebug = constructCmd(url, user, pass, driver, true); |
| } else { |
| com = constructCmdUrl(url, user, driver, false); |
| comForDebug = constructCmdUrl(url, user, driver, true); |
| } |
| debug(comForDebug); |
| if (!dispatch(com)) { |
| exit = true; |
| return false; |
| } |
| return true; |
| } |
| // load property file |
| String propertyFile = cl.getOptionValue("property-file"); |
| if (propertyFile != null) { |
| try { |
| this.consoleReader = new ConsoleReader(); |
| } catch (IOException e) { |
| handleException(e); |
| } |
| if (!dispatch("!properties " + propertyFile)) { |
| exit = true; |
| return false; |
| } else { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private void printBeelineSiteUrls() { |
| BeelineSiteParser beelineSiteParser = getUserBeelineSiteParser(); |
| if (!beelineSiteParser.configExists()) { |
| output("No beeline-site.xml in the path", true); |
| } |
| if (beelineSiteParser.configExists()) { |
| // Get the named url from user specific config file if present |
| try { |
| Properties userNamedConnectionURLs = beelineSiteParser.getConnectionProperties(); |
| userNamedConnectionURLs.remove(BeelineSiteParser.DEFAULT_NAMED_JDBC_URL_PROPERTY_KEY); |
| StringBuilder sb = new StringBuilder("urls: "); |
| for (Entry<Object, Object> entry : userNamedConnectionURLs.entrySet()) { |
| String urlFromBeelineSite = (String) entry.getValue(); |
| if (isZkBasedUrl(urlFromBeelineSite)) { |
| List<String> jdbcUrls = HiveConnection.getAllUrlStrings(urlFromBeelineSite); |
| for (String jdbcUrl : jdbcUrls) { |
| sb.append(jdbcUrl + ", "); |
| } |
| } else { |
| sb.append(urlFromBeelineSite + ", "); |
| } |
| } |
| output(sb.toString(), true); |
| } catch (Exception e) { |
| output(e.getMessage(), true); |
| return; |
| } |
| } |
| } |
| |
| private boolean isZkBasedUrl(String urlFromBeelineSite) { |
| String zkJdbcUriParam = ("serviceDiscoveryMode=zooKeeper").toLowerCase(); |
| if (urlFromBeelineSite.toLowerCase().contains(zkJdbcUriParam)) { |
| return true; |
| } |
| return false; |
| } |
| |
| private void setHiveConfVar(String key, String val) { |
| getOpts().getHiveConfVariables().put(key, val); |
| if (HiveConf.ConfVars.HIVE_EXECUTION_ENGINE.varname.equals(key) && "mr".equals(val)) { |
| info(HiveConf.generateMrDeprecationWarning()); |
| } |
| } |
| |
| private String constructCmd(String url, String user, String pass, String driver, boolean stripPasswd) { |
| return new StringBuilder() |
| .append("!connect ") |
| .append(url) |
| .append(" ") |
| .append(user == null || user.length() == 0 ? "''" : user) |
| .append(" ") |
| .append(stripPasswd ? PASSWD_MASK : (pass.length() == 0 ? "''" : pass)) |
| .append(" ") |
| .append((driver == null ? "" : driver)) |
| .toString(); |
| } |
| |
| /** |
| * This is an internal method used to create !connect command when -p option is used without |
| * providing the password on the command line. Connect command returned should be ; separated |
| * key-value pairs along with the url. We cannot use space separated !connect url user [password] |
| * [driver] here since both password and driver are optional and there would be no way to |
| * distinguish if the last string is password or driver |
| * |
| * @param url connection url passed using -u argument on the command line |
| * @param user username passed through command line |
| * @param driver driver passed through command line -d option |
| * @param stripPasswd when set to true generates a !connect command which strips the password for |
| * logging purposes |
| * @return !connect command |
| */ |
| private String constructCmdUrl(String url, String user, String driver, |
| boolean stripPasswd) { |
| StringBuilder command = new StringBuilder("!connect "); |
| command.append(url); |
| //if the url does not have a database name add the trailing '/' |
| if(isTrailingSlashNeeded(url)) { |
| command.append('/'); |
| } |
| command.append(';'); |
| // if the username is not already available in the URL add the one provided |
| if (Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_USER) == null) { |
| command.append(JdbcConnectionParams.AUTH_USER); |
| command.append('='); |
| command.append((user == null || user.length() == 0 ? "''" : user)); |
| } |
| if (stripPasswd) { |
| // if password is available in url it needs to be striped |
| int startIndex = command.indexOf(JdbcConnectionParams.AUTH_PASSWD + "=") |
| + JdbcConnectionParams.AUTH_PASSWD.length() + 2; |
| if(startIndex != -1) { |
| int endIndex = command.toString().indexOf(";", startIndex); |
| command.replace(startIndex, (endIndex == -1 ? command.length() : endIndex), |
| BeeLine.PASSWD_MASK); |
| } |
| } |
| // if the driver is not already available in the URL add the one provided |
| if (Utils.parsePropertyFromUrl(url, JdbcConnectionParams.PROPERTY_DRIVER) == null |
| && driver != null) { |
| command.append(';'); |
| command.append(JdbcConnectionParams.PROPERTY_DRIVER); |
| command.append("="); |
| command.append(driver); |
| } |
| return command.toString(); |
| } |
| |
| /* |
| * Returns true if trailing slash is needed to be appended to the url |
| */ |
| private boolean isTrailingSlashNeeded(String url) { |
| if (url.toLowerCase().startsWith("jdbc:hive2://")) { |
| return url.indexOf('/', "jdbc:hive2://".length()) < 0; |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Obtains a password from the passed file path. |
| */ |
| private String obtainPasswordFromFile(String passwordFilePath) { |
| try { |
| Path path = Paths.get(passwordFilePath); |
| byte[] passwordFileContents = Files.readAllBytes(path); |
| return new String(passwordFileContents, "UTF-8").trim(); |
| } catch (Exception e) { |
| throw new RuntimeException("Unable to read user password from the password file: " |
| + passwordFilePath, e); |
| } |
| } |
| |
| public void updateOptsForCli() { |
| getOpts().updateBeeLineOptsFromConf(); |
| getOpts().setShowHeader(false); |
| getOpts().setEscapeCRLF(false); |
| getOpts().setOutputFormat("dsv"); |
| getOpts().setDelimiterForDSV(' '); |
| getOpts().setNullEmptyString(true); |
| } |
| |
| public int begin(String[] args, InputStream inputStream) throws IOException { |
| return begin(args, inputStream, true); |
| } |
| /** |
| * Start accepting input from stdin, and dispatch it |
| * to the appropriate {@link CommandHandler} until the |
| * global variable <code>exit</code> is true. |
| */ |
| public int begin(String[] args, InputStream inputStream, boolean keepHistory) throws IOException { |
| try { |
| // load the options first, so we can override on the command line |
| getOpts().load(); |
| } catch (Exception e) { |
| // nothing |
| } |
| |
| if (keepHistory) { |
| setupHistory(); |
| } |
| |
| //add shutdown hook to cleanup the beeline for smooth exit |
| addBeelineShutdownHook(); |
| |
| //this method also initializes the consoleReader which is |
| //needed by initArgs for certain execution paths |
| ConsoleReader reader = initializeConsoleReader(inputStream); |
| if (isBeeLine) { |
| int code = initArgs(args); |
| if (code != 0) { |
| return code; |
| } |
| } else { |
| int code = initArgsFromCliVars(args); |
| if (code != 0 || exit) { |
| return code; |
| } |
| defaultConnect(false); |
| } |
| |
| if (getOpts().isHelpAsked()) { |
| return 0; |
| } |
| if (getOpts().isBeelineSiteUrlsAsked()) { |
| return 0; |
| } |
| if (getOpts().getScriptFile() != null) { |
| return executeFile(getOpts().getScriptFile()); |
| } |
| try { |
| info(getApplicationTitle()); |
| } catch (Exception e) { |
| // ignore |
| } |
| return execute(reader, false); |
| } |
| |
| /* |
| * Attempts to make a connection using default HS2 connection config file if available |
| * if there connection is not made return false |
| * |
| */ |
| private boolean defaultBeelineConnect(CommandLine cl) { |
| String url; |
| try { |
| url = getDefaultConnectionUrl(cl); |
| if (url == null) { |
| debug("Default hs2 connection config file not found"); |
| return false; |
| } |
| } catch (BeelineConfFileParseException e) { |
| error(e); |
| return false; |
| } |
| return dispatch("!connect " + url); |
| } |
| |
| private String getDefaultConnectionUrl(CommandLine cl) throws BeelineConfFileParseException { |
| Properties mergedConnectionProperties = new Properties(); |
| JdbcConnectionParams jdbcConnectionParams = null; |
| BeelineSiteParser beelineSiteParser = getUserBeelineSiteParser(); |
| UserHS2ConnectionFileParser userHS2ConnFileParser = getUserHS2ConnFileParser(); |
| Properties userConnectionProperties = new Properties(); |
| |
| if (!userHS2ConnFileParser.configExists() && !beelineSiteParser.configExists()) { |
| // nothing to do if there is no user HS2 connection configuration file |
| // or beeline-site.xml in the path |
| return null; |
| } |
| |
| if (beelineSiteParser.configExists()) { |
| String urlFromCommandLineOption = cl.getOptionValue("u"); |
| if (urlFromCommandLineOption != null) { |
| throw new BeelineSiteParseException( |
| "Not using beeline-site.xml since the user provided the url: " + urlFromCommandLineOption); |
| } |
| // Get the named url from user specific config file if present |
| Properties userNamedConnectionURLs = beelineSiteParser.getConnectionProperties(); |
| if (!userNamedConnectionURLs.isEmpty()) { |
| String urlName = cl.getOptionValue("c"); |
| String jdbcURL = HS2ConnectionFileUtils.getNamedUrl(userNamedConnectionURLs, urlName); |
| if (jdbcURL != null) { |
| try { |
| jdbcConnectionParams = Utils.extractURLComponents(jdbcURL, new Properties()); |
| } catch (JdbcUriParseException e) { |
| throw new BeelineSiteParseException( |
| "Error in parsing jdbc url: " + jdbcURL + " from beeline-site.xml", e); |
| } |
| } |
| } |
| } |
| |
| if (userHS2ConnFileParser.configExists()) { |
| // get the connection properties from user specific config file |
| userConnectionProperties = userHS2ConnFileParser.getConnectionProperties(); |
| } |
| |
| if (jdbcConnectionParams != null) { |
| String userName = cl.getOptionValue("n"); |
| if (userName != null) { |
| jdbcConnectionParams.getSessionVars().put(JdbcConnectionParams.AUTH_USER, userName); |
| } |
| String password = cl.getOptionValue("p"); |
| if (password != null) { |
| jdbcConnectionParams.getSessionVars().put(JdbcConnectionParams.AUTH_PASSWD, password); |
| } |
| String auth = cl.getOptionValue("a"); |
| if (auth != null) { |
| jdbcConnectionParams.getSessionVars().put(JdbcConnectionParams.AUTH_TYPE, auth); |
| } |
| mergedConnectionProperties = |
| HS2ConnectionFileUtils.mergeUserConnectionPropertiesAndBeelineSite( |
| userConnectionProperties, jdbcConnectionParams); |
| } else { |
| mergedConnectionProperties = userConnectionProperties; |
| } |
| |
| // load the HS2 connection url properties from hive-site.xml if it is present in the classpath |
| HS2ConnectionFileParser hiveSiteParser = getHiveSiteHS2ConnectionFileParser(); |
| Properties hiveSiteConnectionProperties = hiveSiteParser.getConnectionProperties(); |
| // add/override properties found from hive-site with user-specific properties |
| for (String key : mergedConnectionProperties.stringPropertyNames()) { |
| if (hiveSiteConnectionProperties.containsKey(key)) { |
| debug("Overriding connection url property " + key |
| + " from user connection configuration file"); |
| } |
| hiveSiteConnectionProperties.setProperty(key, mergedConnectionProperties.getProperty(key)); |
| } |
| // return the url based on the aggregated connection properties |
| return HS2ConnectionFileUtils.getUrl(hiveSiteConnectionProperties); |
| } |
| |
| |
| /* |
| * Increased visibility of this method is only for providing better test coverage |
| */ |
| @VisibleForTesting |
| public BeelineSiteParser getUserBeelineSiteParser() { |
| return new BeelineSiteParser(); |
| } |
| |
| /* |
| * Increased visibility of this method is only for providing better test coverage |
| */ |
| @VisibleForTesting |
| public UserHS2ConnectionFileParser getUserHS2ConnFileParser() { |
| return new UserHS2ConnectionFileParser(); |
| } |
| |
| /* |
| * Increased visibility of this method is only for providing better test coverage |
| */ |
| @VisibleForTesting |
| public HS2ConnectionFileParser getHiveSiteHS2ConnectionFileParser() { |
| return new HiveSiteHS2ConnectionFileParser(); |
| } |
| |
| int runInit() { |
| String[] initFiles = getOpts().getInitFiles(); |
| |
| //executionResult will be ERRNO_OK only if all initFiles execute successfully |
| int executionResult = ERRNO_OK; |
| boolean exitOnError = !getOpts().getForce(); |
| |
| if (initFiles != null && initFiles.length != 0) { |
| for (String initFile : initFiles) { |
| info("Running init script " + initFile); |
| try { |
| int currentResult = executeFile(initFile); |
| if (currentResult != ERRNO_OK) { |
| executionResult = currentResult; |
| |
| if (exitOnError) { |
| return executionResult; |
| } |
| } |
| } finally { |
| //exit beeline if there is initScript failure and --force is not set |
| exit = exitOnError && executionResult != ERRNO_OK; |
| } |
| } |
| } |
| return executionResult; |
| } |
| |
| private int embeddedConnect() { |
| if (!execCommandWithPrefix("!connect " + Utils.URL_PREFIX + " '' ''")) { |
| return ERRNO_OTHER; |
| } else { |
| return ERRNO_OK; |
| } |
| } |
| |
| private int connectDBInEmbededMode() { |
| if (dbName != null && !dbName.isEmpty()) { |
| if (!dispatch("use " + dbName + ";")) { |
| return ERRNO_OTHER; |
| } |
| } |
| return ERRNO_OK; |
| } |
| |
| public int defaultConnect(boolean exitOnError) { |
| if (embeddedConnect() != ERRNO_OK && exitOnError) { |
| return ERRNO_OTHER; |
| } |
| if (connectDBInEmbededMode() != ERRNO_OK && exitOnError) { |
| return ERRNO_OTHER; |
| } |
| return ERRNO_OK; |
| } |
| |
| private int executeFile(String fileName) { |
| InputStream fileStream = null; |
| try { |
| if (!isBeeLine) { |
| org.apache.hadoop.fs.Path path = new org.apache.hadoop.fs.Path(fileName); |
| FileSystem fs; |
| HiveConf conf = getCommands().getHiveConf(true); |
| if (!path.toUri().isAbsolute()) { |
| fs = FileSystem.getLocal(conf); |
| path = fs.makeQualified(path); |
| } else { |
| fs = FileSystem.get(path.toUri(), conf); |
| } |
| fileStream = fs.open(path); |
| } else { |
| org.apache.hadoop.fs.Path path = new org.apache.hadoop.fs.Path(fileName); |
| FileSystem fs; |
| Configuration conf = new Configuration(); |
| if (!path.toUri().isAbsolute()) { |
| fs = FileSystem.getLocal(conf); |
| path = fs.makeQualified(path); |
| } else { |
| fs = FileSystem.get(path.toUri(), conf); |
| } |
| fileStream = fs.open(path); |
| } |
| return execute(initializeConsoleReader(fileStream), !getOpts().getForce()); |
| } catch (Throwable t) { |
| handleException(t); |
| return ERRNO_OTHER; |
| } finally { |
| IOUtils.closeStream(fileStream); |
| } |
| } |
| |
| private int execute(ConsoleReader reader, boolean exitOnError) { |
| int lastExecutionResult = ERRNO_OK; |
| Character mask = (System.getProperty("jline.terminal", "").equals("jline.UnsupportedTerminal")) ? null |
| : ConsoleReader.NULL_MASK; |
| |
| while (!exit) { |
| try { |
| // Execute one instruction; terminate on executing a script if there is an error |
| // in silent mode, prevent the query and prompt being echoed back to terminal |
| String line = (getOpts().isSilent() && getOpts().getScriptFile() != null) ? reader |
| .readLine(null, mask) : reader.readLine(getPrompt()); |
| |
| // trim line |
| if (line != null) { |
| line = line.trim(); |
| } |
| |
| if (!dispatch(line)) { |
| lastExecutionResult = ERRNO_OTHER; |
| if (exitOnError) { |
| break; |
| } |
| } else if (line != null) { |
| lastExecutionResult = ERRNO_OK; |
| } |
| |
| } catch (Throwable t) { |
| handleException(t); |
| return ERRNO_OTHER; |
| } |
| } |
| return lastExecutionResult; |
| } |
| |
| @Override |
| public void close() { |
| commands.closeall(null); |
| } |
| |
| private void setupHistory() throws IOException { |
| if (this.history != null) { |
| return; |
| } |
| |
| this.history = new FileHistory(new File(getOpts().getHistoryFile())); |
| } |
| |
| private void addBeelineShutdownHook() throws IOException { |
| // add shutdown hook to flush the history to history file and it also close all open connections |
| ShutdownHookManager.addShutdownHook(getShutdownHook()); |
| } |
| |
| public ConsoleReader initializeConsoleReader(InputStream inputStream) throws IOException { |
| if (inputStream != null) { |
| // ### NOTE: fix for sf.net bug 879425. |
| // Working around an issue in jline-2.1.2, see https://github.com/jline/jline/issues/10 |
| // by appending a newline to the end of inputstream |
| InputStream inputStreamAppendedNewline = new SequenceInputStream(inputStream, |
| new ByteArrayInputStream((new String("\n")).getBytes())); |
| consoleReader = new ConsoleReader(inputStreamAppendedNewline, getErrorStream()); |
| consoleReader.setCopyPasteDetection(true); // jline will detect if <tab> is regular character |
| } else { |
| consoleReader = new ConsoleReader(getInputStream(), getErrorStream()); |
| } |
| |
| //disable the expandEvents for the purpose of backward compatibility |
| consoleReader.setExpandEvents(false); |
| |
| try { |
| // now set the output for the history |
| if (this.history != null) { |
| consoleReader.setHistory(this.history); |
| } else { |
| consoleReader.setHistoryEnabled(false); |
| } |
| } catch (Exception e) { |
| handleException(e); |
| } |
| |
| if (inputStream instanceof FileInputStream || inputStream instanceof FSDataInputStream) { |
| // from script.. no need to load history and no need of completer, either |
| return consoleReader; |
| } |
| |
| consoleReader.addCompleter(new BeeLineCompleter(this)); |
| return consoleReader; |
| } |
| |
| void usage() { |
| output(loc("cmd-usage")); |
| } |
| |
| /** |
| * This method is used for executing commands beginning with ! |
| * @param line |
| * @return |
| */ |
| public boolean execCommandWithPrefix(String line) { |
| Map<String, CommandHandler> cmdMap = new TreeMap<String, CommandHandler>(); |
| line = line.substring(1); |
| for (int i = 0; i < commandHandlers.length; i++) { |
| String match = commandHandlers[i].matches(line); |
| if (match != null) { |
| cmdMap.put(match, commandHandlers[i]); |
| } |
| } |
| |
| if (cmdMap.size() == 0) { |
| return error(loc("unknown-command", line)); |
| } |
| if (cmdMap.size() > 1) { |
| // any exact match? |
| CommandHandler handler = cmdMap.get(line); |
| if (handler == null) { |
| return error(loc("multiple-matches", cmdMap.keySet().toString())); |
| } |
| return handler.execute(line); |
| } |
| return cmdMap.values().iterator().next().execute(line); |
| } |
| |
| /** |
| * Dispatch the specified line to the appropriate {@link CommandHandler}. |
| * |
| * @param line |
| * the command-line to dispatch |
| * @return true if the command was "successful" |
| */ |
| boolean dispatch(String line) { |
| if (line == null) { |
| // exit |
| exit = true; |
| return true; |
| } |
| |
| line = HiveStringUtils.removeComments(line); |
| |
| if (line.trim().length() == 0) { |
| return true; |
| } |
| |
| line = line.trim(); |
| |
| // save it to the current script, if any |
| if (scriptOutputFile != null) { |
| scriptOutputFile.addLine(line); |
| } |
| |
| if (isHelpRequest(line)) { |
| line = "!help"; |
| } |
| |
| if (isBeeLine) { |
| if (line.startsWith(COMMAND_PREFIX)) { |
| // handle SQLLine command in beeline which starts with ! and does not end with ; |
| return execCommandWithPrefix(line); |
| } else { |
| return commands.sql(line, getOpts().getEntireLineAsCommand()); |
| } |
| } else { |
| return commands.sql(line, getOpts().getEntireLineAsCommand()); |
| } |
| } |
| |
| /** |
| * Test whether a line requires a continuation. |
| * |
| * @param line |
| * the line to be tested |
| * |
| * @return true if continuation required |
| */ |
| boolean needsContinuation(String line) { |
| if (isHelpRequest(line)) { |
| return false; |
| } |
| |
| if (line.startsWith(COMMAND_PREFIX)) { |
| return false; |
| } |
| |
| if (isComment(line)) { |
| return false; |
| } |
| |
| String trimmed = line.trim(); |
| |
| if (trimmed.length() == 0) { |
| return false; |
| } |
| |
| if (!getOpts().isAllowMultiLineCommand()) { |
| return false; |
| } |
| |
| return !trimmed.endsWith(getOpts().getDelimiter()); |
| } |
| |
| /** |
| * Test whether a line is a help request other than !help. |
| * |
| * @param line |
| * the line to be tested |
| * |
| * @return true if a help request |
| */ |
| boolean isHelpRequest(String line) { |
| return line.equals("?") || line.equalsIgnoreCase("help"); |
| } |
| |
| /** |
| * Test whether a line is a comment. |
| * |
| * @param line |
| * the line to be tested |
| * |
| * @return true if a comment |
| */ |
| boolean isComment(String line) { |
| // SQL92 comment prefix is "--" |
| // beeline also supports shell-style "#" prefix |
| String lineTrimmed = line.trim(); |
| return lineTrimmed.startsWith("#") || lineTrimmed.startsWith("--"); |
| } |
| |
| String[] getCommands(File file) throws IOException { |
| List<String> cmds = new LinkedList<String>(); |
| try (BufferedReader reader = |
| new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) { |
| StringBuilder cmd = null; |
| while (true) { |
| String scriptLine = reader.readLine(); |
| |
| if (scriptLine == null) { |
| break; |
| } |
| |
| String trimmedLine = scriptLine.trim(); |
| if (getOpts().getTrimScripts()) { |
| scriptLine = trimmedLine; |
| } |
| |
| if (cmd != null) { |
| // we're continuing an existing command |
| cmd.append("\n"); |
| cmd.append(scriptLine); |
| if (trimmedLine.endsWith(getOpts().getDelimiter())) { |
| // this command has terminated |
| cmds.add(cmd.toString()); |
| cmd = null; |
| } |
| } else { |
| // we're starting a new command |
| if (needsContinuation(scriptLine)) { |
| // multi-line |
| cmd = new StringBuilder(scriptLine); |
| } else { |
| // single-line |
| cmds.add(scriptLine); |
| } |
| } |
| } |
| |
| if (cmd != null) { |
| // ### REVIEW: oops, somebody left the last command |
| // unterminated; should we fix it for them or complain? |
| // For now be nice and fix it. |
| cmd.append(getOpts().getDelimiter()); |
| cmds.add(cmd.toString()); |
| } |
| } |
| return cmds.toArray(new String[0]); |
| } |
| |
| /** |
| * Print the specified message to the console |
| * |
| * @param msg |
| * the message to print |
| */ |
| void output(String msg) { |
| output(msg, true); |
| } |
| |
| |
| void info(String msg) { |
| if (!(getOpts().isSilent())) { |
| output(msg, true, getErrorStream()); |
| } |
| } |
| |
| |
| void info(ColorBuffer msg) { |
| if (!(getOpts().isSilent())) { |
| output(msg, true, getErrorStream()); |
| } |
| } |
| |
| |
| /** |
| * Issue the specified error message |
| * |
| * @param msg |
| * the message to issue |
| * @return false always |
| */ |
| boolean error(String msg) { |
| output(getColorBuffer().red(msg), true, getErrorStream()); |
| return false; |
| } |
| |
| |
| boolean error(Throwable t) { |
| handleException(t); |
| return false; |
| } |
| |
| |
| void debug(String msg) { |
| if (getOpts().getVerbose()) { |
| output(getColorBuffer().blue(msg), true, getErrorStream()); |
| } |
| } |
| |
| |
| void output(ColorBuffer msg) { |
| output(msg, true); |
| } |
| |
| |
| void output(String msg, boolean newline, PrintStream out) { |
| output(getColorBuffer(msg), newline, out); |
| } |
| |
| |
| void output(ColorBuffer msg, boolean newline) { |
| output(msg, newline, getOutputStream()); |
| } |
| |
| |
| void output(ColorBuffer msg, boolean newline, PrintStream out) { |
| if (newline) { |
| out.println(msg.getColor()); |
| } else { |
| out.print(msg.getColor()); |
| } |
| |
| if (recordOutputFile == null) { |
| return; |
| } |
| |
| // only write to the record file if we are writing a line ... |
| // otherwise we might get garbage from backspaces and such. |
| if (newline) { |
| recordOutputFile.addLine(msg.getMono()); // always just write mono |
| } else { |
| recordOutputFile.print(msg.getMono()); |
| } |
| } |
| |
| |
| /** |
| * Print the specified message to the console |
| * |
| * @param msg |
| * the message to print |
| * @param newline |
| * if false, do not append a newline |
| */ |
| void output(String msg, boolean newline) { |
| output(getColorBuffer(msg), newline); |
| } |
| |
| |
| void autocommitStatus(Connection c) throws SQLException { |
| info(loc("autocommit-status", c.getAutoCommit() + "")); |
| } |
| |
| |
| /** |
| * Ensure that autocommit is on for the current connection |
| * |
| * @return true if autocommit is set |
| */ |
| boolean assertAutoCommit() { |
| if (!(assertConnection())) { |
| return false; |
| } |
| try { |
| if (getDatabaseConnection().getConnection().getAutoCommit()) { |
| return error(loc("autocommit-needs-off")); |
| } |
| } catch (Exception e) { |
| return error(e); |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Assert that we have an active, living connection. Print |
| * an error message if we do not. |
| * |
| * @return true if there is a current, active connection |
| */ |
| boolean assertConnection() { |
| try { |
| if (getDatabaseConnection() == null || getDatabaseConnection().getConnection() == null) { |
| return error(loc("no-current-connection")); |
| } |
| if (getDatabaseConnection().getConnection().isClosed()) { |
| return error(loc("connection-is-closed")); |
| } |
| } catch (SQLException sqle) { |
| return error(loc("no-current-connection")); |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Print out any warnings that exist for the current connection. |
| */ |
| void showWarnings() { |
| try { |
| if (getDatabaseConnection().getConnection() == null |
| || !getOpts().getVerbose()) { |
| return; |
| } |
| showWarnings(getDatabaseConnection().getConnection().getWarnings()); |
| } catch (Exception e) { |
| handleException(e); |
| } |
| } |
| |
| |
| /** |
| * Print the specified warning on the console, as well as |
| * any warnings that are returned from {@link SQLWarning#getNextWarning}. |
| * |
| * @param warn |
| * the {@link SQLWarning} to print |
| */ |
| void showWarnings(SQLWarning warn) { |
| if (warn == null) { |
| return; |
| } |
| |
| if (seenWarnings.get(warn) == null) { |
| // don't re-display warnings we have already seen |
| seenWarnings.put(warn, new java.util.Date()); |
| handleSQLException(warn); |
| } |
| |
| SQLWarning next = warn.getNextWarning(); |
| if (next != warn) { |
| showWarnings(next); |
| } |
| } |
| |
| String getPrompt() { |
| if (isBeeLine) { |
| return getPromptForBeeline(); |
| } else { |
| return getPromptForCli(); |
| } |
| } |
| |
| String getPromptForCli() { |
| String prompt; |
| // read prompt configuration and substitute variables. |
| HiveConf conf = getCommands().getHiveConf(true); |
| prompt = conf.getVar(HiveConf.ConfVars.CLIPROMPT); |
| prompt = getCommands().substituteVariables(conf, prompt); |
| return prompt + getFormattedDb() + "> "; |
| } |
| |
| /** |
| * Retrieve the current database name string to display, based on the |
| * configuration value. |
| * |
| * @return String to show user for current db value |
| */ |
| String getFormattedDb() { |
| if (!getOpts().getShowDbInPrompt()) { |
| return ""; |
| } |
| String currDb = getCurrentDatabase(); |
| |
| if (currDb == null) { |
| return ""; |
| } |
| |
| return " (" + currDb + ")"; |
| } |
| |
| String getPromptForBeeline() { |
| if (getDatabaseConnection() == null || getDatabaseConnection().getUrl() == null) { |
| return "beeline> "; |
| } else { |
| String printClosed = getDatabaseConnection().isClosed() ? " (closed)" : ""; |
| return getPromptForBeeline(getDatabaseConnections().getIndex() |
| + ": " + getDatabaseConnection().getUrl()) + printClosed + getFormattedDb() + "> "; |
| } |
| } |
| |
| static String getPromptForBeeline(String url) { |
| if (url == null || url.length() == 0) { |
| url = "beeline"; |
| } |
| if (url.indexOf(";") > -1) { |
| url = url.substring(0, url.indexOf(";")); |
| } |
| if (url.indexOf("?") > -1) { |
| url = url.substring(0, url.indexOf("?")); |
| } |
| if (url.length() > 45) { |
| url = url.substring(0, 45); |
| } |
| return url; |
| } |
| |
| /** |
| * Try to obtain the current size of the specified {@link ResultSet} by jumping to the last row |
| * and getting the row number. |
| * |
| * @param rs |
| * the {@link ResultSet} to get the size for |
| * @return the size, or -1 if it could not be obtained |
| */ |
| int getSize(ResultSet rs) { |
| try { |
| if (rs.getType() == ResultSet.TYPE_FORWARD_ONLY) { |
| return -1; |
| } |
| rs.last(); |
| int total = rs.getRow(); |
| rs.beforeFirst(); |
| return total; |
| } catch (SQLException sqle) { |
| return -1; |
| } |
| // JDBC 1 driver error |
| catch (AbstractMethodError ame) { |
| return -1; |
| } |
| } |
| |
| |
| ResultSet getColumns(String table) throws SQLException { |
| if (!(assertConnection())) { |
| return null; |
| } |
| return getDatabaseConnection().getDatabaseMetaData().getColumns( |
| getDatabaseConnection().getDatabaseMetaData().getConnection().getCatalog(), null, table, "%"); |
| } |
| |
| |
| ResultSet getTables() throws SQLException { |
| if (!(assertConnection())) { |
| return null; |
| } |
| return getDatabaseConnection().getDatabaseMetaData().getTables( |
| getDatabaseConnection().getDatabaseMetaData().getConnection().getCatalog(), null, "%", |
| new String[] {"TABLE"}); |
| } |
| |
| |
| String[] getColumnNames(DatabaseMetaData meta) throws SQLException { |
| Set<String> names = new HashSet<String>(); |
| info(loc("building-tables")); |
| try { |
| ResultSet columns = getColumns("%"); |
| try { |
| int total = getSize(columns); |
| int index = 0; |
| |
| while (columns.next()) { |
| // add the following strings: |
| // 1. column name |
| // 2. table name |
| // 3. tablename.columnname |
| |
| progress(index++, total); |
| String name = columns.getString("TABLE_NAME"); |
| names.add(name); |
| names.add(columns.getString("COLUMN_NAME")); |
| names.add(columns.getString("TABLE_NAME") + "." |
| + columns.getString("COLUMN_NAME")); |
| } |
| progress(index, index); |
| } finally { |
| columns.close(); |
| } |
| info(loc("done")); |
| return names.toArray(new String[0]); |
| } catch (Throwable t) { |
| handleException(t); |
| return new String[0]; |
| } |
| } |
| |
| |
| // ////////////////// |
| // String utilities |
| // ////////////////// |
| |
| |
| /** |
| * Split the line into an array by tokenizing on space characters |
| * |
| * @param line |
| * the line to break up |
| * @return an array of individual words |
| */ |
| String[] split(String line) { |
| return split(line, " "); |
| } |
| |
| |
| String dequote(String str) { |
| if (str == null) { |
| return null; |
| } |
| while ((str.startsWith("'") && str.endsWith("'")) |
| || (str.startsWith("\"") && str.endsWith("\""))) { |
| str = str.substring(1, str.length() - 1); |
| } |
| return str; |
| } |
| |
| |
| String[] split(String line, String delim) { |
| StringTokenizer tok = new StringTokenizer(line, delim); |
| String[] ret = new String[tok.countTokens()]; |
| int index = 0; |
| while (tok.hasMoreTokens()) { |
| String t = tok.nextToken(); |
| t = dequote(t); |
| ret[index++] = t; |
| } |
| return ret; |
| } |
| |
| |
| static Map<Object, Object> map(Object[] obs) { |
| Map<Object, Object> m = new LinkedHashMap<Object, Object>(); |
| for (int i = 0; i < obs.length - 1; i += 2) { |
| m.put(obs[i], obs[i + 1]); |
| } |
| return Collections.unmodifiableMap(m); |
| } |
| |
| |
| static boolean getMoreResults(Statement stmnt) { |
| try { |
| return stmnt.getMoreResults(); |
| } catch (Throwable t) { |
| return false; |
| } |
| } |
| |
| |
| static String xmlattrencode(String str) { |
| str = replace(str, "\"", """); |
| str = replace(str, "<", "<"); |
| return str; |
| } |
| |
| |
| static String replace(String source, String from, String to) { |
| if (source == null) { |
| return null; |
| } |
| |
| if (from.equals(to)) { |
| return source; |
| } |
| |
| StringBuilder replaced = new StringBuilder(); |
| |
| int index = -1; |
| while ((index = source.indexOf(from)) != -1) { |
| replaced.append(source.substring(0, index)); |
| replaced.append(to); |
| source = source.substring(index + from.length()); |
| } |
| replaced.append(source); |
| |
| return replaced.toString(); |
| } |
| |
| |
| /** |
| * Split the line based on spaces, asserting that the |
| * number of words is correct. |
| * |
| * @param line |
| * the line to split |
| * @param assertLen |
| * the number of words to assure |
| * @param usage |
| * the message to output if there are an incorrect |
| * number of words. |
| * @return the split lines, or null if the assertion failed. |
| */ |
| String[] split(String line, int assertLen, String usage) { |
| String[] ret = split(line); |
| |
| if (ret.length != assertLen) { |
| error(usage); |
| return null; |
| } |
| |
| return ret; |
| } |
| |
| |
| /** |
| * Wrap the specified string by breaking on space characters. |
| * |
| * @param toWrap |
| * the string to wrap |
| * @param len |
| * the maximum length of any line |
| * @param start |
| * the number of spaces to pad at the |
| * beginning of a line |
| * @return the wrapped string |
| */ |
| String wrap(String toWrap, int len, int start) { |
| StringBuilder buff = new StringBuilder(); |
| StringBuilder line = new StringBuilder(); |
| |
| char[] head = new char[start]; |
| Arrays.fill(head, ' '); |
| |
| for (StringTokenizer tok = new StringTokenizer(toWrap, " "); tok.hasMoreTokens();) { |
| String next = tok.nextToken(); |
| if (line.length() + next.length() > len) { |
| buff.append(line).append(separator).append(head); |
| line.setLength(0); |
| } |
| |
| line.append(line.length() == 0 ? "" : " ").append(next); |
| } |
| |
| buff.append(line); |
| return buff.toString(); |
| } |
| |
| |
| /** |
| * Output a progress indicator to the console. |
| * |
| * @param cur |
| * the current progress |
| * @param max |
| * the maximum progress, or -1 if unknown |
| */ |
| void progress(int cur, int max) { |
| StringBuilder out = new StringBuilder(); |
| |
| if (lastProgress != null) { |
| char[] back = new char[lastProgress.length()]; |
| Arrays.fill(back, '\b'); |
| out.append(back); |
| } |
| |
| String progress = cur + "/" |
| + (max == -1 ? "?" : "" + max) + " " |
| + (max == -1 ? "(??%)" |
| : ("(" + (cur * 100 / (max == 0 ? 1 : max)) + "%)")); |
| |
| if (cur >= max && max != -1) { |
| progress += " " + loc("done") + separator; |
| lastProgress = null; |
| } else { |
| lastProgress = progress; |
| } |
| |
| out.append(progress); |
| |
| outputStream.print(out.toString()); |
| outputStream.flush(); |
| } |
| |
| // ///////////////////////////// |
| // Exception handling routines |
| // ///////////////////////////// |
| |
| void handleException(Throwable e) { |
| while (e instanceof InvocationTargetException) { |
| e = ((InvocationTargetException) e).getTargetException(); |
| } |
| |
| if (e instanceof SQLException) { |
| handleSQLException((SQLException) e); |
| } else if (e instanceof EOFException) { |
| setExit(true); // CTRL-D |
| } else if (!(getOpts().getVerbose())) { |
| if (e.getMessage() == null) { |
| error(e.getClass().getName()); |
| } else { |
| error(e.getMessage()); |
| } |
| } else { |
| e.printStackTrace(getErrorStream()); |
| } |
| } |
| |
| |
| void handleSQLException(SQLException e) { |
| if (e instanceof SQLWarning && !(getOpts().getShowWarnings())) { |
| return; |
| } |
| |
| if (e.getCause() instanceof TTransportException) { |
| switch (((TTransportException)e.getCause()).getType()) { |
| case TTransportException.ALREADY_OPEN: |
| error(loc("hs2-connection-already-open")); |
| break; |
| case TTransportException.END_OF_FILE: |
| error(loc("hs2-unexpected-end-of-file")); |
| break; |
| case TTransportException.NOT_OPEN: |
| error(loc("hs2-could-not-open-connection")); |
| break; |
| case TTransportException.TIMED_OUT: |
| error(loc("hs2-connection-timed-out")); |
| break; |
| case TTransportException.UNKNOWN: |
| error(loc("hs2-unknown-connection-problem")); |
| break; |
| default: |
| error(loc("hs2-unexpected-error")); |
| } |
| } |
| |
| error(loc(e instanceof SQLWarning ? "Warning" : "Error", |
| new Object[] { |
| e.getMessage() == null ? "" : e.getMessage().trim(), |
| e.getSQLState() == null ? "" : e.getSQLState().trim(), |
| Integer.valueOf(e.getErrorCode())})); |
| |
| if (getOpts().getVerbose()) { |
| e.printStackTrace(getErrorStream()); |
| } |
| |
| if (!getOpts().getShowNestedErrs()) { |
| return; |
| } |
| |
| for (SQLException nested = e.getNextException(); nested != null && nested != e; nested = nested |
| .getNextException()) { |
| handleSQLException(nested); |
| } |
| } |
| |
| boolean scanForDriver(final String url) { |
| Objects.requireNonNull(url); |
| |
| try { |
| // Check drivers already registered |
| if (findRegisteredDriver(url) != null) { |
| return true; |
| } |
| |
| // Scan classpath for drivers and load them |
| scanDrivers(); |
| |
| // Try to find the driver again given the newly loaded drivers |
| if (findRegisteredDriver(url) != null) { |
| return true; |
| } |
| |
| // Find whether exists a local driver to accept the URL |
| if (findLocalDriver(url) != null) { |
| return true; |
| } |
| } catch (Exception e) { |
| return error(e); |
| } |
| |
| return false; |
| } |
| |
| |
| private Driver findRegisteredDriver(String url) { |
| for (Enumeration drivers = DriverManager.getDrivers(); drivers != null |
| && drivers.hasMoreElements();) { |
| Driver driver = (Driver) drivers.nextElement(); |
| try { |
| if (driver.acceptsURL(url)) { |
| return driver; |
| } |
| } catch (Exception e) { |
| } |
| } |
| return null; |
| } |
| |
| public Driver findLocalDriver(String url) throws Exception { |
| Objects.requireNonNull(url); |
| |
| Collection<Driver> currentDrivers = drivers == null ? Collections.emptyList() : drivers; |
| for (Driver d : currentDrivers) { |
| try { |
| String clazzName = d.getClass().getName(); |
| Driver driver = (Driver) Class.forName(clazzName, true, |
| Thread.currentThread().getContextClassLoader()).newInstance(); |
| if (driver.acceptsURL(url) && isSupportedLocalDriver(driver)) { |
| return driver; |
| } |
| } catch (SQLException e) { |
| throw e; |
| } |
| } |
| |
| return null; |
| } |
| |
| public boolean isSupportedLocalDriver(Driver driver) { |
| String driverName = driver.getClass().getName(); |
| for (String name : supportedLocalDriver) { |
| if (name.equals(driverName)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public void addLocalDriverClazz(String driverClazz) { |
| supportedLocalDriver.add(driverClazz); |
| } |
| |
| Collection<Driver> scanDrivers() throws IOException { |
| final long start = System.nanoTime(); |
| |
| ServiceLoader<Driver> sqlDrivers = ServiceLoader.load(Driver.class); |
| |
| Set<Driver> driverClasses = StreamSupport.stream(sqlDrivers.spliterator(), false).collect(Collectors.toSet()); |
| |
| final long finish = System.nanoTime(); |
| |
| info("Driver scan complete in " + TimeUnit.NANOSECONDS.toMillis(finish - start) + "ms"); |
| return Collections.unmodifiableSet(driverClasses); |
| } |
| |
| // ///////////////////////////////////// |
| // ResultSet output formatting classes |
| // ///////////////////////////////////// |
| |
| |
| |
| int print(ResultSet rs) throws SQLException { |
| String format = getOpts().getOutputFormat(); |
| OutputFormat f = (OutputFormat) formats.get(format); |
| |
| if (f == null) { |
| error(loc("unknown-format", new Object[] { |
| format, formats.keySet()})); |
| f = new TableOutputFormat(this); |
| } |
| |
| Rows rows; |
| |
| if (f instanceof TableOutputFormat) { |
| if (getOpts().getIncremental()) { |
| rows = new IncrementalRowsWithNormalization(this, rs); |
| } else { |
| rows = new BufferedRows(this, rs); |
| } |
| } else { |
| rows = new IncrementalRows(this, rs); |
| } |
| return f.print(rows); |
| } |
| |
| |
| Statement createStatement() throws SQLException { |
| Statement stmnt = getDatabaseConnection().getConnection().createStatement(); |
| if (getOpts().timeout > -1) { |
| stmnt.setQueryTimeout(getOpts().timeout); |
| } |
| if (signalHandler != null) { |
| signalHandler.setStatement(stmnt); |
| } |
| |
| // If no fetch size is specified in beeline, let the driver figure it out |
| final int fetchSize = getOpts().getFetchSize(); |
| if (fetchSize >= 0) { |
| stmnt.setFetchSize(fetchSize); |
| } |
| |
| return stmnt; |
| } |
| |
| |
| void runBatch(List<String> statements) { |
| try { |
| Statement stmnt = createStatement(); |
| try { |
| for (Iterator<String> i = statements.iterator(); i.hasNext();) { |
| stmnt.addBatch(i.next().toString()); |
| } |
| int[] counts = stmnt.executeBatch(); |
| |
| output(getColorBuffer().pad(getColorBuffer().bold("COUNT"), 8) |
| .append(getColorBuffer().bold("STATEMENT"))); |
| |
| for (int i = 0; counts != null && i < counts.length; i++) { |
| output(getColorBuffer().pad(counts[i] + "", 8) |
| .append(statements.get(i).toString())); |
| } |
| } finally { |
| try { |
| stmnt.close(); |
| } catch (Exception e) { |
| } |
| } |
| } catch (Exception e) { |
| handleException(e); |
| } |
| } |
| |
| public int runCommands(String[] cmds) { |
| return runCommands(Arrays.asList(cmds)); |
| } |
| |
| public int runCommands(List<String> cmds) { |
| int successCount = 0; |
| try { |
| // TODO: Make script output prefixing configurable. Had to disable this since |
| // it results in lots of test diffs. |
| for (String cmd : cmds) { |
| info(getColorBuffer().pad(SCRIPT_OUTPUT_PREFIX, SCRIPT_OUTPUT_PAD_SIZE).append(cmd)); |
| // if we do not force script execution, abort |
| // when a failure occurs. |
| if (dispatch(cmd) || getOpts().getForce()) { |
| ++successCount; |
| } else { |
| error(loc("abort-on-error", cmd)); |
| return successCount; |
| } |
| } |
| } catch (Exception e) { |
| handleException(e); |
| } |
| return successCount; |
| } |
| |
| // //////////////////////// |
| // Command methods follow |
| // //////////////////////// |
| |
| void setCompletions() throws SQLException, IOException { |
| if (getDatabaseConnection() != null) { |
| getDatabaseConnection().setCompletions(getOpts().getFastConnect()); |
| } |
| } |
| |
| public BeeLineOpts getOpts() { |
| return opts; |
| } |
| |
| DatabaseConnections getDatabaseConnections() { |
| return connections; |
| } |
| |
| Runnable getShutdownHook() { |
| return shutdownHook; |
| } |
| |
| Completer getCommandCompletor() { |
| return beeLineCommandCompleter; |
| } |
| |
| public boolean isExit() { |
| return exit; |
| } |
| |
| public void setExit(boolean exit) { |
| this.exit = exit; |
| } |
| |
| Collection<Driver> getDrivers() { |
| return drivers; |
| } |
| |
| void setDrivers(Collection<Driver> drivers) { |
| this.drivers = drivers; |
| } |
| |
| public static String getSeparator() { |
| return separator; |
| } |
| |
| Commands getCommands() { |
| return commands; |
| } |
| |
| OutputFile getScriptOutputFile() { |
| return scriptOutputFile; |
| } |
| |
| void setScriptOutputFile(OutputFile script) { |
| this.scriptOutputFile = script; |
| } |
| |
| OutputFile getRecordOutputFile() { |
| return recordOutputFile; |
| } |
| |
| void setRecordOutputFile(OutputFile record) { |
| this.recordOutputFile = record; |
| } |
| |
| public void setOutputStream(PrintStream outputStream) { |
| this.outputStream = new PrintStream(outputStream, true); |
| } |
| |
| PrintStream getOutputStream() { |
| return outputStream; |
| } |
| |
| public void setErrorStream(PrintStream errorStream) { |
| this.errorStream = new PrintStream(errorStream, true); |
| } |
| |
| PrintStream getErrorStream() { |
| return errorStream; |
| } |
| |
| InputStream getInputStream() { |
| return inputStream; |
| } |
| |
| ConsoleReader getConsoleReader() { |
| return consoleReader; |
| } |
| |
| void setConsoleReader(ConsoleReader reader) { |
| this.consoleReader = reader; |
| } |
| |
| List<String> getBatch() { |
| return batch; |
| } |
| |
| void setBatch(List<String> batch) { |
| this.batch = batch; |
| } |
| |
| protected Reflector getReflector() { |
| return reflector; |
| } |
| |
| public boolean isBeeLine() { |
| return isBeeLine; |
| } |
| |
| public void setBeeLine(boolean isBeeLine) { |
| this.isBeeLine = isBeeLine; |
| } |
| |
| public String getCurrentDatabase() { |
| if (currentDatabase == null) { |
| currentDatabase = DEFAULT_DATABASE_NAME; |
| } |
| return currentDatabase; |
| } |
| |
| public void setCurrentDatabase(String currentDatabase) { |
| this.currentDatabase = currentDatabase; |
| } |
| |
| /** |
| * Setting the BeeLine into test mode. |
| * Print only the errors, the operation log and the query results. |
| * Should be used only by tests. |
| * |
| * @param isTestMode |
| */ |
| void setIsTestMode(boolean isTestMode) { |
| this.isTestMode = isTestMode; |
| } |
| |
| boolean isTestMode() { |
| return isTestMode; |
| } |
| } |