mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
resolved conflict
This commit is contained in:
commit
e5465a5a0e
10 changed files with 883 additions and 1 deletions
|
|
@ -105,7 +105,7 @@
|
|||
|
||||
<property>
|
||||
<name>zeppelin.interpreters</name>
|
||||
<value>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.flink.FlinkInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter,org.apache.zeppelin.phoenix.PhoenixInterpreter,org.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,org.apache.zeppelin.scalding.ScaldingInterpreter,org.apache.zeppelin.tachyon.TachyonInterpreter</value>
|
||||
<value>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.flink.FlinkInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.postgresql.PostgreSqlInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter,org.apache.zeppelin.phoenix.PhoenixInterpreter,org.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,org.apache.zeppelin.scalding.ScaldingInterpreter,org.apache.zeppelin.tachyon.TachyonInterpreter</value>
|
||||
<description>Comma separated interpreter configurations. First interpreter become a default</description>
|
||||
</property>
|
||||
|
||||
|
|
|
|||
1
pom.xml
1
pom.xml
|
|
@ -94,6 +94,7 @@
|
|||
<module>hive</module>
|
||||
<module>tachyon</module>
|
||||
<module>phoenix</module>
|
||||
<module>postgresql</module>
|
||||
<module>jdbc</module>
|
||||
<module>tajo</module>
|
||||
<module>flink</module>
|
||||
|
|
|
|||
9
postgresql/README.md
Normal file
9
postgresql/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
## PostgreSQL, HAWQ and Greenplum Interpreter for Apache Zeppelin
|
||||
|
||||
This interpreter supports the following SQL engines:
|
||||
* [PostgreSQL](http://www.postgresql.org/) - OSS, Object-relational database management system (ORDBMS)
|
||||
* [Apache HAWQ](http://pivotal.io/big-data/pivotal-hawq) - Powerful [Open Source](https://wiki.apache.org/incubator/HAWQProposal) SQL-On-Hadoop engine.
|
||||
* [Greenplum](http://pivotal.io/big-data/pivotal-greenplum-database) - MPP database built on open source PostgreSQL.
|
||||
|
||||
The official documentation: [PostgreSQL, HAWQ](https://zeppelin.incubator.apache.org/docs/interpreter/postgresql.html)
|
||||
|
||||
162
postgresql/pom.xml
Normal file
162
postgresql/pom.xml
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>zeppelin</artifactId>
|
||||
<groupId>org.apache.zeppelin</groupId>
|
||||
<version>0.6.0-incubating-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.apache.zeppelin</groupId>
|
||||
<artifactId>zeppelin-postgresql</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.6.0-incubating-SNAPSHOT</version>
|
||||
<name>Zeppelin: PostgreSQL interpreter</name>
|
||||
<url>http://www.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<postgresql.version>9.4-1201-jdbc41</postgresql.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.zeppelin</groupId>
|
||||
<artifactId>zeppelin-interpreter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.12.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mockrunner</groupId>
|
||||
<artifactId>mockrunner-jdbc</artifactId>
|
||||
<version>1.0.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/../../interpreter/psql</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>false</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
<includeScope>runtime</includeScope>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-artifact</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/../../interpreter/psql</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>false</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
<includeScope>runtime</includeScope>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>${project.artifactId}</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>${project.packaging}</type>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
/**
|
||||
* 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.postgresql;
|
||||
|
||||
/*
|
||||
* This source file is based on code taken from SQLLine 1.0.2 See SQLLine notice in LICENSE
|
||||
*/
|
||||
import static org.apache.commons.lang.StringUtils.isBlank;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeSet;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jline.console.completer.ArgumentCompleter.ArgumentList;
|
||||
import jline.console.completer.ArgumentCompleter.WhitespaceArgumentDelimiter;
|
||||
import jline.console.completer.StringsCompleter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Sets.SetView;
|
||||
|
||||
/**
|
||||
* SQL auto complete functionality for the PostgreSqlInterpreter.
|
||||
*/
|
||||
public class SqlCompleter extends StringsCompleter {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(SqlCompleter.class);
|
||||
|
||||
/**
|
||||
* Delimiter that can split SQL statement in keyword list
|
||||
*/
|
||||
private WhitespaceArgumentDelimiter sqlDelimiter = new WhitespaceArgumentDelimiter() {
|
||||
|
||||
private Pattern pattern = Pattern.compile("[\\.:;,]");
|
||||
|
||||
@Override
|
||||
public boolean isDelimiterChar(CharSequence buffer, int pos) {
|
||||
return pattern.matcher("" + buffer.charAt(pos)).matches()
|
||||
|| super.isDelimiterChar(buffer, pos);
|
||||
}
|
||||
};
|
||||
|
||||
private Set<String> modelCompletions = new HashSet<String>();
|
||||
|
||||
public SqlCompleter(Set<String> allCompletions, Set<String> dataModelCompletions) {
|
||||
super(allCompletions);
|
||||
this.modelCompletions = dataModelCompletions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int complete(String buffer, int cursor, List<CharSequence> candidates) {
|
||||
|
||||
if (isBlank(buffer) || (cursor > buffer.length() + 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The delimiter breaks the buffer into separate words (arguments), separated by the
|
||||
// white spaces.
|
||||
ArgumentList argumentList = sqlDelimiter.delimit(buffer, cursor);
|
||||
String argument = argumentList.getCursorArgument();
|
||||
// cursor in the selected argument
|
||||
int argumentPosition = argumentList.getArgumentPosition();
|
||||
|
||||
if (isBlank(argument)) {
|
||||
int argumentsCount = argumentList.getArguments().length;
|
||||
if (argumentsCount <= 0 || ((buffer.length() + 2) < cursor)
|
||||
|| sqlDelimiter.isDelimiterChar(buffer, cursor - 2)) {
|
||||
return -1;
|
||||
}
|
||||
argument = argumentList.getArguments()[argumentsCount - 1];
|
||||
argumentPosition = argument.length();
|
||||
}
|
||||
|
||||
int complete = super.complete(argument, argumentPosition, candidates);
|
||||
|
||||
logger.debug("complete:" + complete + ", size:" + candidates.size());
|
||||
|
||||
return complete;
|
||||
}
|
||||
|
||||
public void updateDataModelMetaData(Connection connection) {
|
||||
|
||||
try {
|
||||
Set<String> newModelCompletions = getDataModelMetadataCompletions(connection);
|
||||
logger.debug("New model metadata is:" + Joiner.on(',').join(newModelCompletions));
|
||||
|
||||
// Sets.difference(set1, set2) - returned set contains all elements that are contained by set1
|
||||
// and not contained by set2. set2 may also contain elements not present in set1; these are
|
||||
// simply ignored.
|
||||
SetView<String> removedCompletions = Sets.difference(modelCompletions, newModelCompletions);
|
||||
logger.debug("Removed Model Completions: " + Joiner.on(',').join(removedCompletions));
|
||||
this.getStrings().removeAll(removedCompletions);
|
||||
|
||||
SetView<String> newCompletions = Sets.difference(newModelCompletions, modelCompletions);
|
||||
logger.debug("New Completions: " + Joiner.on(',').join(newCompletions));
|
||||
this.getStrings().addAll(newCompletions);
|
||||
|
||||
modelCompletions = newModelCompletions;
|
||||
|
||||
} catch (SQLException e) {
|
||||
logger.error("Failed to update the metadata conmpletions", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getSqlKeywordsCompletions(Connection connection) throws IOException,
|
||||
SQLException {
|
||||
|
||||
// Add the default SQL completions
|
||||
String keywords =
|
||||
new BufferedReader(new InputStreamReader(
|
||||
SqlCompleter.class.getResourceAsStream("/ansi.sql.keywords"))).readLine();
|
||||
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
|
||||
// Add the driver specific SQL completions
|
||||
String driverSpecificKeywords =
|
||||
"/" + metaData.getDriverName().replace(" ", "-").toLowerCase() + "-sql.keywords";
|
||||
|
||||
logger.info("JDBC DriverName:" + driverSpecificKeywords);
|
||||
|
||||
if (SqlCompleter.class.getResource(driverSpecificKeywords) != null) {
|
||||
String driverKeywords =
|
||||
new BufferedReader(new InputStreamReader(
|
||||
SqlCompleter.class.getResourceAsStream(driverSpecificKeywords))).readLine();
|
||||
keywords += "," + driverKeywords.toUpperCase();
|
||||
}
|
||||
|
||||
Set<String> completions = new TreeSet<String>();
|
||||
|
||||
|
||||
// Add the keywords from the current JDBC connection
|
||||
try {
|
||||
keywords += "," + metaData.getSQLKeywords();
|
||||
} catch (Exception e) {
|
||||
logger.debug("fail to get SQL key words from database metadata: " + e, e);
|
||||
}
|
||||
try {
|
||||
keywords += "," + metaData.getStringFunctions();
|
||||
} catch (Exception e) {
|
||||
logger.debug("fail to get string function names from database metadata: " + e, e);
|
||||
}
|
||||
try {
|
||||
keywords += "," + metaData.getNumericFunctions();
|
||||
} catch (Exception e) {
|
||||
logger.debug("fail to get numeric function names from database metadata: " + e, e);
|
||||
}
|
||||
try {
|
||||
keywords += "," + metaData.getSystemFunctions();
|
||||
} catch (Exception e) {
|
||||
logger.debug("fail to get system function names from database metadata: " + e, e);
|
||||
}
|
||||
try {
|
||||
keywords += "," + metaData.getTimeDateFunctions();
|
||||
} catch (Exception e) {
|
||||
logger.debug("fail to get time date function names from database metadata: " + e, e);
|
||||
}
|
||||
|
||||
// Also allow lower-case versions of all the keywords
|
||||
keywords += "," + keywords.toLowerCase();
|
||||
|
||||
StringTokenizer tok = new StringTokenizer(keywords, ", ");
|
||||
while (tok.hasMoreTokens()) {
|
||||
completions.add(tok.nextToken());
|
||||
}
|
||||
|
||||
return completions;
|
||||
}
|
||||
|
||||
public static Set<String> getDataModelMetadataCompletions(Connection connection)
|
||||
throws SQLException {
|
||||
Set<String> completions = new TreeSet<String>();
|
||||
getColumnNames(connection.getMetaData(), completions);
|
||||
getSchemaNames(connection.getMetaData(), completions);
|
||||
return completions;
|
||||
}
|
||||
|
||||
private static void getColumnNames(DatabaseMetaData meta, Set<String> names) throws SQLException {
|
||||
|
||||
try {
|
||||
ResultSet columns = meta.getColumns(meta.getConnection().getCatalog(), null, "%", "%");
|
||||
try {
|
||||
|
||||
while (columns.next()) {
|
||||
// Add the following strings: (1) column name, (2) table name
|
||||
String name = columns.getString("TABLE_NAME");
|
||||
if (!isBlank(name)) {
|
||||
names.add(name);
|
||||
names.add(columns.getString("COLUMN_NAME"));
|
||||
// names.add(columns.getString("TABLE_NAME") + "." + columns.getString("COLUMN_NAME"));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
columns.close();
|
||||
}
|
||||
|
||||
logger.debug(Joiner.on(',').join(names));
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to retrieve the column name", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void getSchemaNames(DatabaseMetaData meta, Set<String> names) throws SQLException {
|
||||
|
||||
try {
|
||||
ResultSet schemas = meta.getSchemas();
|
||||
try {
|
||||
while (schemas.next()) {
|
||||
String schemaName = schemas.getString("TABLE_SCHEM");
|
||||
if (!isBlank(schemaName)) {
|
||||
names.add(schemaName + ".");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
schemas.close();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to retrieve the column name", t);
|
||||
}
|
||||
}
|
||||
|
||||
// test purpose only
|
||||
WhitespaceArgumentDelimiter getSqlDelimiter() {
|
||||
return this.sqlDelimiter;
|
||||
}
|
||||
}
|
||||
1
postgresql/src/main/resources/ansi.sql.keywords
Normal file
1
postgresql/src/main/resources/ansi.sql.keywords
Normal file
|
|
@ -0,0 +1 @@
|
|||
ABSOLUTE,ACTION,ADD,ALL,ALLOCATE,ALTER,AND,ANY,ARE,AS,ASC,ASSERTION,AT,AUTHORIZATION,AVG,BEGIN,BETWEEN,BIT,BIT_LENGTH,BOTH,BY,CASCADE,CASCADED,CASE,CAST,CATALOG,CHAR,CHARACTER,CHAR_LENGTH,CHARACTER_LENGTH,CHECK,CLOSE,CLUSTER,COALESCE,COLLATE,COLLATION,COLUMN,COMMIT,CONNECT,CONNECTION,CONSTRAINT,CONSTRAINTS,CONTINUE,CONVERT,CORRESPONDING,COUNT,CREATE,CROSS,CURRENT,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_USER,CURSOR,DATE,DAY,DEALLOCATE,DEC,DECIMAL,DECLARE,DEFAULT,DEFERRABLE,DEFERRED,DELETE,DESC,DESCRIBE,DESCRIPTOR,DIAGNOSTICS,DISCONNECT,DISTINCT,DOMAIN,DOUBLE,DROP,ELSE,END,END-EXEC,ESCAPE,EXCEPT,EXCEPTION,EXEC,EXECUTE,EXISTS,EXTERNAL,EXTRACT,FALSE,FETCH,FIRST,FLOAT,FOR,FOREIGN,FOUND,FROM,FULL,GET,GLOBAL,GO,GOTO,GRANT,GROUP,HAVING,HOUR,IDENTITY,IMMEDIATE,IN,INDICATOR,INITIALLY,INNER,INPUT,INSENSITIVE,INSERT,INT,INTEGER,INTERSECT,INTERVAL,INTO,IS,ISOLATION,JOIN,KEY,LANGUAGE,LAST,LEADING,LEFT,LEVEL,LIKE,LOCAL,LOWER,MATCH,MAX,MIN,MINUTE,MODULE,MONTH,NAMES,NATIONAL,NATURAL,NCHAR,NEXT,NO,NOT,NULL,NULLIF,NUMERIC,OCTET_LENGTH,OF,ON,ONLY,OPEN,OPTION,OR,ORDER,OUTER,OUTPUT,OVERLAPS,OVERWRITE,PAD,PARTIAL,PARTITION,POSITION,PRECISION,PREPARE,PRESERVE,PRIMARY,PRIOR,PRIVILEGES,PROCEDURE,PUBLIC,READ,REAL,REFERENCES,RELATIVE,RESTRICT,REVOKE,RIGHT,ROLLBACK,ROWS,SCHEMA,SCROLL,SECOND,SECTION,SELECT,SESSION,SESSION_USER,SET,SIZE,SMALLINT,SOME,SPACE,SQL,SQLCODE,SQLERROR,SQLSTATE,SUBSTRING,SUM,SYSTEM_USER,TABLE,TEMPORARY,THEN,TIME,TIMESTAMP,TIMEZONE_HOUR,TIMEZONE_MINUTE,TO,TRAILING,TRANSACTION,TRANSLATE,TRANSLATION,TRIM,TRUE,UNION,UNIQUE,UNKNOWN,UPDATE,UPPER,USAGE,USER,USING,VALUE,VALUES,VARCHAR,VARYING,VIEW,WHEN,WHENEVER,WHERE,WITH,WORK,WRITE,YEAR,ZONE,ADA,C,CATALOG_NAME,CHARACTER_SET_CATALOG,CHARACTER_SET_NAME,CHARACTER_SET_SCHEMA,CLASS_ORIGIN,COBOL,COLLATION_CATALOG,COLLATION_NAME,COLLATION_SCHEMA,COLUMN_NAME,COMMAND_FUNCTION,COMMITTED,CONDITION_NUMBER,CONNECTION_NAME,CONSTRAINT_CATALOG,CONSTRAINT_NAME,CONSTRAINT_SCHEMA,CURSOR_NAME,DATA,DATETIME_INTERVAL_CODE,DATETIME_INTERVAL_PRECISION,DYNAMIC_FUNCTION,FORTRAN,LENGTH,MESSAGE_LENGTH,MESSAGE_OCTET_LENGTH,MESSAGE_TEXT,MORE,MUMPS,NAME,NULLABLE,NUMBER,PASCAL,PLI,REPEATABLE,RETURNED_LENGTH,RETURNED_OCTET_LENGTH,RETURNED_SQLSTATE,ROW_COUNT,SCALE,SCHEMA_NAME,SERIALIZABLE,SERVER_NAME,SUBCLASS_ORIGIN,TABLE_NAME,TYPE,UNCOMMITTED,UNNAMED,LIMIT
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,260 @@
|
|||
/**
|
||||
* 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.postgresql;
|
||||
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.DEFAULT_JDBC_DRIVER_NAME;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.DEFAULT_JDBC_URL;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.DEFAULT_JDBC_USER_NAME;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.DEFAULT_JDBC_USER_PASSWORD;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.DEFAULT_MAX_RESULT;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.POSTGRESQL_SERVER_DRIVER_NAME;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.POSTGRESQL_SERVER_MAX_RESULT;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.POSTGRESQL_SERVER_PASSWORD;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.POSTGRESQL_SERVER_URL;
|
||||
import static org.apache.zeppelin.postgresql.PostgreSqlInterpreter.POSTGRESQL_SERVER_USER;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mockrunner.jdbc.BasicJDBCTestCaseAdapter;
|
||||
import com.mockrunner.jdbc.StatementResultSetHandler;
|
||||
import com.mockrunner.mock.jdbc.MockConnection;
|
||||
import com.mockrunner.mock.jdbc.MockResultSet;
|
||||
|
||||
/**
|
||||
* PostgreSQL interpreter unit tests
|
||||
*/
|
||||
public class PostgreSqlInterpreterTest extends BasicJDBCTestCaseAdapter {
|
||||
|
||||
private PostgreSqlInterpreter psqlInterpreter = null;
|
||||
private MockResultSet result = null;
|
||||
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
MockConnection connection = getJDBCMockObjectFactory().getMockConnection();
|
||||
|
||||
StatementResultSetHandler statementHandler = connection.getStatementResultSetHandler();
|
||||
result = statementHandler.createResultSet();
|
||||
statementHandler.prepareGlobalResultSet(result);
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.put(POSTGRESQL_SERVER_DRIVER_NAME, DEFAULT_JDBC_DRIVER_NAME);
|
||||
properties.put(POSTGRESQL_SERVER_URL, DEFAULT_JDBC_URL);
|
||||
properties.put(POSTGRESQL_SERVER_USER, DEFAULT_JDBC_USER_NAME);
|
||||
properties.put(POSTGRESQL_SERVER_PASSWORD, DEFAULT_JDBC_USER_PASSWORD);
|
||||
properties.put(POSTGRESQL_SERVER_MAX_RESULT, DEFAULT_MAX_RESULT);
|
||||
|
||||
psqlInterpreter = spy(new PostgreSqlInterpreter(properties));
|
||||
when(psqlInterpreter.getJdbcConnection()).thenReturn(connection);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenCommandIndempotency() throws SQLException {
|
||||
// Ensure that an attempt to open new connection will clean any remaining connections
|
||||
psqlInterpreter.open();
|
||||
psqlInterpreter.open();
|
||||
psqlInterpreter.open();
|
||||
|
||||
verify(psqlInterpreter, times(3)).open();
|
||||
verify(psqlInterpreter, times(3)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultProperties() throws SQLException {
|
||||
|
||||
PostgreSqlInterpreter psqlInterpreter = new PostgreSqlInterpreter(new Properties());
|
||||
|
||||
assertEquals(DEFAULT_JDBC_DRIVER_NAME,
|
||||
psqlInterpreter.getProperty(POSTGRESQL_SERVER_DRIVER_NAME));
|
||||
assertEquals(DEFAULT_JDBC_URL, psqlInterpreter.getProperty(POSTGRESQL_SERVER_URL));
|
||||
assertEquals(DEFAULT_JDBC_USER_NAME, psqlInterpreter.getProperty(POSTGRESQL_SERVER_USER));
|
||||
assertEquals(DEFAULT_JDBC_USER_PASSWORD,
|
||||
psqlInterpreter.getProperty(POSTGRESQL_SERVER_PASSWORD));
|
||||
assertEquals(DEFAULT_MAX_RESULT, psqlInterpreter.getProperty(POSTGRESQL_SERVER_MAX_RESULT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionClose() throws SQLException {
|
||||
|
||||
PostgreSqlInterpreter psqlInterpreter = spy(new PostgreSqlInterpreter(new Properties()));
|
||||
|
||||
when(psqlInterpreter.getJdbcConnection()).thenReturn(
|
||||
getJDBCMockObjectFactory().getMockConnection());
|
||||
|
||||
psqlInterpreter.close();
|
||||
|
||||
verifyAllResultSetsClosed();
|
||||
verifyAllStatementsClosed();
|
||||
verifyConnectionClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatementCancel() throws SQLException {
|
||||
|
||||
PostgreSqlInterpreter psqlInterpreter = spy(new PostgreSqlInterpreter(new Properties()));
|
||||
|
||||
when(psqlInterpreter.getJdbcConnection()).thenReturn(
|
||||
getJDBCMockObjectFactory().getMockConnection());
|
||||
|
||||
psqlInterpreter.cancel(null);
|
||||
|
||||
verifyAllResultSetsClosed();
|
||||
verifyAllStatementsClosed();
|
||||
assertFalse("Cancel operation should not close the connection", psqlInterpreter
|
||||
.getJdbcConnection().isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullColumnResult() throws SQLException {
|
||||
|
||||
when(psqlInterpreter.getMaxResult()).thenReturn(1000);
|
||||
|
||||
String sqlQuery = "select * from t";
|
||||
|
||||
result.addColumn("col1", new String[] {"val11", null});
|
||||
result.addColumn("col2", new String[] {null, "val22"});
|
||||
|
||||
InterpreterResult interpreterResult = psqlInterpreter.interpret(sqlQuery, null);
|
||||
|
||||
assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
|
||||
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.type());
|
||||
assertEquals("col1\tcol2\nval11\t\n\tval22\n", interpreterResult.message());
|
||||
|
||||
verifySQLStatementExecuted(sqlQuery);
|
||||
verifyAllResultSetsClosed();
|
||||
verifyAllStatementsClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectQuery() throws SQLException {
|
||||
|
||||
when(psqlInterpreter.getMaxResult()).thenReturn(1000);
|
||||
|
||||
String sqlQuery = "select * from t";
|
||||
|
||||
result.addColumn("col1", new String[] {"val11", "val12"});
|
||||
result.addColumn("col2", new String[] {"val21", "val22"});
|
||||
|
||||
InterpreterResult interpreterResult = psqlInterpreter.interpret(sqlQuery, null);
|
||||
|
||||
assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
|
||||
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.type());
|
||||
assertEquals("col1\tcol2\nval11\tval21\nval12\tval22\n", interpreterResult.message());
|
||||
|
||||
verifySQLStatementExecuted(sqlQuery);
|
||||
verifyAllResultSetsClosed();
|
||||
verifyAllStatementsClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectQueryMaxResult() throws SQLException {
|
||||
|
||||
when(psqlInterpreter.getMaxResult()).thenReturn(1);
|
||||
|
||||
String sqlQuery = "select * from t";
|
||||
|
||||
result.addColumn("col1", new String[] {"val11", "val12"});
|
||||
result.addColumn("col2", new String[] {"val21", "val22"});
|
||||
|
||||
InterpreterResult interpreterResult = psqlInterpreter.interpret(sqlQuery, null);
|
||||
|
||||
assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
|
||||
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.type());
|
||||
assertEquals("col1\tcol2\nval11\tval21\n", interpreterResult.message());
|
||||
|
||||
verifySQLStatementExecuted(sqlQuery);
|
||||
verifyAllResultSetsClosed();
|
||||
verifyAllStatementsClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectQueryWithSpecialCharacters() throws SQLException {
|
||||
|
||||
when(psqlInterpreter.getMaxResult()).thenReturn(1000);
|
||||
|
||||
String sqlQuery = "select * from t";
|
||||
|
||||
result.addColumn("co\tl1", new String[] {"val11", "va\tl1\n2"});
|
||||
result.addColumn("co\nl2", new String[] {"v\nal21", "val\t22"});
|
||||
|
||||
InterpreterResult interpreterResult = psqlInterpreter.interpret(sqlQuery, null);
|
||||
|
||||
assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
|
||||
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.type());
|
||||
assertEquals("co l1\tco l2\nval11\tv al21\nva l1 2\tval 22\n", interpreterResult.message());
|
||||
|
||||
verifySQLStatementExecuted(sqlQuery);
|
||||
verifyAllResultSetsClosed();
|
||||
verifyAllStatementsClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExplainQuery() throws SQLException {
|
||||
|
||||
when(psqlInterpreter.getMaxResult()).thenReturn(1000);
|
||||
|
||||
String sqlQuery = "explain select * from t";
|
||||
|
||||
result.addColumn("col1", new String[] {"val11", "val12"});
|
||||
|
||||
InterpreterResult interpreterResult = psqlInterpreter.interpret(sqlQuery, null);
|
||||
|
||||
assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
|
||||
assertEquals(InterpreterResult.Type.TEXT, interpreterResult.type());
|
||||
assertEquals("col1\nval11\nval12\n", interpreterResult.message());
|
||||
|
||||
verifySQLStatementExecuted(sqlQuery);
|
||||
verifyAllResultSetsClosed();
|
||||
verifyAllStatementsClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExplainQueryWithSpecialCharachters() throws SQLException {
|
||||
|
||||
when(psqlInterpreter.getMaxResult()).thenReturn(1000);
|
||||
|
||||
String sqlQuery = "explain select * from t";
|
||||
|
||||
result.addColumn("co\tl\n1", new String[] {"va\nl11", "va\tl\n12"});
|
||||
|
||||
InterpreterResult interpreterResult = psqlInterpreter.interpret(sqlQuery, null);
|
||||
|
||||
assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
|
||||
assertEquals(InterpreterResult.Type.TEXT, interpreterResult.type());
|
||||
assertEquals("co\tl\n1\nva\nl11\nva\tl\n12\n", interpreterResult.message());
|
||||
|
||||
verifySQLStatementExecuted(sqlQuery);
|
||||
verifyAllResultSetsClosed();
|
||||
verifyAllStatementsClosed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoCompletion() throws SQLException {
|
||||
psqlInterpreter.open();
|
||||
assertEquals(1, psqlInterpreter.completion("SEL", 0).size());
|
||||
assertEquals("SELECT ", psqlInterpreter.completion("SEL", 0).iterator().next());
|
||||
assertEquals(0, psqlInterpreter.completion("SEL", 100).size());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/**
|
||||
* 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.postgresql;
|
||||
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import jline.console.completer.Completer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mockrunner.jdbc.BasicJDBCTestCaseAdapter;
|
||||
|
||||
public class SqlCompleterTest extends BasicJDBCTestCaseAdapter {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(SqlCompleterTest.class);
|
||||
|
||||
private final static Set<String> EMPTY = new HashSet<String>();
|
||||
|
||||
private CompleterTester tester;
|
||||
|
||||
private SqlCompleter sqlCompleter;
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws IOException, SQLException {
|
||||
Set<String> keywordsCompletions =
|
||||
SqlCompleter.getSqlKeywordsCompletions(getJDBCMockObjectFactory().getMockConnection());
|
||||
Set<String> dataModelCompletions =
|
||||
SqlCompleter
|
||||
.getDataModelMetadataCompletions(getJDBCMockObjectFactory().getMockConnection());
|
||||
|
||||
sqlCompleter =
|
||||
new SqlCompleter(Sets.union(keywordsCompletions, dataModelCompletions),
|
||||
dataModelCompletions);
|
||||
tester = new CompleterTester(sqlCompleter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterBufferEnd() {
|
||||
String buffer = "ORDER";
|
||||
// Up to 2 white spaces after the buffer end, the completer still uses the last argument
|
||||
tester.buffer(buffer).from(0).to(buffer.length() + 1).expect(newHashSet("ORDER ")).test();
|
||||
// 2 white spaces or more behind the buffer end the completer returns empty result
|
||||
tester.buffer(buffer).from(buffer.length() + 2).to(buffer.length() + 5).expect(EMPTY).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEdges() {
|
||||
String buffer = " ORDER ";
|
||||
tester.buffer(buffer).from(0).to(8).expect(newHashSet("ORDER ")).test();
|
||||
tester.buffer(buffer).from(9).to(15).expect(EMPTY).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleWords() {
|
||||
String buffer = " SELE fro LIM";
|
||||
tester.buffer(buffer).from(0).to(6).expect(newHashSet("SELECT ")).test();
|
||||
tester.buffer(buffer).from(7).to(11).expect(newHashSet("from ")).test();
|
||||
tester.buffer(buffer).from(12).to(19).expect(newHashSet("LIMIT ")).test();
|
||||
tester.buffer(buffer).from(20).to(24).expect(EMPTY).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiLineBuffer() {
|
||||
String buffer = " \n SELE \n fro";
|
||||
tester.buffer(buffer).from(0).to(7).expect(newHashSet("SELECT ")).test();
|
||||
tester.buffer(buffer).from(8).to(14).expect(newHashSet("from ")).test();
|
||||
tester.buffer(buffer).from(15).to(17).expect(EMPTY).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleCompletionSuggestions() {
|
||||
String buffer = " SU";
|
||||
tester.buffer(buffer).from(0).to(5).expect(newHashSet("SUBCLASS_ORIGIN", "SUM", "SUBSTRING"))
|
||||
.test();
|
||||
tester.buffer(buffer).from(6).to(7).expect(EMPTY).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDotDelimiter() {
|
||||
String buffer = " order.select ";
|
||||
tester.buffer(buffer).from(4).to(7).expect(newHashSet("order ")).test();
|
||||
tester.buffer(buffer).from(8).to(15).expect(newHashSet("select ")).test();
|
||||
tester.buffer(buffer).from(16).to(17).expect(EMPTY).test();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSqlDelimiterCharacters() {
|
||||
assertTrue(sqlCompleter.getSqlDelimiter().isDelimiterChar("r.", 1));
|
||||
assertTrue(sqlCompleter.getSqlDelimiter().isDelimiterChar("SS;", 2));
|
||||
assertTrue(sqlCompleter.getSqlDelimiter().isDelimiterChar(":", 0));
|
||||
assertTrue(sqlCompleter.getSqlDelimiter().isDelimiterChar("ttt,", 3));
|
||||
}
|
||||
|
||||
public class CompleterTester {
|
||||
|
||||
private Completer completer;
|
||||
|
||||
private String buffer;
|
||||
private int fromCursor;
|
||||
private int toCursor;
|
||||
private Set<String> expectedCompletions;
|
||||
|
||||
public CompleterTester(Completer completer) {
|
||||
this.completer = completer;
|
||||
}
|
||||
|
||||
public CompleterTester buffer(String buffer) {
|
||||
this.buffer = buffer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CompleterTester from(int fromCursor) {
|
||||
this.fromCursor = fromCursor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CompleterTester to(int toCursor) {
|
||||
this.toCursor = toCursor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CompleterTester expect(Set<String> expectedCompletions) {
|
||||
this.expectedCompletions = expectedCompletions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void test() {
|
||||
for (int c = fromCursor; c <= toCursor; c++) {
|
||||
expectedCompletions(buffer, c, expectedCompletions);
|
||||
}
|
||||
}
|
||||
|
||||
private void expectedCompletions(String buffer, int cursor, Set<String> expected) {
|
||||
|
||||
ArrayList<CharSequence> candidates = new ArrayList<CharSequence>();
|
||||
|
||||
completer.complete(buffer, cursor, candidates);
|
||||
|
||||
String explain = explain(buffer, cursor, candidates);
|
||||
|
||||
logger.info(explain);
|
||||
|
||||
assertEquals("Buffer [" + buffer.replace(" ", ".") + "] and Cursor[" + cursor + "] "
|
||||
+ explain, expected, newHashSet(candidates));
|
||||
}
|
||||
|
||||
private String explain(String buffer, int cursor, ArrayList<CharSequence> candidates) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (int i = 0; i <= Math.max(cursor, buffer.length()); i++) {
|
||||
if (i == cursor) {
|
||||
sb.append("(");
|
||||
}
|
||||
if (i >= buffer.length()) {
|
||||
sb.append("_");
|
||||
} else {
|
||||
if (Character.isWhitespace(buffer.charAt(i))) {
|
||||
sb.append(".");
|
||||
} else {
|
||||
sb.append(buffer.charAt(i));
|
||||
}
|
||||
}
|
||||
if (i == cursor) {
|
||||
sb.append(")");
|
||||
}
|
||||
}
|
||||
sb.append(" >> [").append(Joiner.on(",").join(candidates)).append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -403,6 +403,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
+ "org.apache.zeppelin.hive.HiveInterpreter,"
|
||||
+ "org.apache.zeppelin.tachyon.TachyonInterpreter,"
|
||||
+ "org.apache.zeppelin.phoenix.PhoenixInterpreter,"
|
||||
+ "org.apache.zeppelin.postgresql.PostgreSqlInterpreter,"
|
||||
+ "org.apache.zeppelin.tajo.TajoInterpreter,"
|
||||
+ "org.apache.zeppelin.flink.FlinkInterpreter,"
|
||||
+ "org.apache.zeppelin.ignite.IgniteInterpreter,"
|
||||
|
|
|
|||
Loading…
Reference in a new issue