diff --git a/conf/zeppelin-site.xml.template b/conf/zeppelin-site.xml.template
index 9f773d50add..12d571b9c92 100644
--- a/conf/zeppelin-site.xml.template
+++ b/conf/zeppelin-site.xml.template
@@ -66,7 +66,7 @@
zeppelin.interpreters
- org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.hive.HiveInterpreter,org.apache.zeppelin.tajo.TajoInterpreter
+ org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.hive.HiveInterpreter,org.apache.zeppelin.tajo.TajoInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter
Comma separated interpreter configurations. First interpreter become a default
diff --git a/jdbc/COPYING b/jdbc/COPYING
new file mode 100644
index 00000000000..78d5b1b8243
--- /dev/null
+++ b/jdbc/COPYING
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+# @Author Hyungu Roh
+#
diff --git a/jdbc/pom.xml b/jdbc/pom.xml
new file mode 100644
index 00000000000..ab94b41281b
--- /dev/null
+++ b/jdbc/pom.xml
@@ -0,0 +1,140 @@
+
+
+
+
+ 4.0.0
+
+
+ zeppelin
+ org.apache.zeppelin
+ 0.5.0-SNAPSHOT
+
+
+ org.apache.zeppelin
+ zeppelin-jdbc
+ jar
+ 0.5.0-SNAPSHOT
+ Zeppelin: JDBC interpreter
+ http://zeppelin.incubator.apache.org
+
+
+
+ ${project.groupId}
+ zeppelin-interpreter
+ ${project.version}
+ provided
+
+
+
+ org.apache.commons
+ commons-exec
+ 1.1
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+
+ junit
+ junit
+ test
+
+
+
+ mysql
+ mysql-connector-java
+ 5.1.35
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+ 2.7
+
+ true
+
+
+
+
+ maven-enforcer-plugin
+ 1.3.1
+
+
+ enforce
+ none
+
+
+
+
+
+ maven-dependency-plugin
+ 2.8
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/../../interpreter/jdbc
+ false
+ false
+ true
+ runtime
+
+
+
+ copy-artifact
+ package
+
+ copy
+
+
+ ${project.build.directory}/../../interpreter/jdbc
+ false
+ false
+ true
+ runtime
+
+
+ ${project.groupId}
+ ${project.artifactId}
+ ${project.version}
+ ${project.packaging}
+
+
+
+
+
+
+
+
+
+
diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/DBConnection.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/DBConnection.java
new file mode 100644
index 00000000000..08966990065
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/DBConnection.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zeppelin.jdbc;
+
+import org.apache.zeppelin.interpreter.InterpreterResult;
+
+/**
+ * DBConnection
+ *
+ * @author Hyungu Roh hyungu.roh@navercorp.com
+ *
+ */
+
+public interface DBConnection {
+ void open();
+ void close();
+ InterpreterResult executeSql(String sql);
+ void cancel();
+}
+
diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/DBConnectionFactory.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/DBConnectionFactory.java
new file mode 100644
index 00000000000..15f0b466e92
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/DBConnectionFactory.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zeppelin.jdbc;
+
+import java.util.Properties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.sql.Connection;
+
+/**
+ * DBConnectionFactory
+ *
+ * @author Hyungu Roh hyungu.roh@navercorp.com
+ *
+ */
+
+public class DBConnectionFactory {
+ Logger logger = LoggerFactory.getLogger(DBConnectionFactory.class);
+
+ String jdbc = "";
+ String host = "";
+ String port = "";
+ String user = "";
+ String password = "";
+
+ public DBConnectionFactory(Properties currentProperty) {
+ for (Object k : currentProperty.keySet()) {
+ String key = (String) k;
+ String value = (String) currentProperty.get(key);
+
+ if ( key.equals("jdbc") ) {
+ this.jdbc = value.toLowerCase();
+ } else if ( key.equals("host") ) {
+ this.host = value;
+ } else if ( key.equals("password") ) {
+ this.password = value;
+ } else if ( key.equals("user") ) {
+ this.user = value;
+ } else if ( key.equals("port") ) {
+ this.port = value;
+ } else {
+ logger.info("else key : " + key);
+ }
+ }
+ }
+
+ public DBConnection getDBConnection() {
+ DBConnection currentConnection;
+
+ // add other jdbc
+ if ( jdbc.equals("mysql") ) {
+ currentConnection = new MysqlConnection(host, port, user, password);
+ } else {
+ currentConnection = null;
+ }
+
+ return currentConnection;
+ }
+}
+
diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
new file mode 100644
index 00000000000..1c0cf4f4ed4
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zeppelin.jdbc;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.zeppelin.interpreter.Interpreter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+import org.apache.zeppelin.scheduler.Scheduler;
+import org.apache.zeppelin.scheduler.SchedulerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * JDBC interpreter for Zeppelin.
+ *
+ * @author Hyungu Roh hyungu.roh@navercorp.com
+ *
+ */
+
+public class JDBCInterpreter extends Interpreter {
+ Logger logger = LoggerFactory.getLogger(JDBCInterpreter.class);
+ int commandTimeOut = 600000;
+
+ static {
+ Interpreter.register("jdbc", JDBCInterpreter.class.getName());
+ }
+
+ DBConnection jdbcConnection;
+
+ public JDBCInterpreter(Properties property) {
+ super(property);
+ Properties currentProperty = getProperty();
+ DBConnectionFactory DBFactory = new DBConnectionFactory(currentProperty);
+ this.jdbcConnection = DBFactory.getDBConnection();
+ }
+
+ @Override
+ public void open() {
+ jdbcConnection.open();
+ }
+
+ @Override
+ public void close() {
+ jdbcConnection.close();
+ }
+
+ @Override
+ public InterpreterResult interpret(String cmd, InterpreterContext contextInterpreter) {
+ logger.info("Run SQL command '" + cmd + "'");
+ return jdbcConnection.executeSql(cmd);
+ }
+
+ @Override
+ public void cancel(InterpreterContext context) {
+ jdbcConnection.cancel();
+ }
+
+ @Override
+ public FormType getFormType() {
+ return FormType.SIMPLE;
+ }
+
+ @Override
+ public int getProgress(InterpreterContext context) {
+ return 0;
+ }
+
+ @Override
+ public Scheduler getScheduler() {
+ return SchedulerFactory.singleton().createOrGetFIFOScheduler(
+ JDBCInterpreter.class.getName() + this.hashCode());
+ }
+
+ @Override
+ public List completion(String buf, int cursor) {
+ return null;
+ }
+
+}
diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/MysqlConnection.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/MysqlConnection.java
new file mode 100644
index 00000000000..10f6ef88804
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/MysqlConnection.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zeppelin.jdbc;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.commons.lang.StringUtils;
+
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.InterpreterResult.Code;
+
+import java.util.Vector;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * MysqlConnection
+ *
+ * @author Hyungu Roh hyungu.roh@navercorp.com
+ *
+ */
+
+public class MysqlConnection implements DBConnection {
+ Logger logger = LoggerFactory.getLogger(MysqlConnection.class);
+
+ String host;
+ String port;
+ String user;
+ String passwd;
+
+ public MysqlConnection(String host, String port, String user, String passwd) {
+ this.host = host;
+ this.port = port;
+ this.user = user;
+ this.passwd = passwd;
+ }
+
+ Connection mysqlConnection;
+ Exception exceptionOnConnect;
+ Statement currentStatement;
+ ResultSet resultSet;
+
+ @Override
+ public void open() {
+ String driver = "com.mysql.jdbc.Driver";
+ String url = "jdbc:mysql://";
+ url += host;
+ url += port != "" ? ":" + port : "";
+ url += "/?user=" + user;
+
+ try {
+ Class.forName(driver);
+ mysqlConnection = DriverManager.getConnection(url, user, passwd);
+ } catch ( ClassNotFoundException | SQLException e ) {
+ logger.error("Can not open connection", e);
+ exceptionOnConnect = e;
+ }
+ }
+
+ @Override
+ public void close() {
+ try {
+ mysqlConnection.close();
+ currentStatement.close();
+ resultSet.close();
+ } catch ( SQLException e ) {
+ logger.error("Can not close connection", e);
+ }
+
+ mysqlConnection = null;
+ exceptionOnConnect = null;
+ currentStatement = null;
+ resultSet = null;
+ }
+
+ @Override
+ public InterpreterResult executeSql(String sql) {
+ try {
+ if (exceptionOnConnect != null) {
+ return new InterpreterResult(Code.ERROR, exceptionOnConnect.getMessage());
+ }
+ currentStatement = mysqlConnection.createStatement();
+ StringBuilder msg = null;
+ if (StringUtils.containsIgnoreCase(sql, "EXPLAIN ")) {
+ //return the explain as text, make this visual explain later
+ msg = new StringBuilder();
+ }
+ else {
+ msg = new StringBuilder("%table ");
+ }
+ resultSet = currentStatement.executeQuery(sql);
+ try {
+ ResultSetMetaData md = resultSet.getMetaData();
+ for (int i = 1; i < md.getColumnCount() + 1; i++) {
+ if (i == 1) {
+ msg.append(md.getColumnName(i));
+ } else {
+ msg.append("\t" + md.getColumnName(i));
+ }
+ }
+ msg.append("\n");
+ while (resultSet.next()) {
+ for (int i = 1; i < md.getColumnCount() + 1; i++) {
+ msg.append(resultSet.getString(i) + "\t");
+ }
+ msg.append("\n");
+ }
+ } catch ( NullPointerException e ) {
+
+ }
+
+ InterpreterResult rett = new InterpreterResult(Code.SUCCESS, msg.toString());
+ return rett;
+ }
+ catch (SQLException ex) {
+ logger.error("Can not run " + sql, ex);
+ return new InterpreterResult(Code.ERROR, ex.getMessage());
+ }
+ }
+
+ @Override
+ public void cancel() {
+ if (currentStatement != null) {
+ try {
+ currentStatement.cancel();
+ }
+ catch (SQLException ex) {
+ }
+ finally {
+ currentStatement = null;
+ }
+ }
+ }
+}
+
diff --git a/pom.xml b/pom.xml
index 81fd00ecb40..d7f9424241f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,6 +92,7 @@
shell
hive
tajo
+ jdbc
zeppelin-web
zeppelin-server
zeppelin-distribution
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
index bbf46fc88d4..475b9dbe622 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
@@ -389,7 +389,8 @@ public static enum ConfVars {
+ "org.apache.zeppelin.angular.AngularInterpreter,"
+ "org.apache.zeppelin.shell.ShellInterpreter,"
+ "org.apache.zeppelin.hive.HiveInterpreter,"
- + "org.apache.zeppelin.tajo.TajoInterpreter"),
+ + "org.apache.zeppelin.tajo.TajoInterpreter,"
+ + "org.apache.zeppelin.jdbc.JDBCInterpreter"),
ZEPPELIN_INTERPRETER_DIR("zeppelin.interpreter.dir", "interpreter"),
ZEPPELIN_ENCODING("zeppelin.encoding", "UTF-8"),
ZEPPELIN_NOTEBOOK_DIR("zeppelin.notebook.dir", "notebook"),