blob: 129fc2eb9cc9f76e59d4d63ba1affa42b4c9f6ed [file] [log] [blame]
/*
* 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.IOException;
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.util.Collection;
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 org.apache.hive.jdbc.HiveConnection;
import jline.console.completer.ArgumentCompleter;
import jline.console.completer.Completer;
class DatabaseConnection {
private static final String HIVE_VAR_PREFIX = "hivevar:";
private static final String HIVE_CONF_PREFIX = "hiveconf:";
private final BeeLine beeLine;
private Connection connection;
private DatabaseMetaData meta;
private final String driver;
private final String url;
private final Properties info;
private Schema schema = null;
private Completer sqlCompleter = null;
public boolean isClosed() {
return (null == connection);
}
public DatabaseConnection(BeeLine beeLine, String driver, String url,
Properties info) throws SQLException {
this.beeLine = beeLine;
this.driver = driver;
this.url = url;
this.info = info;
}
@Override
public String toString() {
return getUrl() + "";
}
void setCompletions(boolean skipmeta) throws SQLException, IOException {
final String extraNameCharacters =
getDatabaseMetaData() == null || getDatabaseMetaData().getExtraNameCharacters() == null ? ""
: getDatabaseMetaData().getExtraNameCharacters();
// setup the completer for the database
sqlCompleter = new ArgumentCompleter(
new ArgumentCompleter.AbstractArgumentDelimiter() {
// delimiters for SQL statements are any
// non-letter-or-number characters, except
// underscore and characters that are specified
// by the database to be valid name identifiers.
@Override
public boolean isDelimiterChar(CharSequence buffer, int pos) {
char c = buffer.charAt(pos);
if (Character.isWhitespace(c)) {
return true;
}
return !(Character.isLetterOrDigit(c))
&& c != '_'
&& extraNameCharacters.indexOf(c) == -1;
}
},
new SQLCompleter(SQLCompleter.getSQLCompleters(beeLine, skipmeta)));
// not all argument elements need to hold true
((ArgumentCompleter) sqlCompleter).setStrict(false);
}
/**
* Connection to the specified data source.
*/
boolean connect() throws SQLException {
try {
if (driver != null && driver.length() != 0) {
Class.forName(driver);
}
} catch (ClassNotFoundException cnfe) {
return beeLine.error(cnfe);
}
boolean isDriverRegistered = false;
try {
isDriverRegistered = DriverManager.getDriver(getUrl()) != null;
} catch (Exception e) {
}
try {
close();
} catch (Exception e) {
return beeLine.error(e);
}
Map<String, String> hiveVars = beeLine.getOpts().getHiveVariables();
if (hiveVars != null){
for (Map.Entry<String, String> var : hiveVars.entrySet()) {
info.put(HIVE_VAR_PREFIX + var.getKey(), var.getValue());
}
}
Map<String, String> hiveConfVars = beeLine.getOpts().getHiveConfVariables();
if (hiveConfVars != null){
for (Map.Entry<String, String> var : hiveConfVars.entrySet()) {
info.put(HIVE_CONF_PREFIX + var.getKey(), var.getValue());
}
}
if (isDriverRegistered) {
// if the driver registered in the driver manager, get the connection via the driver manager
setConnection(DriverManager.getConnection(getUrl(), info));
} else {
beeLine.debug("Use the driver from local added jar file.");
setConnection(getConnectionFromLocalDriver(getUrl(), info));
}
setDatabaseMetaData(getConnection().getMetaData());
try {
beeLine.info(beeLine.loc("connected", new Object[] {
getDatabaseMetaData().getDatabaseProductName(),
getDatabaseMetaData().getDatabaseProductVersion()}));
} catch (Exception e) {
beeLine.handleException(e);
}
try {
beeLine.info(beeLine.loc("driver", new Object[] {
getDatabaseMetaData().getDriverName(),
getDatabaseMetaData().getDriverVersion()}));
} catch (Exception e) {
beeLine.handleException(e);
}
try {
getConnection().setAutoCommit(beeLine.getOpts().getAutoCommit());
// TODO: Setting autocommit should not generate an exception as long as it is set to false
// beeLine.autocommitStatus(getConnection());
} catch (Exception e) {
beeLine.handleException(e);
}
try {
beeLine.getCommands().isolation("isolation: " + beeLine.getOpts().getIsolation());
} catch (Exception e) {
beeLine.handleException(e);
}
return true;
}
public Connection getConnectionFromLocalDriver(String url, Properties properties) {
Collection<Driver> drivers = beeLine.getDrivers();
for (Driver d : drivers) {
try {
if (d.acceptsURL(url) && beeLine.isSupportedLocalDriver(d)) {
String clazzName = d.getClass().getName();
beeLine.debug("Driver name is " + clazzName);
Driver driver =
(Driver) Class.forName(clazzName, true, Thread.currentThread().getContextClassLoader())
.newInstance();
return driver.connect(url, properties);
}
} catch (Exception e) {
beeLine.error("Fail to connect with a local driver due to the exception:" + e);
beeLine.error(e);
}
}
return null;
}
public Connection getConnection() throws SQLException {
if (connection != null) {
return connection;
}
connect();
return connection;
}
public Connection getCurrentConnection() {
return connection;
}
public void reconnect() throws Exception {
close();
getConnection();
}
public void close() {
try {
try {
if (connection != null && !connection.isClosed()) {
beeLine.output(beeLine.loc("closing", connection));
connection.close();
}
} catch (Exception e) {
beeLine.handleException(e);
}
} finally {
setConnection(null);
setDatabaseMetaData(null);
}
}
public String[] getTableNames(boolean force) {
Schema.Table[] t = getSchema().getTables();
Set<String> names = new TreeSet<String>();
for (int i = 0; t != null && i < t.length; i++) {
names.add(t[i].getName());
}
return names.toArray(new String[names.size()]);
}
Schema getSchema() {
if (schema == null) {
schema = new Schema();
}
return schema;
}
void setConnection(Connection connection) {
this.connection = connection;
}
DatabaseMetaData getDatabaseMetaData() {
return meta;
}
void setDatabaseMetaData(DatabaseMetaData meta) {
this.meta = meta;
}
String getUrl() {
return url;
}
public String getConnectedUrl() {
if (connection instanceof HiveConnection) {
return ((HiveConnection) connection).getConnectedUrl();
}
return getUrl();
}
Completer getSQLCompleter() {
return sqlCompleter;
}
class Schema {
private Table[] tables = null;
Table[] getTables() {
if (tables != null) {
return tables;
}
List<Table> tnames = new LinkedList<Table>();
try {
ResultSet rs = getDatabaseMetaData().getTables(getConnection().getCatalog(),
null, "%", new String[] {"TABLE"});
try {
while (rs.next()) {
tnames.add(new Table(rs.getString("TABLE_NAME")));
}
} finally {
try {
rs.close();
} catch (Exception e) {
}
}
} catch (Throwable t) {
}
return tables = tnames.toArray(new Table[0]);
}
Table getTable(String name) {
Table[] t = getTables();
for (int i = 0; t != null && i < t.length; i++) {
if (name.equalsIgnoreCase(t[i].getName())) {
return t[i];
}
}
return null;
}
class Table {
final String name;
Column[] columns;
public Table(String name) {
this.name = name;
}
public String getName() {
return name;
}
class Column {
final String name;
boolean isPrimaryKey;
public Column(String name) {
this.name = name;
}
}
}
}
}