diff --git a/docs/interpreter/jdbc.md b/docs/interpreter/jdbc.md
index 44f8aab9002..ae501c05b36 100644
--- a/docs/interpreter/jdbc.md
+++ b/docs/interpreter/jdbc.md
@@ -192,6 +192,10 @@ There are more JDBC interpreter properties you can specify like below.
default.jceks.credentialKey |
jceks credential key |
+
+ | zeppelin.jdbc.interpolation |
+ Enables ZeppelinContext variable interpolation into paragraph text. Default value is false. |
+
You can also add more properties by using this [method](http://docs.oracle.com/javase/7/docs/api/java/sql/DriverManager.html#getConnection%28java.lang.String,%20java.util.Properties%29).
@@ -240,7 +244,7 @@ You can leverage [Zeppelin Dynamic Form](../usage/dynamic_form/intro.html) insid
%jdbc_interpreter_name
SELECT name, country, performer
FROM demo.performers
-WHERE name='{{"{{performer=Sheryl Crow|Doof|Fanfarlo|Los Paranoia"}}}}'
+WHERE name='${performer=Sheryl Crow|Doof|Fanfarlo|Los Paranoia}'
```
### Usage *precode*
You can set *precode* for each data source. Code runs once while opening the connection.
@@ -724,5 +728,27 @@ Before Adding one of the below dependencies, check the Phoenix version first.
[Maven Repository: org.apache.tajo:tajo-jdbc](https://mvnrepository.com/artifact/org.apache.tajo/tajo-jdbc)
+## Object Interpolation
+The JDBC interpreter also supports interpolation of `ZeppelinContext` objects into the paragraph text.
+The following example shows one use of this facility:
+
+####In Scala cell:
+```
+z.put("country_code", "KR")
+ // ...
+```
+
+####In later JDBC cell:
+```sql
+%jdbc_interpreter_name
+ select * from patents_list where
+ priority_country = '{country_code}' and filing_date like '2015-%'
+```
+
+Object interpolation is disabled by default, and can be enabled for all instances of the JDBC interpreter by
+setting the value of the property `zeppelin.jdbc.interpolation` to `true` (see _More Properties_ above).
+More details of this feature can be found in the Spark interpreter documentation under
+[Object Interpolation](spark.html#object-interpolation)
+
## Bug reporting
If you find a bug using JDBC interpreter, please create a [JIRA](https://issues.apache.org/jira/browse/ZEPPELIN) ticket.
diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
index 56afe6f00f4..c48106fbb68 100644
--- a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
+++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
@@ -782,7 +782,9 @@ private String replaceReservedChars(String str) {
}
@Override
- public InterpreterResult interpret(String cmd, InterpreterContext contextInterpreter) {
+ public InterpreterResult interpret(String originalCmd, InterpreterContext contextInterpreter) {
+ String cmd = Boolean.parseBoolean(getProperty("zeppelin.jdbc.interpolation")) ?
+ interpolate(originalCmd, contextInterpreter.getResourcePool()) : originalCmd;
logger.debug("Run SQL command '{}'", cmd);
String propertyKey = getPropertyKey(cmd);
diff --git a/jdbc/src/main/resources/interpreter-setting.json b/jdbc/src/main/resources/interpreter-setting.json
index abbc1cfd9c9..287cf5a8d97 100644
--- a/jdbc/src/main/resources/interpreter-setting.json
+++ b/jdbc/src/main/resources/interpreter-setting.json
@@ -101,6 +101,13 @@
"defaultValue": "",
"description": "Kerberos principal",
"type": "string"
+ },
+ "zeppelin.jdbc.interpolation": {
+ "envName": null,
+ "propertyName": "zeppelin.jdbc.interpolation",
+ "defaultValue": false,
+ "description": "Enable ZeppelinContext variable interpolation into paragraph text",
+ "type": "checkbox"
}
},
"editor": {
diff --git a/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterInterpolationTest.java b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterInterpolationTest.java
new file mode 100644
index 00000000000..fe7bc80a179
--- /dev/null
+++ b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterInterpolationTest.java
@@ -0,0 +1,181 @@
+/**
+ * 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 com.mockrunner.jdbc.BasicJDBCTestCaseAdapter;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.resource.LocalResourcePool;
+import org.apache.zeppelin.resource.ResourcePool;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.Statement;
+import java.util.Properties;
+
+import static java.lang.String.format;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * JDBC interpreter Z-variable interpolation unit tests.
+ */
+public class JDBCInterpreterInterpolationTest extends BasicJDBCTestCaseAdapter {
+
+ private static String jdbcConnection;
+ private InterpreterContext interpreterContext;
+ private ResourcePool resourcePool;
+
+ private String getJdbcConnection() throws IOException {
+ if (null == jdbcConnection) {
+ Path tmpDir = Files.createTempDirectory("h2-test-");
+ tmpDir.toFile().deleteOnExit();
+ jdbcConnection = format("jdbc:h2:%s", tmpDir);
+ }
+ return jdbcConnection;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ Class.forName("org.h2.Driver");
+ Connection connection = DriverManager.getConnection(getJdbcConnection());
+ Statement statement = connection.createStatement();
+ statement.execute(
+ "DROP TABLE IF EXISTS test_table; " +
+ "CREATE TABLE test_table(id varchar(255), name varchar(255));");
+
+ Statement insertStatement = connection.createStatement();
+ insertStatement.execute("insert into test_table(id, name) values " +
+ "('pro', 'processor')," +
+ "('mem', 'memory')," +
+ "('key', 'keyboard')," +
+ "('mou', 'mouse');");
+ resourcePool = new LocalResourcePool("JdbcInterpolationTest");
+
+ interpreterContext = new InterpreterContext("", "1", null, "", "",
+ new AuthenticationInfo("testUser"), null, null, null, null, resourcePool, null, null);
+ }
+
+ @Test
+ public void testEnableDisableProperty() throws IOException {
+ Properties properties = new Properties();
+ properties.setProperty("common.max_count", "1000");
+ properties.setProperty("common.max_retry", "3");
+ properties.setProperty("default.driver", "org.h2.Driver");
+ properties.setProperty("default.url", getJdbcConnection());
+ properties.setProperty("default.user", "");
+ properties.setProperty("default.password", "");
+
+ resourcePool.put("zid", "mem");
+ String sqlQuery = "select * from test_table where id = '{zid}'";
+
+ //
+ // Empty result expected because "zeppelin.jdbc.interpolation" is false by default ...
+ //
+ JDBCInterpreter t = new JDBCInterpreter(properties);
+ t.open();
+ InterpreterResult interpreterResult = t.interpret(sqlQuery, interpreterContext);
+ assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
+ assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
+ assertEquals(1, interpreterResult.message().size());
+ assertEquals("ID\tNAME\n", interpreterResult.message().get(0).getData());
+
+ //
+ // 1 result expected because "zeppelin.jdbc.interpolation" set to "true" ...
+ //
+ properties.setProperty("zeppelin.jdbc.interpolation", "true");
+ t = new JDBCInterpreter(properties);
+ t.open();
+ interpreterResult = t.interpret(sqlQuery, interpreterContext);
+ assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
+ assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
+ assertEquals(1, interpreterResult.message().size());
+ assertEquals("ID\tNAME\nmem\tmemory\n",
+ interpreterResult.message().get(0).getData());
+ }
+
+ @Test
+ public void testNormalQueryInterpolation() throws IOException {
+ Properties properties = new Properties();
+ properties.setProperty("common.max_count", "1000");
+ properties.setProperty("common.max_retry", "3");
+ properties.setProperty("default.driver", "org.h2.Driver");
+ properties.setProperty("default.url", getJdbcConnection());
+ properties.setProperty("default.user", "");
+ properties.setProperty("default.password", "");
+
+ properties.setProperty("zeppelin.jdbc.interpolation", "true");
+
+ JDBCInterpreter t = new JDBCInterpreter(properties);
+ t.open();
+
+ //
+ // Empty result expected because "kbd" is not defined ...
+ //
+ String sqlQuery = "select * from test_table where id = '{kbd}'";
+ InterpreterResult interpreterResult = t.interpret(sqlQuery, interpreterContext);
+ assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
+ assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
+ assertEquals(1, interpreterResult.message().size());
+ assertEquals("ID\tNAME\n", interpreterResult.message().get(0).getData());
+
+ resourcePool.put("itemId", "key");
+
+ //
+ // 1 result expected because z-variable 'item' is 'key' ...
+ //
+ sqlQuery = "select * from test_table where id = '{itemId}'";
+ interpreterResult = t.interpret(sqlQuery, interpreterContext);
+ assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
+ assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
+ assertEquals(1, interpreterResult.message().size());
+ assertEquals("ID\tNAME\nkey\tkeyboard\n",
+ interpreterResult.message().get(0).getData());
+ }
+
+ @Test
+ public void testEscapedInterpolationPattern() throws IOException {
+ Properties properties = new Properties();
+ properties.setProperty("common.max_count", "1000");
+ properties.setProperty("common.max_retry", "3");
+ properties.setProperty("default.driver", "org.h2.Driver");
+ properties.setProperty("default.url", getJdbcConnection());
+ properties.setProperty("default.user", "");
+ properties.setProperty("default.password", "");
+
+ properties.setProperty("zeppelin.jdbc.interpolation", "true");
+
+ JDBCInterpreter t = new JDBCInterpreter(properties);
+ t.open();
+
+ //
+ // 2 rows (keyboard and mouse) expected when searching names with 2 consecutive vowels ...
+ // The 'regexp' keyword is specific to H2 database
+ //
+ String sqlQuery = "select * from test_table where name regexp '[aeiou]{{2}}'";
+ InterpreterResult interpreterResult = t.interpret(sqlQuery, interpreterContext);
+ assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
+ assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
+ assertEquals(1, interpreterResult.message().size());
+ assertEquals("ID\tNAME\nkey\tkeyboard\nmou\tmouse\n",
+ interpreterResult.message().get(0).getData());
+ }
+
+}