Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/interpreter/jdbc.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ The JDBC interpreter properties are defined by default like below.
<tr>
<td>default.precode</td>
<td></td>
<td>Some SQL which executes while opening connection</td>
<td>Some SQL which executes every time after initialization of the interpreter (see [Binding mode](../manual/interpreters.md#interpreter-binding-mode))</td>
</tr>
<tr>
<td>default.completer.schemaFilters</td>
Expand Down
8 changes: 8 additions & 0 deletions docs/manual/interpreters.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,11 @@ interpreter.start()
The above code will start interpreter thread inside your process. Once the interpreter is started you can configure zeppelin to connect to RemoteInterpreter by checking **Connect to existing process** checkbox and then provide **Host** and **Port** on which interpreter process is listening as shown in the image below:

<img src="../assets/themes/zeppelin/img/screenshots/existing_interpreter.png" width="450px">

## Precode

Snippet of code (language of interpreter) that executes after initialization of the interpreter depends on [Binding mode](#interpreter-binding-mode). To configure add parameter with class of interpreter (`zeppelin.<ClassName>.precode`) except JDBCInterpreter ([JDBC precode](../interpreter/jdbc.md#usage-precode)).

<img src="../assets/themes/zeppelin/img/screenshots/interpreter_precode.png" width="800px">


22 changes: 10 additions & 12 deletions jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,6 @@ private Connection getConnectionFromPool(String url, String user, String propert

if (!getJDBCConfiguration(user).isConnectionInDBDriverPool(propertyKey)) {
createConnectionPool(url, user, propertyKey, properties);
try (Connection connection = DriverManager.getConnection(jdbcDriver)) {
executePrecode(connection, propertyKey);
}
}
return DriverManager.getConnection(jdbcDriver);
}
Expand Down Expand Up @@ -572,18 +569,19 @@ protected ArrayList<String> splitSqlQueries(String sql) {
return queries;
}

private void executePrecode(Connection connection, String propertyKey) throws SQLException {
String precode = getProperty(String.format(PRECODE_KEY_TEMPLATE, propertyKey));
if (StringUtils.isNotBlank(precode)) {
precode = StringUtils.trim(precode);
logger.debug("Run SQL precode '{}'", precode);
try (Statement statement = connection.createStatement()) {
statement.execute(precode);
if (!connection.getAutoCommit()) {
connection.commit();
public InterpreterResult executePrecode(InterpreterContext interpreterContext) {
InterpreterResult interpreterResult = null;
for (String propertyKey : basePropretiesMap.keySet()) {
String precode = getProperty(String.format("%s.precode", propertyKey));
if (StringUtils.isNotBlank(precode)) {
interpreterResult = executeSql(propertyKey, precode, interpreterContext);
if (interpreterResult.code() != Code.SUCCESS) {
break;
}
}
}

return interpreterResult;
}

private InterpreterResult executeSql(String propertyKey, String sql,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,17 +400,18 @@ public void testPrecode() throws SQLException, IOException {
properties.setProperty("default.url", getJdbcConnection());
properties.setProperty("default.user", "");
properties.setProperty("default.password", "");
properties.setProperty(DEFAULT_PRECODE, "SET @testVariable=1");
properties.setProperty(DEFAULT_PRECODE, "create table test_precode (id int); insert into test_precode values (1);");
JDBCInterpreter jdbcInterpreter = new JDBCInterpreter(properties);
jdbcInterpreter.open();
jdbcInterpreter.executePrecode(interpreterContext);

String sqlQuery = "select @testVariable";
String sqlQuery = "select *from test_precode";

InterpreterResult interpreterResult = jdbcInterpreter.interpret(sqlQuery, interpreterContext);

assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
assertEquals("@TESTVARIABLE\n1\n", interpreterResult.message().get(0).getData());
assertEquals("ID\n1\n", interpreterResult.message().get(0).getData());
}

@Test
Expand All @@ -420,13 +421,15 @@ public void testIncorrectPrecode() throws SQLException, IOException {
properties.setProperty("default.url", getJdbcConnection());
properties.setProperty("default.user", "");
properties.setProperty("default.password", "");
properties.setProperty(DEFAULT_PRECODE, "incorrect command");
properties.setProperty(DEFAULT_PRECODE, "select 1");
properties.setProperty("incorrect.driver", "org.h2.Driver");
properties.setProperty("incorrect.url", getJdbcConnection());
properties.setProperty("incorrect.user", "");
properties.setProperty("incorrect.password", "");
properties.setProperty(String.format(PRECODE_KEY_TEMPLATE, "incorrect"), "incorrect command");
JDBCInterpreter jdbcInterpreter = new JDBCInterpreter(properties);
jdbcInterpreter.open();

String sqlQuery = "select 1";

InterpreterResult interpreterResult = jdbcInterpreter.interpret(sqlQuery, interpreterContext);
InterpreterResult interpreterResult = jdbcInterpreter.executePrecode(interpreterContext);

assertEquals(InterpreterResult.Code.ERROR, interpreterResult.code());
assertEquals(InterpreterResult.Type.TEXT, interpreterResult.message().get(0).getType());
Expand All @@ -439,17 +442,18 @@ public void testPrecodeWithAnotherPrefix() throws SQLException, IOException {
properties.setProperty("anotherPrefix.url", getJdbcConnection());
properties.setProperty("anotherPrefix.user", "");
properties.setProperty("anotherPrefix.password", "");
properties.setProperty(String.format(PRECODE_KEY_TEMPLATE, "anotherPrefix"), "SET @testVariable=2");
properties.setProperty(String.format(PRECODE_KEY_TEMPLATE, "anotherPrefix"), "create table test_precode_2 (id int); insert into test_precode_2 values (2);");
JDBCInterpreter jdbcInterpreter = new JDBCInterpreter(properties);
jdbcInterpreter.open();
jdbcInterpreter.executePrecode(interpreterContext);

String sqlQuery = "(anotherPrefix) select @testVariable";
String sqlQuery = "(anotherPrefix) select *from test_precode_2";

InterpreterResult interpreterResult = jdbcInterpreter.interpret(sqlQuery, interpreterContext);

assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
assertEquals("@TESTVARIABLE\n2\n", interpreterResult.message().get(0).getData());
assertEquals("ID\n2\n", interpreterResult.message().get(0).getData());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ public abstract class Interpreter {
@ZeppelinApi
public abstract void close();

/**
* Run precode if exists.
*/
@ZeppelinApi
public InterpreterResult executePrecode(InterpreterContext interpreterContext) {
String simpleName = this.getClass().getSimpleName();
String precode = getProperty(String.format("zeppelin.%s.precode", simpleName));
if (StringUtils.isNotBlank(precode)) {
return interpret(precode, interpreterContext);
}
return null;
}

/**
* Run code and return result, in synchronous way.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.List;
import java.util.Properties;

import org.apache.zeppelin.interpreter.remote.RemoteInterpreter;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.apache.zeppelin.scheduler.Scheduler;

Expand Down Expand Up @@ -73,6 +72,11 @@ public synchronized void open() {
}
}

@Override
public InterpreterResult executePrecode(InterpreterContext interpreterContext) {
return intp.executePrecode(interpreterContext);
}

@Override
public void close() {
synchronized (intp) {
Expand Down Expand Up @@ -157,7 +161,7 @@ public void setInterpreterGroup(InterpreterGroup interpreterGroup) {
public void setClassloaderUrls(URL [] urls) {
intp.setClassloaderUrls(urls);
}

@Override
public void registerHook(String noteId, String event, String cmd) {
intp.registerHook(noteId, event, cmd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,19 +481,24 @@ protected Object jobRun() throws Throwable {
try {
InterpreterContext.set(context);

InterpreterResult result = null;

// Open the interpreter instance prior to calling interpret().
// This is necessary because the earliest we can register a hook
// is from within the open() method.
LazyOpenInterpreter lazy = (LazyOpenInterpreter) interpreter;
if (!lazy.isOpen()) {
lazy.open();
result = lazy.executePrecode(context);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't RemoteInterpreterServer.open() also call executePrecode()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it must be called once per instance of the interprete

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Leemoonsoo
works same as the previous jdbc precode.
case:
user: some_user
JDBC interpreter (per user)

  1. there is precode CREATE table IF NOT EXISTS tbl_#{user}
  2. user executes insert into tbm_some_user ...
    • execute precode
    • execute paragraph text
  3. user executes select *from tbm_some_user
    • execute paragraph text

Spark

  1. there is precode var someConst = 12 ...
  2. User executes var result = 1 + someConst
    • execute precode
    • execute paragraph text
  3. User executes var
result2 = 2 + someConts
print(result2)
  • execute only paragraph text

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explain.

Currently, unittest https://github.com/apache/zeppelin/pull/2221/files#diff-9c5e6fbaa5b23bc0192b4fedc12b2680R445 executes jdbcInterpreter.executePrecode(interpreterContext); manually after open().

Shell we have other unittest that does not call executePrecode() manually? so lazy.executePrecode in InterpreterServer can be verified.

zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterTest.java is one place the unittest actually creates RemoteInterpreter process and test against it. This place might be the place you can locate test for this feature.

Copy link
Copy Markdown
Contributor Author

@tinkoff-dwh tinkoff-dwh Apr 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Leemoonsoo
fix it, if I understand correctly your comment

ci green https://travis-ci.org/tinkoff-dwh/zeppelin/builds/225094590

}

// Add hooks to script from registry.
// Global scope first, followed by notebook scope
processInterpreterHooks(null);
processInterpreterHooks(context.getNoteId());
InterpreterResult result = interpreter.interpret(script, context);
if (result == null || result.code() == Code.SUCCESS) {
// Add hooks to script from registry.
// Global scope first, followed by notebook scope
processInterpreterHooks(null);
processInterpreterHooks(context.getNoteId());
result = interpreter.interpret(script, context);
}

// data from context.out is prepended to InterpreterResult if both defined
context.out.flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,79 @@ public void testRemoteInterperterCall() throws TTransportException, IOException

}

@Test
public void testExecuteIncorrectPrecode() throws TTransportException, IOException {
Properties p = new Properties();
p.put("zeppelin.MockInterpreterA.precode", "fail test");
intpGroup.put("note", new LinkedList<Interpreter>());

RemoteInterpreter intpA = createMockInterpreterA(p);

intpGroup.get("note").add(intpA);

intpA.setInterpreterGroup(intpGroup);

RemoteInterpreterProcess process = intpA.getInterpreterProcess();

intpA.open();

InterpreterResult result = intpA.interpret("1",
new InterpreterContext(
"note",
"id",
null,
"title",
"text",
new AuthenticationInfo(),
new HashMap<String, Object>(),
new GUI(),
new AngularObjectRegistry(intpGroup.getId(), null),
new LocalResourcePool("pool1"),
new LinkedList<InterpreterContextRunner>(), null));



intpA.close();
assertEquals(Code.ERROR, result.code());
}

@Test
public void testExecuteCorrectPrecode() throws TTransportException, IOException {
Properties p = new Properties();
p.put("zeppelin.MockInterpreterA.precode", "2");
intpGroup.put("note", new LinkedList<Interpreter>());

RemoteInterpreter intpA = createMockInterpreterA(p);

intpGroup.get("note").add(intpA);

intpA.setInterpreterGroup(intpGroup);

RemoteInterpreterProcess process = intpA.getInterpreterProcess();

intpA.open();

InterpreterResult result = intpA.interpret("1",
new InterpreterContext(
"note",
"id",
null,
"title",
"text",
new AuthenticationInfo(),
new HashMap<String, Object>(),
new GUI(),
new AngularObjectRegistry(intpGroup.getId(), null),
new LocalResourcePool("pool1"),
new LinkedList<InterpreterContextRunner>(), null));



intpA.close();
assertEquals(Code.SUCCESS, result.code());
assertEquals("1", result.message().get(0).getData());
}

@Test
public void testRemoteInterperterErrorStatus() throws TTransportException, IOException {
Properties p = new Properties();
Expand Down