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
78 changes: 75 additions & 3 deletions jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ public class JDBCInterpreter extends Interpreter {
private final String CONCURRENT_EXECUTION_COUNT = "zeppelin.jdbc.concurrent.max_connection";
private final String DBCP_STRING = "jdbc:apache:commons:dbcp:";

private static final String[] TABLE_TYPES = { "TABLE", "VIEW", "SYSTEM TABLE",
"GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM" };
private static final String METADATA_KEYWORD = "explore";

private final HashMap<String, Properties> basePropretiesMap;
private final HashMap<String, JDBCUserConfigurations> jdbcUserConfigurationsMap;
private final Map<String, SqlCompleter> propertyKeySqlCompleterMap;
Expand Down Expand Up @@ -512,6 +516,67 @@ private InterpreterResult executeSql(String propertyKey, String sql,
}
}

private InterpreterResult getMetaData(String propertyKey,
String cmd, InterpreterContext interpreterContext) {
Connection connection;
String user = interpreterContext.getAuthenticationInfo().getUser();
DatabaseMetaData dataBaseMetaData;
ResultSet resultSet = null;
String tableName = null;
String results;

if (cmd.split(" +").length > 1) {
tableName = cmd.split(" +")[1];
}

try {
connection = getConnection(propertyKey, interpreterContext);

if (connection == null) {
return new InterpreterResult(Code.ERROR, "Prefix not found.");
}

try {
dataBaseMetaData = connection.getMetaData();
if (tableName == null) {
// if a table name is supplied get table metadata
resultSet = dataBaseMetaData.getTables(null, null, "%", TABLE_TYPES);
} else {
// if not, get database metadata
resultSet = dataBaseMetaData.getColumns(null, null, tableName, null);
}
results = getResults(resultSet, true);
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) { /*ignored*/ }
}
if (connection != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

connection can't be null here because we return at line 533 in case of null

try {
connection.close();
} catch (SQLException e) { /*ignored*/ }
}
}
return new InterpreterResult(Code.SUCCESS, results);

} catch (Exception e) {
logger.error("Cannot fetch metadata.", e);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
e.printStackTrace(ps);
String errorMsg = new String(baos.toByteArray(), StandardCharsets.UTF_8);
Copy link
Contributor

Choose a reason for hiding this comment

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

As I remember, org.apache.commons.lang3.exception.ExceptionUtils#getStackTrace does the same thing


try {
closeDBPool(user, propertyKey);
} catch (SQLException e1) {
e1.printStackTrace();
Copy link
Contributor

Choose a reason for hiding this comment

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

It's better to use logger, not to write to System.err

Copy link
Member

Choose a reason for hiding this comment

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

Huge 👍 for using Logger here, as in the rest of the project

}

return new InterpreterResult(Code.ERROR, errorMsg);
}
}

/**
* For %table response replace Tab and Newline characters from the content.
*/
Expand All @@ -524,7 +589,7 @@ private String replaceReservedChars(String str) {

@Override
public InterpreterResult interpret(String cmd, InterpreterContext contextInterpreter) {
logger.info("Run SQL command '{}'", cmd);
logger.info("Run Interpreter command '{}'", cmd);
String propertyKey = getPropertyKey(cmd);

if (null != propertyKey && !propertyKey.equals(DEFAULT_KEY)) {
Expand All @@ -533,8 +598,15 @@ public InterpreterResult interpret(String cmd, InterpreterContext contextInterpr

cmd = cmd.trim();

logger.info("PropertyKey: {}, SQL command: '{}'", propertyKey, cmd);
return executeSql(propertyKey, cmd, contextInterpreter);
if (cmd.split(" ")[0].toLowerCase().equals(METADATA_KEYWORD)) {
// if the command starts with the METADATA_KEYWORD, call getMetaData
logger.info("PropertyKey: {}, MetaData command: '{}'", propertyKey, cmd);
return getMetaData(propertyKey, cmd, contextInterpreter);
} else {
// otherwise all executeSql
logger.info("PropertyKey: {}, SQL command: '{}'", propertyKey, cmd);
return executeSql(propertyKey, cmd, contextInterpreter);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,67 @@ public void testSelectQueryMaxResult() throws SQLException, IOException {
assertEquals("ID\tNAME\na\ta_name\n", interpreterResult.message().get(0).getData());
}

@Test
public void testConnectionMetaData() throws SQLException, IOException {

Properties properties = new Properties();
properties.setProperty("common.max_count", "1");
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", "");
JDBCInterpreter t = new JDBCInterpreter(properties);
t.open();

String command = "explore";

InterpreterResult interpreterResult = t.interpret(command, interpreterContext);

assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());

String testOutput = interpreterResult.message().get(0).getData().replaceAll("H2-TEST-([0-9]+)",
"H2-TEST-1");

assertEquals("TABLE_CATALOG\tTABLE_SCHEMA\tTABLE_NAME\tTABLE_TYPE\tREMARKS\tTYPE_NAME\tTYPE_NAME\t" +
"TYPE_NAME\tTYPE_NAME\tTYPE_NAME\tSQL\nH2-TEST-1\tINFORMATION_SCHEMA\t" +
"CATALOGS\tSYSTEM TABLE\t\tnull\tnull\tnull\tnull\tnull\tnull\n", testOutput);
}

@Test
public void testTableMetaData() throws SQLException, IOException {

Properties properties = new Properties();
properties.setProperty("common.max_count", "1");
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", "");
JDBCInterpreter t = new JDBCInterpreter(properties);
t.open();

String command = "explore TEST_TABLE";

InterpreterResult interpreterResult = t.interpret(command, interpreterContext);

assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());

System.out.println("Printed:\n" + interpreterResult.message().get(0).getData());
String testOutput = interpreterResult.message().get(0).getData().replaceAll("H2-TEST-([0-9]+)",
"H2-TEST-1");

assertEquals("TABLE_CATALOG\tTABLE_SCHEMA\tTABLE_NAME\tCOLUMN_NAME\tDATA_TYPE\tTYPE_NAME\t" +
"CHARACTER_MAXIMUM_LENGTH\tCHARACTER_MAXIMUM_LENGTH\tNUMERIC_SCALE\tNUMERIC_PRECISION_RADIX" +
"\tNULLABLE\tREMARKS\tCOLUMN_DEFAULT\tDATA_TYPE\tSQL_DATETIME_SUB\tCHARACTER_OCTET_LENGTH\t" +
"ORDINAL_POSITION\tIS_NULLABLE\tSCOPE_CATALOG\tSCOPE_SCHEMA\tSCOPE_TABLE\tSOURCE_DATA_TYPE\t" +
"IS_AUTOINCREMENT\tSCOPE_CATLOG\nH2-TEST-1\tPUBLIC\tTEST_TABLE\tID\t12\t" +
"VARCHAR\t255\t255\t0\t10\t1\t\tnull\t12\t0\t255\t1\tYES\tnull\tnull\tnull\tnull\tNO\tnull\n"
, testOutput);
}

@Test
public void concurrentSettingTest() {
Properties properties = new Properties();
Expand Down