From d41b907cf8a16f176cda3e59fe4f6cc7e61cf59c Mon Sep 17 00:00:00 2001
From: honma
Date: Thu, 13 Nov 2014 16:49:08 +0800
Subject: [PATCH 1/9] add a API for purging cubes
---
.../kylinolap/rest/controller/CubeController.java | 32 ++++++++------
.../rest/interceptor/CacheIntercaptor.java | 2 +-
.../com/kylinolap/rest/service/CubeService.java | 50 ++++++++++++++++------
3 files changed, 59 insertions(+), 25 deletions(-)
diff --git a/server/src/main/java/com/kylinolap/rest/controller/CubeController.java b/server/src/main/java/com/kylinolap/rest/controller/CubeController.java
index c8f4252..5ea9df2 100644
--- a/server/src/main/java/com/kylinolap/rest/controller/CubeController.java
+++ b/server/src/main/java/com/kylinolap/rest/controller/CubeController.java
@@ -215,12 +215,6 @@ public JobInstance rebuild(@PathVariable String cubeName, @RequestBody JobBuildR
return jobInstance;
}
- /**
- * Get available table list of the input database
- *
- * @return true
- * @throws IOException
- */
@RequestMapping(value = "/{cubeName}/disable", method = { RequestMethod.PUT })
@ResponseBody
@Metered(name = "disableCube")
@@ -240,12 +234,26 @@ public CubeInstance disableCube(@PathVariable String cubeName) {
}
}
- /**
- * Get available table list of the input database
- *
- * @return true
- * @throws IOException
- */
+ @RequestMapping(value = "/{cubeName}/purge", method = { RequestMethod.PUT })
+ @ResponseBody
+ @Metered(name = "purgeCube")
+ public CubeInstance purgeCube(@PathVariable String cubeName) {
+ try {
+ CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new InternalErrorException("Cannot find cube " + cubeName);
+ }
+
+ return cubeService.purgeCube(cube);
+ } catch (Exception e) {
+ String message = "Failed to purge cube: " + cubeName;
+ logger.error(message, e);
+ throw new InternalErrorException(message + " Caused by: " + e.getMessage(), e);
+ }
+ }
+
+
@RequestMapping(value = "/{cubeName}/enable", method = { RequestMethod.PUT })
@ResponseBody
@Metered(name = "enableCube")
diff --git a/server/src/main/java/com/kylinolap/rest/interceptor/CacheIntercaptor.java b/server/src/main/java/com/kylinolap/rest/interceptor/CacheIntercaptor.java
index 7bf2b98..2b763dd 100644
--- a/server/src/main/java/com/kylinolap/rest/interceptor/CacheIntercaptor.java
+++ b/server/src/main/java/com/kylinolap/rest/interceptor/CacheIntercaptor.java
@@ -35,7 +35,7 @@
public void flush(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
- if (methodName.matches("(update|create|save|disable|enable|delete|drop)")) {
+ if (methodName.matches("(update|create|save|disable|enable|delete|drop|purge)")) {
Broadcaster.flush();
}
}
diff --git a/server/src/main/java/com/kylinolap/rest/service/CubeService.java b/server/src/main/java/com/kylinolap/rest/service/CubeService.java
index 0c03e3d..1523142 100644
--- a/server/src/main/java/com/kylinolap/rest/service/CubeService.java
+++ b/server/src/main/java/com/kylinolap/rest/service/CubeService.java
@@ -83,7 +83,7 @@
/**
* Stateless & lightweight service facade of cube management functions.
- *
+ *
* @author yangli9
*/
@Component("cubeMgmtService")
@@ -267,9 +267,36 @@ public void removeCubeCache(String cubeName) {
}
/**
+ * Stop all jobs belonging to this cube and clean out all segments
+ *
+ * @param cube
+ * @return
+ * @throws IOException
+ * @throws CubeIntegrityException
+ * @throws JobException
+ */
+ @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#cube, 'ADMINISTRATION') or hasPermission(#cube, 'OPERATION') or hasPermission(#cube, 'MANAGEMENT')")
+ @Caching(evict = { @CacheEvict(value = QueryController.SUCCESS_QUERY_CACHE, allEntries = true), @CacheEvict(value = QueryController.EXCEPTION_QUERY_CACHE, allEntries = true) })
+ public CubeInstance purgeCube(CubeInstance cube) throws IOException, CubeIntegrityException, JobException {
+ String cubeName = cube.getName();
+
+ CubeStatusEnum ostatus = cube.getStatus();
+ if (null != ostatus && !CubeStatusEnum.DISABLED.equals(ostatus)) {
+ throw new InternalErrorException("Only disabled cube can be purged, status of " + cubeName + " is " + ostatus);
+ }
+
+ try {
+ this.releaseAllSegments(cube);
+ return cube;
+ } catch (IOException e) {
+ throw e;
+ }
+
+ }
+
+ /**
* Update a cube status from ready to disabled.
- *
- * @param cubeName
+ *
* @return
* @throws CubeIntegrityException
* @throws IOException
@@ -297,7 +324,7 @@ public CubeInstance disableCube(CubeInstance cube) throws IOException, CubeInteg
/**
* Update a cube status from disable to ready.
- *
+ *
* @return
* @throws CubeIntegrityException
* @throws IOException
@@ -365,13 +392,11 @@ public MetricsResponse calculateMetrics(MetricsRequest request) {
/**
* Calculate size of each region for given table and other info of the
* table.
- *
- * @param tableName
- * The table name.
+ *
+ * @param tableName The table name.
* @return The HBaseResponse object contains table size, region count. null
- * if error happens.
- * @throws IOException
- * Exception when HTable resource is not closed correctly.
+ * if error happens.
+ * @throws IOException Exception when HTable resource is not closed correctly.
*/
public HBaseResponse getHTableInfo(String tableName) throws IOException {
// Get HBase storage conf.
@@ -411,7 +436,7 @@ public HBaseResponse getHTableInfo(String tableName) throws IOException {
/**
* Generate cardinality for table This will trigger a hadoop job and nothing
* The result will be merged into table exd info
- *
+ *
* @param tableName
* @param delimiter
* @param format
@@ -532,7 +557,8 @@ public CubeInstance rebuildLookupSnapshot(String cubeName, String segmentName, S
}
/**
- * @param cube
+ * purge the cube
+ *
* @throws IOException
* @throws JobException
* @throws UnknownHostException
From 097bf405ae224f9e6bc23abbed1e3f45ded89342 Mon Sep 17 00:00:00 2001
From: jiazhong
Date: Thu, 13 Nov 2014 17:24:06 +0800
Subject: [PATCH 2/9] add purge cube in front page
---
webapp/app/js/controllers/cubes.js | 8 ++++++++
webapp/app/js/services/cubes.js | 1 +
webapp/app/partials/cubes/cubes.html | 2 ++
3 files changed, 11 insertions(+)
diff --git a/webapp/app/js/controllers/cubes.js b/webapp/app/js/controllers/cubes.js
index ece6f01..f6dca82 100644
--- a/webapp/app/js/controllers/cubes.js
+++ b/webapp/app/js/controllers/cubes.js
@@ -118,6 +118,14 @@ KylinApp
}
}
+ $scope.purge = function (cube) {
+ if (confirm("Are you sure to purge the cube? ")) {
+ CubeService.purge({cubeId: cube.name}, {}, function (result) {
+ MessageService.sendMsg('Purge job was submitted successfully', 'success', {});
+ });
+ }
+ }
+
$scope.disable = function (cube) {
if (confirm("Are you sure to disable the cube?")) {
CubeService.disable({cubeId: cube.name}, {}, function (result) {
diff --git a/webapp/app/js/services/cubes.js b/webapp/app/js/services/cubes.js
index 4753bcd..ad7f670 100644
--- a/webapp/app/js/services/cubes.js
+++ b/webapp/app/js/services/cubes.js
@@ -8,6 +8,7 @@ KylinApp.factory('CubeService', ['$resource', function ($resource, config) {
rebuildCube: {method: 'PUT', params: {action: 'rebuild'}, isArray: false},
disable: {method: 'PUT', params: {action: 'disable'}, isArray: false},
enable: {method: 'PUT', params: {action: 'enable'}, isArray: false},
+ purge: {method: 'PUT', params: {action: 'purge'}, isArray: false},
drop: {method: 'DELETE', params: {}, isArray: false},
save: {method: 'POST', params: {}, isArray: false},
update: {method: 'PUT', params: {}, isArray: false},
diff --git a/webapp/app/partials/cubes/cubes.html b/webapp/app/partials/cubes/cubes.html
index 437aaa3..c9be05c 100644
--- a/webapp/app/partials/cubes/cubes.html
+++ b/webapp/app/partials/cubes/cubes.html
@@ -97,6 +97,8 @@
Merge
Disable
Enable
+ Purge
+
From 579ae3404f1b8142be86272b25db0f3b26f2644f Mon Sep 17 00:00:00 2001
From: "Li, Yang"
Date: Thu, 13 Nov 2014 17:27:57 +0800
Subject: [PATCH 3/9] exclude a few files in coverage test
---
pom.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/pom.xml b/pom.xml
index 15af0dd..84edc94 100644
--- a/pom.xml
+++ b/pom.xml
@@ -70,6 +70,7 @@
reuseReports
${project.basedir}/../target/jacoco.exec
java
+ com/kylinolap/**/tools/**:net/hydromatic/optiq/**:org/eigenbase/sql2rel/**
From cdb6b4f72b98b1200d37c69899a9c281cc899469 Mon Sep 17 00:00:00 2001
From: "Li, Yang"
Date: Thu, 13 Nov 2014 17:28:43 +0800
Subject: [PATCH 4/9] rename package to com/kylinolap/jdbc
---
jdbc/src/main/java/com/kylinolap/jdbc/Driver.java | 137 ++++
.../com/kylinolap/jdbc/KylinConnectionImpl.java | 157 ++++
.../java/com/kylinolap/jdbc/KylinEnumerator.java | 85 +++
.../com/kylinolap/jdbc/KylinJdbc40Factory.java | 28 +
.../com/kylinolap/jdbc/KylinJdbc41Factory.java | 125 ++++
.../java/com/kylinolap/jdbc/KylinMetaImpl.java | 825 +++++++++++++++++++++
.../main/java/com/kylinolap/jdbc/KylinPrepare.java | 96 +++
.../java/com/kylinolap/jdbc/KylinPrepareImpl.java | 45 ++
.../kylinolap/jdbc/KylinPrepareStatementImpl.java | 168 +++++
.../java/com/kylinolap/jdbc/KylinResultSet.java | 43 ++
.../com/kylinolap/jdbc/KylinStatementImpl.java | 52 ++
.../kylinolap/jdbc/stub/ConnectionException.java | 53 ++
.../main/java/com/kylinolap/jdbc/stub/DataSet.java | 53 ++
.../java/com/kylinolap/jdbc/stub/KylinClient.java | 376 ++++++++++
.../kylinolap/jdbc/stub/KylinColumnMetaData.java | 36 +
.../java/com/kylinolap/jdbc/stub/RemoteClient.java | 57 ++
.../com/kylinolap/jdbc/stub/SQLResponseStub.java | 320 ++++++++
.../com/kylinolap/jdbc/stub/TableMetaStub.java | 329 ++++++++
.../jdbc/util/DefaultSslProtocolSocketFactory.java | 148 ++++
.../jdbc/util/DefaultX509TrustManager.java | 112 +++
.../java/com/kylinolap/jdbc/util/SQLTypeMap.java | 179 +++++
.../main/java/com/kylinolap/kylin/jdbc/Driver.java | 137 ----
.../kylinolap/kylin/jdbc/KylinConnectionImpl.java | 157 ----
.../com/kylinolap/kylin/jdbc/KylinEnumerator.java | 85 ---
.../kylinolap/kylin/jdbc/KylinJdbc40Factory.java | 28 -
.../kylinolap/kylin/jdbc/KylinJdbc41Factory.java | 125 ----
.../com/kylinolap/kylin/jdbc/KylinMetaImpl.java | 825 ---------------------
.../com/kylinolap/kylin/jdbc/KylinPrepare.java | 96 ---
.../com/kylinolap/kylin/jdbc/KylinPrepareImpl.java | 45 --
.../kylin/jdbc/KylinPrepareStatementImpl.java | 168 -----
.../com/kylinolap/kylin/jdbc/KylinResultSet.java | 43 --
.../kylinolap/kylin/jdbc/KylinStatementImpl.java | 52 --
.../kylin/jdbc/stub/ConnectionException.java | 53 --
.../com/kylinolap/kylin/jdbc/stub/DataSet.java | 53 --
.../com/kylinolap/kylin/jdbc/stub/KylinClient.java | 376 ----------
.../kylin/jdbc/stub/KylinColumnMetaData.java | 36 -
.../kylinolap/kylin/jdbc/stub/RemoteClient.java | 57 --
.../kylinolap/kylin/jdbc/stub/SQLResponseStub.java | 320 --------
.../kylinolap/kylin/jdbc/stub/TableMetaStub.java | 329 --------
.../jdbc/util/DefaultSslProtocolSocketFactory.java | 148 ----
.../kylin/jdbc/util/DefaultX509TrustManager.java | 112 ---
.../com/kylinolap/kylin/jdbc/util/SQLTypeMap.java | 179 -----
.../test/java/com/kylinolap/jdbc/DriverTest.java | 158 ++++
.../test/java/com/kylinolap/jdbc/DummyClient.java | 69 ++
.../test/java/com/kylinolap/jdbc/DummyDriver.java | 16 +
.../com/kylinolap/jdbc/DummyJdbc41Factory.java | 19 +
.../java/com/kylinolap/kylin/jdbc/DriverTest.java | 156 ----
.../java/com/kylinolap/kylin/jdbc/DummyClient.java | 67 --
.../java/com/kylinolap/kylin/jdbc/DummyDriver.java | 14 -
.../kylinolap/kylin/jdbc/DummyJdbc41Factory.java | 17 -
50 files changed, 3686 insertions(+), 3678 deletions(-)
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/Driver.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinConnectionImpl.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinEnumerator.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinJdbc40Factory.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinJdbc41Factory.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinMetaImpl.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinPrepare.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinPrepareImpl.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinPrepareStatementImpl.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinResultSet.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/KylinStatementImpl.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/stub/ConnectionException.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/stub/DataSet.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/stub/KylinClient.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/stub/KylinColumnMetaData.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/stub/RemoteClient.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/stub/SQLResponseStub.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/stub/TableMetaStub.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/util/DefaultSslProtocolSocketFactory.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/util/DefaultX509TrustManager.java
create mode 100644 jdbc/src/main/java/com/kylinolap/jdbc/util/SQLTypeMap.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/Driver.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinConnectionImpl.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinEnumerator.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinJdbc40Factory.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinJdbc41Factory.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinMetaImpl.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinPrepare.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinPrepareImpl.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinPrepareStatementImpl.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinResultSet.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/KylinStatementImpl.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/stub/ConnectionException.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/stub/DataSet.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/stub/KylinClient.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/stub/KylinColumnMetaData.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/stub/RemoteClient.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/stub/SQLResponseStub.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/stub/TableMetaStub.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/util/DefaultSslProtocolSocketFactory.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/util/DefaultX509TrustManager.java
delete mode 100644 jdbc/src/main/java/com/kylinolap/kylin/jdbc/util/SQLTypeMap.java
create mode 100644 jdbc/src/test/java/com/kylinolap/jdbc/DriverTest.java
create mode 100644 jdbc/src/test/java/com/kylinolap/jdbc/DummyClient.java
create mode 100644 jdbc/src/test/java/com/kylinolap/jdbc/DummyDriver.java
create mode 100644 jdbc/src/test/java/com/kylinolap/jdbc/DummyJdbc41Factory.java
delete mode 100644 jdbc/src/test/java/com/kylinolap/kylin/jdbc/DriverTest.java
delete mode 100644 jdbc/src/test/java/com/kylinolap/kylin/jdbc/DummyClient.java
delete mode 100644 jdbc/src/test/java/com/kylinolap/kylin/jdbc/DummyDriver.java
delete mode 100644 jdbc/src/test/java/com/kylinolap/kylin/jdbc/DummyJdbc41Factory.java
diff --git a/jdbc/src/main/java/com/kylinolap/jdbc/Driver.java b/jdbc/src/main/java/com/kylinolap/jdbc/Driver.java
new file mode 100644
index 0000000..0f5e380
--- /dev/null
+++ b/jdbc/src/main/java/com/kylinolap/jdbc/Driver.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.jdbc;
+
+import java.sql.SQLException;
+
+import net.hydromatic.avatica.AvaticaConnection;
+import net.hydromatic.avatica.AvaticaStatement;
+import net.hydromatic.avatica.DriverVersion;
+import net.hydromatic.avatica.Handler;
+import net.hydromatic.avatica.HandlerImpl;
+import net.hydromatic.avatica.UnregisteredDriver;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.kylinolap.jdbc.stub.ConnectionException;
+import com.kylinolap.jdbc.stub.RemoteClient;
+
+/**
+ *
+ * Kylin JDBC Driver based on optiq avatica and kylin restful api.
+ * Supported versions:
+ *
+ *
+ * - jdbc 4.0
+ * - jdbc 4.1
+ *
+ *
+ *
+ * Supported Statements:
+ *
+ *
+ * - {@link KylinStatementImpl}
+ * - {@link KylinPrepareStatementImpl}
+ *
+ *
+ *
+ * Supported properties:
+ *
+ * - user: username
+ * - password: password
+ * - ssl: true/false
+ *
+ *
+ *
+ *
+ * Driver init code sample:
+ *
+ *
+ * Driver driver = (Driver) Class.forName("com.kylinolap.kylin.jdbc.Driver").newInstance();
+ * Properties info = new Properties();
+ * info.put("user", "user");
+ * info.put("password", "password");
+ * info.put("ssl", true);
+ * Connection conn = driver.connect("jdbc:kylin://{domain}/{project}", info);
+ *
+ *
+ *
+ *
+ * @author xduo
+ *
+ */
+public class Driver extends UnregisteredDriver {
+ private static final Logger logger = LoggerFactory.getLogger(Driver.class);
+
+ public static final String CONNECT_STRING_PREFIX = "jdbc:kylin:";
+
+ @Override
+ protected DriverVersion createDriverVersion() {
+ return DriverVersion.load(Driver.class, "com-kylinolap-kylin-jdbc.properties", "Kylin JDBC Driver", "unknown version", "Kylin", "unknown version");
+ }
+
+ @Override
+ protected String getFactoryClassName(JdbcVersion jdbcVersion) {
+ switch (jdbcVersion) {
+ case JDBC_30:
+ throw new UnsupportedOperationException();
+ case JDBC_40:
+ return "com.kylinolap.kylin.jdbc.KylinJdbc40Factory";
+ case JDBC_41:
+ default:
+ return "com.kylinolap.kylin.jdbc.KylinJdbc41Factory";
+ }
+ }
+
+ @Override
+ protected Handler createHandler() {
+ return new HandlerImpl() {
+ @Override
+ public void onConnectionInit(AvaticaConnection connection_) throws SQLException {
+ KylinConnectionImpl kylinConn = (KylinConnectionImpl) connection_;
+ RemoteClient runner = ((KylinJdbc41Factory) factory).newRemoteClient(kylinConn);
+ try {
+ runner.connect();
+ kylinConn.setMetaProject(runner.getMetadata(kylinConn.getProject()));
+ logger.debug("Connection inited.");
+ } catch (ConnectionException e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new SQLException(e.getLocalizedMessage());
+ }
+ }
+
+ public void onConnectionClose(AvaticaConnection connection) {
+ logger.debug("Connection closed.");
+ }
+
+ public void onStatementExecute(AvaticaStatement statement, ResultSink resultSink) {
+ logger.debug("statement executed.");
+ }
+
+ public void onStatementClose(AvaticaStatement statement) {
+ logger.debug("statement closed.");
+ }
+ };
+ }
+
+ @Override
+ protected String getConnectStringPrefix() {
+ return CONNECT_STRING_PREFIX;
+ }
+
+}
diff --git a/jdbc/src/main/java/com/kylinolap/jdbc/KylinConnectionImpl.java b/jdbc/src/main/java/com/kylinolap/jdbc/KylinConnectionImpl.java
new file mode 100644
index 0000000..2b412ed
--- /dev/null
+++ b/jdbc/src/main/java/com/kylinolap/jdbc/KylinConnectionImpl.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.jdbc;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.xml.bind.DatatypeConverter;
+
+import net.hydromatic.avatica.AvaticaConnection;
+import net.hydromatic.avatica.AvaticaFactory;
+import net.hydromatic.avatica.AvaticaPreparedStatement;
+import net.hydromatic.avatica.AvaticaStatement;
+import net.hydromatic.avatica.Meta;
+import net.hydromatic.avatica.UnregisteredDriver;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.kylinolap.jdbc.KylinMetaImpl.MetaProject;
+import com.kylinolap.jdbc.KylinPrepare.PrepareResult;
+
+/**
+ * Kylin connection implementation
+ *
+ * @author xduo
+ *
+ */
+public abstract class KylinConnectionImpl extends AvaticaConnection {
+ private static final Logger logger = LoggerFactory.getLogger(KylinConnectionImpl.class);
+
+ private final String baseUrl;
+ private final String project;
+ private MetaProject metaProject;
+ public final List statements;
+ static final Trojan TROJAN = createTrojan();
+
+ protected KylinConnectionImpl(UnregisteredDriver driver, AvaticaFactory factory, String url, Properties info) {
+ super(driver, factory, url, info);
+
+ String odbcUrl = url;
+ odbcUrl = odbcUrl.replace(Driver.CONNECT_STRING_PREFIX + "//", "");
+ String[] temps = odbcUrl.split("/");
+
+ assert temps.length == 2;
+
+ this.baseUrl = temps[0];
+ this.project = temps[1];
+
+ logger.debug("Kylin base url " + this.baseUrl + ", project name " + this.project);
+
+ statements = new ArrayList();
+ }
+
+ @Override
+ protected Meta createMeta() {
+ return new KylinMetaImpl(this, (KylinJdbc41Factory) factory);
+ }
+
+ @Override
+ public AvaticaStatement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ AvaticaStatement statement = super.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
+ statements.add(statement);
+
+ return statement;
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql) throws SQLException {
+ PrepareResult pr = new KylinPrepareImpl().prepare(sql);
+ AvaticaPreparedStatement statement = ((KylinJdbc41Factory) factory).newPreparedStatement(this, pr, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, this.getHoldability());
+ statements.add(statement);
+
+ return statement;
+ }
+
+ // ~ kylin specified implements
+
+ public String getBasicAuthHeader() {
+ String username = this.info.getProperty("user");
+ String password = this.info.getProperty("password");
+
+ return DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
+ }
+
+ public String getConnectUrl() {
+ boolean isSsl = Boolean.parseBoolean((this.info.getProperty("ssl", "false")));
+ return (isSsl ? "https://" : "http://") + this.baseUrl + ":" + (isSsl ? 443 : 80) + "/kylin/api/user/authentication";
+ }
+
+ public String getMetaProjectUrl(String project) {
+ assert project != null;
+ boolean isSsl = Boolean.parseBoolean((this.info.getProperty("ssl", "false")));
+ return (isSsl ? "https://" : "http://") + this.baseUrl + ":" + (isSsl ? 443 : 80) + "/kylin/api/tables_and_columns?project=" + project;
+ }
+
+ public String getQueryUrl() {
+ boolean isSsl = Boolean.parseBoolean((this.info.getProperty("ssl", "false")));
+ return (isSsl ? "https://" : "http://") + this.baseUrl + ":" + (isSsl ? 443 : 80) + "/kylin/api/query";
+ }
+
+ public String getProject() {
+ return this.project;
+ }
+
+ public Meta getMeta() {
+ return this.meta;
+ }
+
+ public AvaticaFactory getFactory() {
+ return this.factory;
+ }
+
+ public UnregisteredDriver getDriver() {
+ return this.driver;
+ }
+
+ public MetaProject getMetaProject() {
+ return metaProject;
+ }
+
+ public void setMetaProject(MetaProject metaProject) {
+ this.metaProject = metaProject;
+ }
+
+ @Override
+ public void close() throws SQLException {
+ super.close();
+
+ this.metaProject = null;
+ this.statements.clear();
+ }
+
+ @Override
+ public String toString() {
+ return "KylinConnectionImpl [baseUrl=" + baseUrl + ", project=" + project + ", metaProject=" + metaProject + "]";
+ }
+
+}
diff --git a/jdbc/src/main/java/com/kylinolap/jdbc/KylinEnumerator.java b/jdbc/src/main/java/com/kylinolap/jdbc/KylinEnumerator.java
new file mode 100644
index 0000000..8ef6f66
--- /dev/null
+++ b/jdbc/src/main/java/com/kylinolap/jdbc/KylinEnumerator.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.jdbc;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import net.hydromatic.linq4j.Enumerator;
+
+/**
+ * Query results enumerator
+ *
+ * @author xduo
+ *
+ */
+public class KylinEnumerator implements Enumerator {
+
+ /**
+ * current row
+ */
+ private E current;
+
+ /**
+ * data collection
+ */
+ private Collection dataCollection;
+
+ /**
+ * result iterator
+ */
+ private Iterator cursor;
+
+ public KylinEnumerator(Collection dataCollection) {
+ this.dataCollection = dataCollection;
+ this.cursor = this.dataCollection.iterator();
+
+ if (null == this.cursor) {
+ throw new RuntimeException("Cursor can't be null");
+ }
+ }
+
+ @Override
+ public E current() {
+ return current;
+ }
+
+ @Override
+ public boolean moveNext() {
+ if (!cursor.hasNext()) {
+ this.reset();
+
+ return false;
+ }
+
+ current = cursor.next();
+
+ return true;
+ }
+
+ @Override
+ public void reset() {
+ this.cursor = this.dataCollection.iterator();
+ }
+
+ @Override
+ public void close() {
+ this.cursor = null;
+ this.dataCollection = null;
+ }
+
+}
diff --git a/jdbc/src/main/java/com/kylinolap/jdbc/KylinJdbc40Factory.java b/jdbc/src/main/java/com/kylinolap/jdbc/KylinJdbc40Factory.java
new file mode 100644
index 0000000..83fcca3
--- /dev/null
+++ b/jdbc/src/main/java/com/kylinolap/jdbc/KylinJdbc40Factory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.jdbc;
+
+/**
+ * @author xduo
+ *
+ */
+public class KylinJdbc40Factory extends KylinJdbc41Factory {
+
+ public KylinJdbc40Factory() {
+ super(4, 0);
+ }
+}
diff --git a/jdbc/src/main/java/com/kylinolap/jdbc/KylinJdbc41Factory.java b/jdbc/src/main/java/com/kylinolap/jdbc/KylinJdbc41Factory.java
new file mode 100644
index 0000000..10a8e02
--- /dev/null
+++ b/jdbc/src/main/java/com/kylinolap/jdbc/KylinJdbc41Factory.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.jdbc;
+
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Properties;
+import java.util.TimeZone;
+
+import net.hydromatic.avatica.AvaticaConnection;
+import net.hydromatic.avatica.AvaticaDatabaseMetaData;
+import net.hydromatic.avatica.AvaticaFactory;
+import net.hydromatic.avatica.AvaticaPrepareResult;
+import net.hydromatic.avatica.AvaticaPreparedStatement;
+import net.hydromatic.avatica.AvaticaResultSet;
+import net.hydromatic.avatica.AvaticaResultSetMetaData;
+import net.hydromatic.avatica.AvaticaStatement;
+import net.hydromatic.avatica.ColumnMetaData;
+import net.hydromatic.avatica.UnregisteredDriver;
+
+import com.kylinolap.jdbc.stub.KylinClient;
+import com.kylinolap.jdbc.stub.RemoteClient;
+
+/**
+ * Kylin JDBC factory.
+ *
+ * @author xduo
+ *
+ */
+public class KylinJdbc41Factory implements AvaticaFactory {
+ private final int major;
+ private final int minor;
+
+ /** Creates a JDBC factory. */
+ public KylinJdbc41Factory() {
+ this(4, 1);
+ }
+
+ /** Creates a JDBC factory with given major/minor version number. */
+ protected KylinJdbc41Factory(int major, int minor) {
+ this.major = major;
+ this.minor = minor;
+ }
+
+ public int getJdbcMajorVersion() {
+ return major;
+ }
+
+ public int getJdbcMinorVersion() {
+ return minor;
+ }
+
+ public AvaticaConnection newConnection(UnregisteredDriver driver, AvaticaFactory factory, String url, Properties info) {
+ return new KylinJdbc41Connection(driver, factory, url, info);
+ }
+
+ public AvaticaDatabaseMetaData newDatabaseMetaData(AvaticaConnection connection) {
+ return new AvaticaJdbc41DatabaseMetaData(connection);
+ }
+
+ public AvaticaStatement newStatement(AvaticaConnection connection, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
+ return new KylinJdbc41Statement(connection, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+
+ public AvaticaPreparedStatement newPreparedStatement(AvaticaConnection connection, AvaticaPrepareResult prepareResult, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return new KylinJdbc41PreparedStatement(connection, prepareResult, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+
+ public AvaticaResultSet newResultSet(AvaticaStatement statement, AvaticaPrepareResult prepareResult, TimeZone timeZone) {
+ final ResultSetMetaData metaData = newResultSetMetaData(statement, prepareResult.getColumnList());
+ return new KylinResultSet(statement, prepareResult, metaData, timeZone);
+ }
+
+ public AvaticaResultSetMetaData newResultSetMetaData(AvaticaStatement statement, List columnMetaDataList) {
+ return new AvaticaResultSetMetaData(statement, null, columnMetaDataList);
+ }
+
+ // ~ kylin sepcified
+ public RemoteClient newRemoteClient(KylinConnectionImpl connection) {
+ return new KylinClient(connection);
+ }
+
+ /** Implementation of Connection for JDBC 4.1. */
+ private static class KylinJdbc41Connection extends KylinConnectionImpl {
+ KylinJdbc41Connection(UnregisteredDriver driver, AvaticaFactory factory, String url, Properties info) {
+ super(driver, (KylinJdbc41Factory) factory, url, info);
+ }
+ }
+
+ /** Implementation of Statement for JDBC 4.1. */
+ public static class KylinJdbc41Statement extends KylinStatementImpl {
+ public KylinJdbc41Statement(AvaticaConnection connection, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
+ super(connection, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+ }
+
+ /** Implementation of PreparedStatement for JDBC 4.1. */
+ public static class KylinJdbc41PreparedStatement extends KylinPrepareStatementImpl {
+ KylinJdbc41PreparedStatement(AvaticaConnection connection, AvaticaPrepareResult sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ super(connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+ }
+
+ /** Implementation of DatabaseMetaData for JDBC 4.1. */
+ private static class AvaticaJdbc41DatabaseMetaData extends AvaticaDatabaseMetaData {
+ AvaticaJdbc41DatabaseMetaData(AvaticaConnection connection) {
+ super(connection);
+ }
+ }
+}
diff --git a/jdbc/src/main/java/com/kylinolap/jdbc/KylinMetaImpl.java b/jdbc/src/main/java/com/kylinolap/jdbc/KylinMetaImpl.java
new file mode 100644
index 0000000..8be47b0
--- /dev/null
+++ b/jdbc/src/main/java/com/kylinolap/jdbc/KylinMetaImpl.java
@@ -0,0 +1,825 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.jdbc;
+
+import java.lang.reflect.Field;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import net.hydromatic.avatica.AvaticaPrepareResult;
+import net.hydromatic.avatica.AvaticaResultSet;
+import net.hydromatic.avatica.AvaticaStatement;
+import net.hydromatic.avatica.ColumnMetaData;
+import net.hydromatic.avatica.ColumnMetaData.Rep;
+import net.hydromatic.avatica.Cursor;
+import net.hydromatic.avatica.Meta;
+import net.hydromatic.linq4j.Enumerator;
+import net.hydromatic.optiq.runtime.EnumeratorCursor;
+
+import org.eigenbase.sql.SqlJdbcFunctionCall;
+import org.eigenbase.sql.parser.SqlParser;
+import org.eigenbase.util.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.kylinolap.jdbc.stub.DataSet;
+import com.kylinolap.jdbc.stub.KylinColumnMetaData;
+import com.kylinolap.jdbc.stub.RemoteClient;
+import com.kylinolap.jdbc.util.SQLTypeMap;
+
+/**
+ * Implementation of avatica interface
+ *
+ * @author xduo
+ */
+public class KylinMetaImpl implements Meta {
+
+ private static final Logger logger = LoggerFactory.getLogger(KylinMetaImpl.class);
+
+ private final KylinConnectionImpl conn;
+
+ private final KylinJdbc41Factory factory;
+
+ /**
+ * @param conn
+ */
+ public KylinMetaImpl(KylinConnectionImpl conn, KylinJdbc41Factory factory) {
+ super();
+ this.conn = conn;
+ this.factory = factory;
+ }
+
+ private ResultSet mockEmptyResultSet() {
+ AvaticaResultSet resultSet = null;
+ try {
+ List columnMetas = new ArrayList();
+ List