kylin-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From liy...@apache.org
Subject [8/8] incubator-kylin git commit: KYLIN-780 JDBC query pass
Date Tue, 30 Jun 2015 12:37:05 GMT
KYLIN-780 JDBC query pass


Project: http://git-wip-us.apache.org/repos/asf/incubator-kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kylin/commit/776a3a24
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kylin/tree/776a3a24
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kylin/diff/776a3a24

Branch: refs/heads/KYLIN-780
Commit: 776a3a2492fc13771ebc23004ef0251451c8058e
Parents: 51c1860
Author: Yang Li <liyang@apache.org>
Authored: Tue Jun 30 20:36:14 2015 +0800
Committer: Yang Li <liyang@apache.org>
Committed: Tue Jun 30 20:36:14 2015 +0800

----------------------------------------------------------------------
 .../kylin/jdbc/stub/KylinColumnMetaData.java    |   4 +-
 .../util/DefaultSslProtocolSocketFactory.java   |   2 -
 .../org/apache/kylin/jdbc/util/SQLTypeMap.java  |   4 +-
 .../java/org/apache/kylin/jdbc2/Driver.java     | 145 +++++++++
 .../org/apache/kylin/jdbc2/IRemoteClient.java   |  55 ++++
 .../org/apache/kylin/jdbc2/KylinClient.java     | 287 +++++++++++++++++
 .../org/apache/kylin/jdbc2/KylinConnection.java | 119 +++++++
 .../apache/kylin/jdbc2/KylinJdbcFactory.java    | 108 +++++++
 .../java/org/apache/kylin/jdbc2/KylinMeta.java  |  96 ++++++
 .../kylin/jdbc2/KylinPreparedStatement.java     | 100 ++++++
 .../org/apache/kylin/jdbc2/KylinResultSet.java  |  66 ++++
 .../org/apache/kylin/jdbc2/KylinStatement.java  |  31 ++
 .../kylin/jdbc2/json/PreparedQueryRequest.java  |  33 ++
 .../apache/kylin/jdbc2/json/QueryRequest.java   |  40 +++
 .../kylin/jdbc2/json/SQLResponseStub.java       | 321 +++++++++++++++++++
 .../kylin/jdbc2/json/StatementParameter.java    |  47 +++
 .../java/org/apache/kylin/jdbc/DriverTest.java  | 174 ----------
 .../java/org/apache/kylin/jdbc/DummyClient.java |  80 -----
 .../java/org/apache/kylin/jdbc/DummyDriver.java |  32 --
 .../apache/kylin/jdbc/DummyJdbc41Factory.java   |  35 --
 .../java/org/apache/kylin/jdbc2/DriverTest.java | 178 ++++++++++
 .../org/apache/kylin/jdbc2/DummyClient.java     |  76 +++++
 .../org/apache/kylin/jdbc2/DummyDriver.java     |  30 ++
 .../apache/kylin/jdbc2/DummyJdbcFactory.java    |  35 ++
 .../java/org/apache/kylin/query/QueryCli.java   |   4 +-
 .../kylin/rest/controller/QueryController.java  |  27 +-
 .../apache/kylin/rest/service/BasicService.java |   3 +-
 .../org/apache/kylin/rest/util/QueryUtil.java   |  22 +-
 28 files changed, 1805 insertions(+), 349 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc/stub/KylinColumnMetaData.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/stub/KylinColumnMetaData.java b/jdbc/src/main/java/org/apache/kylin/jdbc/stub/KylinColumnMetaData.java
index e0e14e7..92b0c19 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/stub/KylinColumnMetaData.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/stub/KylinColumnMetaData.java
@@ -20,11 +20,9 @@ package org.apache.kylin.jdbc.stub;
 
 import java.sql.DatabaseMetaData;
 
-import net.hydromatic.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.ColumnMetaData;
 
 /**
- * @author xduo
- * 
  */
 public class KylinColumnMetaData extends ColumnMetaData {
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc/util/DefaultSslProtocolSocketFactory.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/util/DefaultSslProtocolSocketFactory.java b/jdbc/src/main/java/org/apache/kylin/jdbc/util/DefaultSslProtocolSocketFactory.java
index 9ed24cc..d607ac5 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/util/DefaultSslProtocolSocketFactory.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/util/DefaultSslProtocolSocketFactory.java
@@ -35,8 +35,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * @author xduo
- * 
  */
 public class DefaultSslProtocolSocketFactory implements SecureProtocolSocketFactory {
     /** Log object for this class. */

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc/util/SQLTypeMap.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/util/SQLTypeMap.java b/jdbc/src/main/java/org/apache/kylin/jdbc/util/SQLTypeMap.java
index c4090ab..44092ba 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/util/SQLTypeMap.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/util/SQLTypeMap.java
@@ -26,8 +26,8 @@ import java.sql.Types;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import net.hydromatic.avatica.ColumnMetaData;
-import net.hydromatic.avatica.ColumnMetaData.Rep;
+import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.ColumnMetaData.Rep;
 
 import org.apache.kylin.jdbc.stub.KylinColumnMetaData;
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/Driver.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/Driver.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/Driver.java
new file mode 100644
index 0000000..b15d7d0
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/Driver.java
@@ -0,0 +1,145 @@
+/*
+ * 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.kylin.jdbc2;
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import org.apache.calcite.avatica.AvaticaConnection;
+import org.apache.calcite.avatica.DriverVersion;
+import org.apache.calcite.avatica.Meta;
+import org.apache.calcite.avatica.UnregisteredDriver;
+import org.apache.kylin.jdbc.KylinPrepareStatementImpl;
+import org.apache.kylin.jdbc.KylinStatementImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <p>
+ * Kylin JDBC Driver based on Calcite Avatica and Kylin restful API.<br>
+ * Supported versions:
+ * </p>
+ * <ul>
+ * <li>jdbc 4.0</li>
+ * <li>jdbc 4.1</li>
+ * </ul>
+ * 
+ * <p>
+ * Supported Statements:
+ * </p>
+ * <ul>
+ * <li>{@link KylinStatementImpl}</li>
+ * <li>{@link KylinPrepareStatementImpl}</li>
+ * </ul>
+ * 
+ * <p>
+ * Supported properties:
+ * <ul>
+ * <li>user: username</li>
+ * <li>password: password</li>
+ * <li>ssl: true/false</li>
+ * </ul>
+ * </p>
+ * 
+ * <p>
+ * Driver init code sample:<br>
+ * 
+ * <pre>
+ * Driver driver = (Driver) Class.forName(&quot;org.apache.kylin.kylin.jdbc.Driver&quot;).newInstance();
+ * Properties info = new Properties();
+ * info.put(&quot;user&quot;, &quot;user&quot;);
+ * info.put(&quot;password&quot;, &quot;password&quot;);
+ * info.put(&quot;ssl&quot;, true);
+ * Connection conn = driver.connect(&quot;jdbc:kylin://{domain}/{project}&quot;, info);
+ * </pre>
+ * 
+ * </p>
+ */
+public class Driver extends UnregisteredDriver {
+    private static final Logger logger = LoggerFactory.getLogger(Driver.class);
+
+    public static final String CONNECT_STRING_PREFIX = "jdbc:kylin:";
+    static {
+        try {
+            DriverManager.registerDriver(new Driver());
+        } catch (SQLException e) {
+            throw new RuntimeException("Error occurred while registering JDBC driver " + Driver.class.getName() + ": " + e.toString());
+        }
+    }
+    
+    @Override
+    protected String getConnectStringPrefix() {
+        return CONNECT_STRING_PREFIX;
+    }
+
+    @Override
+    protected DriverVersion createDriverVersion() {
+        return DriverVersion.load(Driver.class, "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 KylinJdbcFactory.Version40.class.getName();
+        case JDBC_41:
+        default:
+            return KylinJdbcFactory.Version41.class.getName();
+        }
+    }
+
+    @Override
+    public Meta createMeta(AvaticaConnection connection) {
+        return new KylinMeta((KylinConnection) connection);
+    }
+
+//    @Override
+//    protected Handler createHandler() {
+//        return new HandlerImpl() {
+//            @Override
+//            public void onConnectionInit(AvaticaConnection connection) throws SQLException {
+//                KylinConnection conn = (KylinConnection) connection;
+//                RemoteClient runner = ((KylinJdbcFactory) factory).newRemoteClient(conn);
+//                try {
+//                    runner.connect();
+//                    conn.setMetaProject(runner.getMetadata(conn.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.");
+//            }
+//        };
+//    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/IRemoteClient.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/IRemoteClient.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/IRemoteClient.java
new file mode 100644
index 0000000..94073b1
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/IRemoteClient.java
@@ -0,0 +1,55 @@
+/*
+ * 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.kylin.jdbc2;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.kylin.jdbc.KylinMetaImpl.MetaProject;
+
+public interface IRemoteClient {
+
+    public static class QueryResult {
+        public final List<ColumnMetaData> columnMeta;
+        public final Iterable<Object> iterable;
+
+        public QueryResult(List<ColumnMetaData> columnMeta, Iterable<Object> iterable) {
+            this.columnMeta = columnMeta;
+            this.iterable = iterable;
+        }
+    }
+
+    /**
+     * Connect to Kylin restful service. IOException will be thrown if authentication failed.
+     */
+    public void connect() throws IOException;
+
+    /**
+     * Retrieve meta data of given project.
+     */
+    public MetaProject retrieveMetaData(String project) throws IOException;
+
+    /**
+     * Execute query remotely and get back result.
+     */
+    public QueryResult executeQuery(String sql, List<AvaticaParameter> params, List<Object> paramValues) throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinClient.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinClient.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinClient.java
new file mode 100644
index 0000000..310d850
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinClient.java
@@ -0,0 +1,287 @@
+package org.apache.kylin.jdbc2;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.ColumnMetaData.Rep;
+import org.apache.calcite.avatica.ColumnMetaData.ScalarType;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
+import org.apache.kylin.jdbc.KylinMetaImpl.MetaProject;
+import org.apache.kylin.jdbc.util.DefaultSslProtocolSocketFactory;
+import org.apache.kylin.jdbc.util.SQLTypeMap;
+import org.apache.kylin.jdbc2.json.PreparedQueryRequest;
+import org.apache.kylin.jdbc2.json.QueryRequest;
+import org.apache.kylin.jdbc2.json.SQLResponseStub;
+import org.apache.kylin.jdbc2.json.StatementParameter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class KylinClient implements IRemoteClient {
+
+    private static final Logger logger = LoggerFactory.getLogger(KylinClient.class);
+
+    private final KylinConnection conn;
+    private final Properties connProps;
+    private final HttpClient httpClient;
+    private final ObjectMapper jsonMapper;
+
+    public KylinClient(KylinConnection conn) {
+        this.conn = conn;
+        this.connProps = conn.getConnectionProperties();
+        this.httpClient = new HttpClient();
+        this.jsonMapper = new ObjectMapper();
+
+        // trust all certificates
+        if (isSSL()) {
+            Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) new DefaultSslProtocolSocketFactory(), 443));
+        }
+    }
+
+    private boolean isSSL() {
+        return Boolean.parseBoolean(connProps.getProperty("ssl", "false"));
+    }
+
+    private String baseUrl() {
+        return (isSSL() ? "https://" : "http://") + conn.getBaseUrl();
+    }
+
+    private String getMetaProjectUrl(String project) {
+        return baseUrl() + "/kylin/api/tables_and_columns?project=" + project;
+    }
+
+    private void addPostHeaders(HttpMethodBase method) {
+        method.addRequestHeader("Accept", "application/json, text/plain, */*");
+        method.addRequestHeader("Content-Type", "application/json");
+
+        String username = connProps.getProperty("user");
+        String password = connProps.getProperty("password");
+        String basicAuth = DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
+        method.addRequestHeader("Authorization", "Basic " + basicAuth);
+    }
+
+    @Override
+    public void connect() throws IOException {
+        PostMethod post = new PostMethod(baseUrl() + "/kylin/api/user/authentication");
+        addPostHeaders(post);
+        StringRequestEntity requestEntity = new StringRequestEntity("{}", "application/json", "UTF-8");
+        post.setRequestEntity(requestEntity);
+
+        httpClient.executeMethod(post);
+
+        if (post.getStatusCode() != 200 && post.getStatusCode() != 201) {
+            throw asIOException(post);
+        }
+    }
+
+    private IOException asIOException(HttpMethodBase method) throws IOException {
+        return new IOException(method + " failed, error code " + method.getStatusCode() + " and response: " + method.getResponseBodyAsString());
+    }
+
+    @Override
+    public MetaProject retrieveMetaData(String project) throws IOException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public QueryResult executeQuery(String sql, List<AvaticaParameter> params, List<Object> paramValues) throws IOException {
+
+        SQLResponseStub queryResp = executeKylinQuery(sql, convertParameters(params, paramValues));
+        if (queryResp.getIsException())
+            throw new IOException(queryResp.getExceptionMessage());
+
+        List<ColumnMetaData> metas = convertColumnMeta(queryResp);
+        List<Object> data = convertResultData(queryResp, metas);
+
+        return new QueryResult(metas, data);
+    }
+
+    private List<StatementParameter> convertParameters(List<AvaticaParameter> params, List<Object> paramValues) {
+        if (params == null || params.isEmpty())
+            return null;
+
+        assert params.size() == paramValues.size();
+
+        List<StatementParameter> result = new ArrayList<StatementParameter>();
+        for (Object v : paramValues) {
+            result.add(new StatementParameter(v.getClass().getCanonicalName(), String.valueOf(v)));
+        }
+        return result;
+    }
+
+    private SQLResponseStub executeKylinQuery(String sql, List<StatementParameter> params) throws IOException {
+        String url = baseUrl() + "/kylin/api/query";
+        String project = conn.getProject();
+
+        QueryRequest request = null;
+        if (null != params) {
+            request = new PreparedQueryRequest();
+            ((PreparedQueryRequest) request).setParams(params);
+            url += "/prestate"; // means prepared statement..
+        } else {
+            request = new QueryRequest();
+        }
+        request.setSql(sql);
+        request.setProject(project);
+
+        PostMethod post = new PostMethod(url);
+        addPostHeaders(post);
+
+        String postBody = jsonMapper.writeValueAsString(request);
+        logger.debug("Post body:\n " + postBody);
+        StringRequestEntity requestEntity = new StringRequestEntity(postBody, "application/json", "UTF-8");
+        post.setRequestEntity(requestEntity);
+
+        httpClient.executeMethod(post);
+
+        if (post.getStatusCode() != 200 && post.getStatusCode() != 201) {
+            throw asIOException(post);
+        }
+
+        return jsonMapper.readValue(post.getResponseBodyAsStream(), SQLResponseStub.class);
+    }
+
+    private List<ColumnMetaData> convertColumnMeta(SQLResponseStub queryResp) {
+        List<ColumnMetaData> metas = new ArrayList<ColumnMetaData>();
+        for (int i = 0; i < queryResp.getColumnMetas().size(); i++) {
+            SQLResponseStub.ColumnMetaStub scm = queryResp.getColumnMetas().get(i);
+            ScalarType type = ColumnMetaData.scalar(scm.getColumnType(), scm.getColumnTypeName(), Rep.of(convertType(scm.getColumnType())));
+
+            ColumnMetaData meta = new ColumnMetaData(i, scm.isAutoIncrement(), scm.isCaseSensitive(), scm.isSearchable(), scm.isCurrency(), scm.getIsNullable(), scm.isSigned(), scm.getDisplaySize(), scm.getLabel(), scm.getName(), scm.getSchemaName(), scm.getPrecision(), scm.getScale(), scm.getTableName(), scm.getSchemaName(), type, scm.isReadOnly(), scm.isWritable(), scm.isWritable(), null);
+
+            metas.add(meta);
+        }
+
+        return metas;
+    }
+
+    private List<Object> convertResultData(SQLResponseStub queryResp, List<ColumnMetaData> metas) {
+        List<String[]> stringResults = queryResp.getResults();
+        List<Object> data = new ArrayList<Object>(stringResults.size());
+        for (String[] result : stringResults) {
+            Object[] row = new Object[result.length];
+
+            for (int i = 0; i < result.length; i++) {
+                ColumnMetaData meta = metas.get(i);
+                row[i] = SQLTypeMap.wrapObject(result[i], meta.type.type);
+            }
+
+            data.add(row);
+        }
+        return (List<Object>) data;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static Class convertType(int sqlType) {
+        Class result = Object.class;
+
+        switch (sqlType) {
+        case Types.CHAR:
+        case Types.VARCHAR:
+        case Types.LONGVARCHAR:
+            result = String.class;
+            break;
+        case Types.NUMERIC:
+        case Types.DECIMAL:
+            result = BigDecimal.class;
+            break;
+        case Types.BIT:
+            result = Boolean.class;
+            break;
+        case Types.TINYINT:
+            result = Byte.class;
+            break;
+        case Types.SMALLINT:
+            result = Short.class;
+            break;
+        case Types.INTEGER:
+            result = Integer.class;
+            break;
+        case Types.BIGINT:
+            result = Long.class;
+            break;
+        case Types.REAL:
+        case Types.FLOAT:
+        case Types.DOUBLE:
+            result = Double.class;
+            break;
+        case Types.BINARY:
+        case Types.VARBINARY:
+        case Types.LONGVARBINARY:
+            result = Byte[].class;
+            break;
+        case Types.DATE:
+            result = Date.class;
+            break;
+        case Types.TIME:
+            result = Time.class;
+            break;
+        case Types.TIMESTAMP:
+            result = Timestamp.class;
+            break;
+        }
+
+        return result;
+    }
+
+    public static Object wrapObject(String value, int sqlType) {
+        if (null == value) {
+            return null;
+        }
+
+        switch (sqlType) {
+        case Types.CHAR:
+        case Types.VARCHAR:
+        case Types.LONGVARCHAR:
+            return value;
+        case Types.NUMERIC:
+        case Types.DECIMAL:
+            return new BigDecimal(value);
+        case Types.BIT:
+            return Boolean.parseBoolean(value);
+        case Types.TINYINT:
+            return Byte.valueOf(value);
+        case Types.SMALLINT:
+            return Short.valueOf(value);
+        case Types.INTEGER:
+            return Integer.parseInt(value);
+        case Types.BIGINT:
+            return Long.parseLong(value);
+        case Types.FLOAT:
+            return Float.parseFloat(value);
+        case Types.REAL:
+        case Types.DOUBLE:
+            return Double.parseDouble(value);
+        case Types.BINARY:
+        case Types.VARBINARY:
+        case Types.LONGVARBINARY:
+            return value.getBytes();
+        case Types.DATE:
+            return Date.valueOf(value);
+        case Types.TIME:
+            return Time.valueOf(value);
+        case Types.TIMESTAMP:
+            return Timestamp.valueOf(value);
+        }
+
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinConnection.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinConnection.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinConnection.java
new file mode 100644
index 0000000..3d5c142
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinConnection.java
@@ -0,0 +1,119 @@
+/*
+ * 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.kylin.jdbc2;
+
+import java.io.IOException;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.calcite.avatica.AvaticaConnection;
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.AvaticaStatement;
+import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.Meta;
+import org.apache.calcite.avatica.Meta.CursorFactory;
+import org.apache.calcite.avatica.Meta.Signature;
+import org.apache.calcite.avatica.UnregisteredDriver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class KylinConnection extends AvaticaConnection {
+
+    private static final Logger logger = LoggerFactory.getLogger(KylinConnection.class);
+
+    private final String baseUrl;
+    private final String project;
+    private final IRemoteClient remoteClient;
+
+    protected KylinConnection(UnregisteredDriver driver, KylinJdbcFactory factory, String url, Properties info) throws SQLException {
+        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);
+        
+        this.remoteClient = factory.newRemoteClient(this);
+
+        try {
+            this.remoteClient.connect();
+        } catch (IOException e) {
+            throw new SQLException(e);
+        }
+    }
+    
+    String getBaseUrl() {
+        return baseUrl;
+    }
+    
+    String getProject() {
+        return project;
+    }
+    
+    Properties getConnectionProperties() {
+        return info;
+    }
+    
+    @Override
+    public AvaticaStatement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+        return super.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+
+    @Override
+    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+        Meta.Signature sig = mockPreparedSignature(sql);
+        return factory().newPreparedStatement(this, null, sig, resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+    
+    // TODO add restful API to prepare SQL, get back expected ResultSetMetaData
+    Signature mockPreparedSignature(String sql) {
+        List<AvaticaParameter> params = new ArrayList<AvaticaParameter>();
+        int startIndex = 0;
+        while (sql.indexOf("?", startIndex) >= 0) {
+            AvaticaParameter param = new AvaticaParameter(false, 0, 0, 0, null, null, null);
+            params.add(param);
+            startIndex = sql.indexOf("?", startIndex) + 1;
+        }
+
+        ArrayList<ColumnMetaData> columns = new ArrayList<ColumnMetaData>();
+        Map<String, Object> internalParams = Collections.<String, Object>emptyMap();
+        
+        return new Meta.Signature(columns, sql, params, internalParams, CursorFactory.ARRAY);
+    }
+
+    private KylinJdbcFactory factory() {
+        return (KylinJdbcFactory) factory;
+    }
+
+    public IRemoteClient getRemoteClient() {
+        return remoteClient;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinJdbcFactory.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinJdbcFactory.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinJdbcFactory.java
new file mode 100644
index 0000000..329382a
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinJdbcFactory.java
@@ -0,0 +1,108 @@
+/*
+ * 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.kylin.jdbc2;
+
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Properties;
+import java.util.TimeZone;
+
+import org.apache.calcite.avatica.AvaticaConnection;
+import org.apache.calcite.avatica.AvaticaDatabaseMetaData;
+import org.apache.calcite.avatica.AvaticaFactory;
+import org.apache.calcite.avatica.AvaticaPreparedStatement;
+import org.apache.calcite.avatica.AvaticaResultSet;
+import org.apache.calcite.avatica.AvaticaResultSetMetaData;
+import org.apache.calcite.avatica.AvaticaStatement;
+import org.apache.calcite.avatica.Meta.Signature;
+import org.apache.calcite.avatica.Meta.StatementHandle;
+import org.apache.calcite.avatica.UnregisteredDriver;
+
+/**
+ * Kylin JDBC factory.
+ */
+public class KylinJdbcFactory implements AvaticaFactory {
+
+    public static class Version40 extends KylinJdbcFactory {
+        public Version40() {
+            super(4, 0);
+        }
+    }
+
+    public static class Version41 extends KylinJdbcFactory {
+        public Version41() {
+            super(4, 1);
+        }
+    }
+
+    final int major;
+    final int minor;
+
+    /** Creates a JDBC factory with given major/minor version number. */
+    protected KylinJdbcFactory(int major, int minor) {
+        this.major = major;
+        this.minor = minor;
+    }
+
+    @Override
+    public int getJdbcMajorVersion() {
+        return major;
+    }
+
+    @Override
+    public int getJdbcMinorVersion() {
+        return minor;
+    }
+
+    @Override
+    public AvaticaConnection newConnection(UnregisteredDriver driver, AvaticaFactory factory, String url, Properties info) throws SQLException {
+        return new KylinConnection(driver, (KylinJdbcFactory) factory, url, info);
+    }
+
+    @Override
+    public AvaticaDatabaseMetaData newDatabaseMetaData(AvaticaConnection connection) {
+        return new AvaticaDatabaseMetaData(connection) {
+        };
+    }
+
+    @Override
+    public AvaticaStatement newStatement(AvaticaConnection connection, StatementHandle h, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+        return new KylinStatement((KylinConnection) connection, h, resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+
+    @Override
+    public AvaticaPreparedStatement newPreparedStatement(AvaticaConnection connection, StatementHandle h, Signature signature, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+        return new KylinPreparedStatement((KylinConnection) connection, h, signature, resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+
+    @Override
+    public AvaticaResultSet newResultSet(AvaticaStatement statement, Signature signature, TimeZone timeZone, Iterable<Object> iterable) throws SQLException {
+        AvaticaResultSetMetaData resultSetMetaData = new AvaticaResultSetMetaData(statement, null, signature);
+        return new KylinResultSet(statement, signature, resultSetMetaData, timeZone, iterable);
+    }
+
+    @Override
+    public ResultSetMetaData newResultSetMetaData(AvaticaStatement statement, Signature signature) throws SQLException {
+        return new AvaticaResultSetMetaData(statement, null, signature);
+    }
+
+    public IRemoteClient newRemoteClient(KylinConnection conn) {
+        return new KylinClient(conn);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinMeta.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinMeta.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinMeta.java
new file mode 100644
index 0000000..0b8615a
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinMeta.java
@@ -0,0 +1,96 @@
+/*
+ * 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.kylin.jdbc2;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.calcite.avatica.MetaImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of avatica interface
+ */
+public class KylinMeta extends MetaImpl {
+
+    public KylinMeta(KylinConnection connection) {
+        super(connection);
+    }
+
+    private static final Logger logger = LoggerFactory.getLogger(KylinMeta.class);
+
+    private KylinConnection connection() {
+        return (KylinConnection) connection;
+    }
+
+    // insert/update/delete go this path, ignorable for Kylin
+    @Override
+    public Signature prepare(StatementHandle h, String sql, int maxRowCount) {
+        return connection().mockPreparedSignature(sql);
+    }
+
+    // mimic from CalciteMetaImpl, real execution happens in KylinResultSet.execute()
+    @Override
+    public MetaResultSet prepareAndExecute(StatementHandle h, String sql, int maxRowCount, PrepareCallback callback) {
+        final Signature signature;
+        try {
+            synchronized (callback.getMonitor()) {
+                callback.clear();
+                signature = prepare(h, sql, maxRowCount);
+                callback.assign(signature, null);
+            }
+            callback.execute();
+            return new MetaResultSet(h.id, false, signature, null);
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public MetaResultSet getSchemas(String catalog, Pat schemaPattern) {
+        // TODO Auto-generated method stub
+        return super.getSchemas(catalog, schemaPattern);
+    }
+
+    @Override
+    public MetaResultSet getCatalogs() {
+        // TODO Auto-generated method stub
+        return super.getCatalogs();
+    }
+
+    @Override
+    public MetaResultSet getTableTypes() {
+        // TODO Auto-generated method stub
+        return super.getTableTypes();
+    }
+
+    @Override
+    public MetaResultSet getTables(String catalog, Pat schemaPattern, Pat tableNamePattern, List<String> typeList) {
+        // TODO Auto-generated method stub
+        return super.getTables(catalog, schemaPattern, tableNamePattern, typeList);
+    }
+
+    @Override
+    public MetaResultSet getColumns(String catalog, Pat schemaPattern, Pat tableNamePattern, Pat columnNamePattern) {
+        // TODO Auto-generated method stub
+        return super.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinPreparedStatement.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinPreparedStatement.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinPreparedStatement.java
new file mode 100644
index 0000000..6e0e490
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinPreparedStatement.java
@@ -0,0 +1,100 @@
+package org.apache.kylin.jdbc2;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.sql.NClob;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.calcite.avatica.AvaticaConnection;
+import org.apache.calcite.avatica.AvaticaPreparedStatement;
+import org.apache.calcite.avatica.Meta.Signature;
+import org.apache.calcite.avatica.Meta.StatementHandle;
+
+public class KylinPreparedStatement extends AvaticaPreparedStatement {
+
+    protected KylinPreparedStatement(AvaticaConnection connection, StatementHandle h, Signature signature, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+        super(connection, h, signature, resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+    
+    protected List<Object> getParameterValues() {
+        return Arrays.asList(slots);
+    }
+    
+    // ============================================================================
+
+    public void setRowId(int parameterIndex, RowId x) throws SQLException {
+        getParameter(parameterIndex).setRowId(slots, parameterIndex, x);
+    }
+
+    public void setNString(int parameterIndex, String value) throws SQLException {
+        getParameter(parameterIndex).setNString(slots, parameterIndex, value);
+    }
+
+    public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
+        getParameter(parameterIndex).setNCharacterStream(slots, parameterIndex, value, length);
+    }
+
+    public void setNClob(int parameterIndex, NClob value) throws SQLException {
+        getParameter(parameterIndex).setNClob(slots, parameterIndex, value);
+    }
+
+    public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
+        getParameter(parameterIndex).setClob(slots, parameterIndex, reader, length);
+    }
+
+    public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
+        getParameter(parameterIndex).setBlob(slots, parameterIndex, inputStream, length);
+    }
+
+    public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
+        getParameter(parameterIndex).setNClob(slots, parameterIndex, reader, length);
+    }
+
+    public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
+        getParameter(parameterIndex).setSQLXML(slots, parameterIndex, xmlObject);
+    }
+
+    public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
+        getParameter(parameterIndex).setAsciiStream(slots, parameterIndex, x, length);
+    }
+
+    public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
+        getParameter(parameterIndex).setBinaryStream(slots, parameterIndex, x, length);
+    }
+
+    public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
+        getParameter(parameterIndex).setCharacterStream(slots, parameterIndex, reader, length);
+    }
+
+    public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
+        getParameter(parameterIndex).setAsciiStream(slots, parameterIndex, x);
+    }
+
+    public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
+        getParameter(parameterIndex).setBinaryStream(slots, parameterIndex, x);
+    }
+
+    public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
+        getParameter(parameterIndex).setCharacterStream(slots, parameterIndex, reader);
+    }
+
+    public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
+        getParameter(parameterIndex).setNCharacterStream(slots, parameterIndex, value);
+    }
+
+    public void setClob(int parameterIndex, Reader reader) throws SQLException {
+        getParameter(parameterIndex).setClob(slots, parameterIndex, reader);
+    }
+
+    public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
+        getParameter(parameterIndex).setBlob(slots, parameterIndex, inputStream);
+    }
+
+    public void setNClob(int parameterIndex, Reader reader) throws SQLException {
+        getParameter(parameterIndex).setNClob(slots, parameterIndex, reader);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinResultSet.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinResultSet.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinResultSet.java
new file mode 100644
index 0000000..a1d0e9b
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinResultSet.java
@@ -0,0 +1,66 @@
+/*
+ * 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.kylin.jdbc2;
+
+import java.io.IOException;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.TimeZone;
+
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.AvaticaResultSet;
+import org.apache.calcite.avatica.AvaticaStatement;
+import org.apache.calcite.avatica.Meta.Signature;
+import org.apache.calcite.avatica.MetaImpl;
+import org.apache.kylin.jdbc2.IRemoteClient.QueryResult;
+
+public class KylinResultSet extends AvaticaResultSet {
+
+    public KylinResultSet(AvaticaStatement statement, Signature signature, ResultSetMetaData resultSetMetaData, TimeZone timeZone, Iterable<Object> iterable) {
+        super(statement, signature, resultSetMetaData, timeZone, iterable);
+    }
+
+    @Override
+    protected AvaticaResultSet execute() throws SQLException {
+        String sql = signature.sql;
+        List<AvaticaParameter> params = signature.parameters;
+        List<Object> paramValues = null;
+        if (params != null && params.size() > 0) {
+            paramValues = ((KylinPreparedStatement) statement).getParameterValues();
+        }
+        
+        IRemoteClient client = ((KylinConnection) statement.connection).getRemoteClient();
+        QueryResult result;
+        try {
+            result = client.executeQuery(sql, params, paramValues);
+        } catch (IOException e) {
+            throw new SQLException(e);
+        }
+        
+        columnMetaDataList.clear();
+        columnMetaDataList.addAll(result.columnMeta);
+        
+        cursor = MetaImpl.createCursor(signature.cursorFactory, result.iterable);
+        return super.execute2(cursor, columnMetaDataList);
+    }
+    
+    
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinStatement.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinStatement.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinStatement.java
new file mode 100644
index 0000000..4d9dc83
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/KylinStatement.java
@@ -0,0 +1,31 @@
+/*
+ * 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.kylin.jdbc2;
+
+import org.apache.calcite.avatica.AvaticaConnection;
+import org.apache.calcite.avatica.AvaticaStatement;
+import org.apache.calcite.avatica.Meta.StatementHandle;
+
+public class KylinStatement extends AvaticaStatement {
+
+    protected KylinStatement(AvaticaConnection connection, StatementHandle h, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
+        super(connection, h, resultSetType, resultSetConcurrency, resultSetHoldability);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/json/PreparedQueryRequest.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/json/PreparedQueryRequest.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/json/PreparedQueryRequest.java
new file mode 100644
index 0000000..555ecc2
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/json/PreparedQueryRequest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.kylin.jdbc2.json;
+
+import java.util.List;
+
+public class PreparedQueryRequest extends QueryRequest {
+    private List<StatementParameter> params;
+
+    public List<StatementParameter> getParams() {
+        return params;
+    }
+
+    public void setParams(List<StatementParameter> params) {
+        this.params = params;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/json/QueryRequest.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/json/QueryRequest.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/json/QueryRequest.java
new file mode 100644
index 0000000..43205b2
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/json/QueryRequest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.kylin.jdbc2.json;
+
+public class QueryRequest {
+    private String sql;
+    private String project;
+
+    public String getSql() {
+        return sql;
+    }
+
+    public void setSql(String sql) {
+        this.sql = sql;
+    }
+
+    public String getProject() {
+        return project;
+    }
+
+    public void setProject(String project) {
+        this.project = project;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/json/SQLResponseStub.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/json/SQLResponseStub.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/json/SQLResponseStub.java
new file mode 100644
index 0000000..fb34a4a
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/json/SQLResponseStub.java
@@ -0,0 +1,321 @@
+/*
+ * 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.kylin.jdbc2.json;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ */
+public class SQLResponseStub implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // private static final Logger logger =
+    // LoggerFactory.getLogger(SQLResponse.class);
+
+    // the data type for each column
+    private List<ColumnMetaStub> columnMetas;
+
+    // the results rows, each row contains several columns
+    private List<String[]> results;
+
+    private String cube;
+
+    // if not select query, only return affected row count
+    private int affectedRowCount;
+
+    // if isException, the detailed exception message
+    private String exceptionMessage;
+
+    private boolean isException;
+
+    private long duration;
+
+    private boolean isPartial = false;
+
+    private long totalScanCount;
+
+    private boolean hitCache = false;
+
+    public SQLResponseStub() {
+    }
+
+    public List<ColumnMetaStub> getColumnMetas() {
+        return columnMetas;
+    }
+
+    public void setColumnMetas(List<ColumnMetaStub> columnMetas) {
+        this.columnMetas = columnMetas;
+    }
+
+    public List<String[]> getResults() {
+        return results;
+    }
+
+    public void setResults(List<String[]> results) {
+        this.results = results;
+    }
+
+    public String getCube() {
+        return cube;
+    }
+
+    public void setCube(String cube) {
+        this.cube = cube;
+    }
+
+    public int getAffectedRowCount() {
+        return affectedRowCount;
+    }
+
+    public void setAffectedRowCount(int affectedRowCount) {
+        this.affectedRowCount = affectedRowCount;
+    }
+
+    public boolean getIsException() {
+        return isException;
+    }
+
+    public void setIsException(boolean isException) {
+        this.isException = isException;
+    }
+
+    public String getExceptionMessage() {
+        return exceptionMessage;
+    }
+
+    public void setExceptionMessage(String exceptionMessage) {
+        this.exceptionMessage = exceptionMessage;
+    }
+
+    public long getDuration() {
+        return duration;
+    }
+
+    public void setDuration(long duration) {
+        this.duration = duration;
+    }
+
+    public boolean isPartial() {
+        return isPartial;
+    }
+
+    public void setPartial(boolean isPartial) {
+        this.isPartial = isPartial;
+    }
+
+    public long getTotalScanCount() {
+        return totalScanCount;
+    }
+
+    public void setTotalScanCount(long totalScanCount) {
+        this.totalScanCount = totalScanCount;
+    }
+
+    public boolean isHitCache() {
+        return hitCache;
+    }
+
+    public void setHitCache(boolean hitCache) {
+        this.hitCache = hitCache;
+    }
+
+    public static long getSerialversionuid() {
+        return serialVersionUID;
+    }
+
+    public static class ColumnMetaStub {
+
+        private boolean isAutoIncrement;
+        private boolean isCaseSensitive;
+        private boolean isSearchable;
+        private boolean isCurrency;
+        private int isNullable;// 0:nonull, 1:nullable, 2: nullableunknown
+        private boolean isSigned;
+        private int displaySize;
+        private String label;// AS keyword
+        private String name;
+        private String schemaName;
+        private String catelogName;
+        private String tableName;
+        private int precision;
+        private int scale;
+        private int columnType;// as defined in java.sql.Types
+        private String columnTypeName;
+        private boolean isReadOnly;
+        private boolean isWritable;
+        private boolean isDefinitelyWritable;
+
+        public ColumnMetaStub() {
+        }
+
+        public boolean isAutoIncrement() {
+            return isAutoIncrement;
+        }
+
+        public void setAutoIncrement(boolean isAutoIncrement) {
+            this.isAutoIncrement = isAutoIncrement;
+        }
+
+        public boolean isCaseSensitive() {
+            return isCaseSensitive;
+        }
+
+        public void setCaseSensitive(boolean isCaseSensitive) {
+            this.isCaseSensitive = isCaseSensitive;
+        }
+
+        public boolean isSearchable() {
+            return isSearchable;
+        }
+
+        public void setSearchable(boolean isSearchable) {
+            this.isSearchable = isSearchable;
+        }
+
+        public boolean isCurrency() {
+            return isCurrency;
+        }
+
+        public void setCurrency(boolean isCurrency) {
+            this.isCurrency = isCurrency;
+        }
+
+        public int getIsNullable() {
+            return isNullable;
+        }
+
+        public void setIsNullable(int isNullable) {
+            this.isNullable = isNullable;
+        }
+
+        public boolean isSigned() {
+            return isSigned;
+        }
+
+        public void setSigned(boolean isSigned) {
+            this.isSigned = isSigned;
+        }
+
+        public int getDisplaySize() {
+            return displaySize;
+        }
+
+        public void setDisplaySize(int displaySize) {
+            this.displaySize = displaySize;
+        }
+
+        public String getLabel() {
+            return label;
+        }
+
+        public void setLabel(String label) {
+            this.label = label;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getSchemaName() {
+            return schemaName;
+        }
+
+        public void setSchemaName(String schemaName) {
+            this.schemaName = schemaName;
+        }
+
+        public String getCatelogName() {
+            return catelogName;
+        }
+
+        public void setCatelogName(String catelogName) {
+            this.catelogName = catelogName;
+        }
+
+        public String getTableName() {
+            return tableName;
+        }
+
+        public void setTableName(String tableName) {
+            this.tableName = tableName;
+        }
+
+        public int getPrecision() {
+            return precision;
+        }
+
+        public void setPrecision(int precision) {
+            this.precision = precision;
+        }
+
+        public int getScale() {
+            return scale;
+        }
+
+        public void setScale(int scale) {
+            this.scale = scale;
+        }
+
+        public int getColumnType() {
+            return columnType;
+        }
+
+        public void setColumnType(int columnType) {
+            this.columnType = columnType;
+        }
+
+        public String getColumnTypeName() {
+            return columnTypeName;
+        }
+
+        public void setColumnTypeName(String columnTypeName) {
+            this.columnTypeName = columnTypeName;
+        }
+
+        public boolean isReadOnly() {
+            return isReadOnly;
+        }
+
+        public void setReadOnly(boolean isReadOnly) {
+            this.isReadOnly = isReadOnly;
+        }
+
+        public boolean isWritable() {
+            return isWritable;
+        }
+
+        public void setWritable(boolean isWritable) {
+            this.isWritable = isWritable;
+        }
+
+        public boolean isDefinitelyWritable() {
+            return isDefinitelyWritable;
+        }
+
+        public void setDefinitelyWritable(boolean isDefinitelyWritable) {
+            this.isDefinitelyWritable = isDefinitelyWritable;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/main/java/org/apache/kylin/jdbc2/json/StatementParameter.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc2/json/StatementParameter.java b/jdbc/src/main/java/org/apache/kylin/jdbc2/json/StatementParameter.java
new file mode 100644
index 0000000..6234fc3
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc2/json/StatementParameter.java
@@ -0,0 +1,47 @@
+/*
+ * 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.kylin.jdbc2.json;
+
+public class StatementParameter {
+
+    private String className;
+    private String value;
+
+    public StatementParameter(String className, String value) {
+        this.className = className;
+        this.value = value;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClazz(String className) {
+        this.className = className;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/test/java/org/apache/kylin/jdbc/DriverTest.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/kylin/jdbc/DriverTest.java b/jdbc/src/test/java/org/apache/kylin/jdbc/DriverTest.java
deleted file mode 100644
index 4594e1a..0000000
--- a/jdbc/src/test/java/org/apache/kylin/jdbc/DriverTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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.kylin.jdbc;
-
-import static org.junit.Assert.*;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.Properties;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
-/**
- * Unit test for Driver.
- * 
- * @author xduo
- * 
- */
-public class DriverTest {
-
-    @Test
-    public void testStatementWithMockData() throws SQLException {
-        Driver driver = new DummyDriver();
-
-        Connection conn = driver.connect("jdbc:kylin://test_url/test_db", null);
-
-        ResultSet tables = conn.getMetaData().getTables(null, null, null, null);
-        while (tables.next()) {
-            for (int i = 0; i < 10; i++) {
-                assertEquals("dummy", tables.getString(i + 1));
-            }
-        }
-
-        Statement state = conn.createStatement();
-        ResultSet resultSet = state.executeQuery("select * from test_table");
-
-        ResultSetMetaData metadata = resultSet.getMetaData();
-        assertEquals(12, metadata.getColumnType(1));
-        assertEquals("varchar", metadata.getColumnTypeName(1));
-        assertEquals(1, metadata.isNullable(1));
-
-        while (resultSet.next()) {
-            assertEquals("foo", resultSet.getString(1));
-            assertEquals("bar", resultSet.getString(2));
-            assertEquals("tool", resultSet.getString(3));
-        }
-    }
-
-    @Test
-    public void testPreStatementWithMockData() throws SQLException {
-        Driver driver = new DummyDriver();
-
-        Connection conn = driver.connect("jdbc:kylin://test_url/test_db", null);
-        PreparedStatement state = conn.prepareStatement("select * from test_table where id=?");
-        state.setInt(1, 10);
-        ResultSet resultSet = state.executeQuery();
-
-        ResultSetMetaData metadata = resultSet.getMetaData();
-        assertEquals(12, metadata.getColumnType(1));
-        assertEquals("varchar", metadata.getColumnTypeName(1));
-        assertEquals(1, metadata.isNullable(1));
-
-        while (resultSet.next()) {
-            assertEquals("foo", resultSet.getString(1));
-            assertEquals("bar", resultSet.getString(2));
-            assertEquals("tool", resultSet.getString(3));
-        }
-    }
-
-    @Ignore("not maintaining")
-    @Test
-    public void testWithCubeData() throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException {
-        Driver driver = (Driver) Class.forName("org.apache.kylin.kylin.jdbc.Driver").newInstance();
-        Properties info = new Properties();
-        info.put("user", "");
-        info.put("password", "");
-        Connection conn = driver.connect("jdbc:kylin://localhost/default", info);
-
-        ResultSet catalogs = conn.getMetaData().getCatalogs();
-        while (catalogs.next()) {
-            System.out.println(catalogs.getString("TABLE_CAT"));
-        }
-
-        ResultSet schemas = conn.getMetaData().getSchemas();
-        while (schemas.next()) {
-            System.out.println(schemas.getString(1));
-            System.out.println(schemas.getString(2));
-        }
-
-        ResultSet tables = conn.getMetaData().getTables(null, null, null, null);
-        while (tables.next()) {
-            String tableName = tables.getString(3);
-            assertEquals(tables.getString("TABLE_NAME"), tableName);
-            ResultSet columns = conn.getMetaData().getColumns(null, null, tableName, null);
-
-            while (columns.next()) {
-                System.out.println(columns.getString("COLUMN_NAME"));
-                String column = "";
-                for (int i = 0; i < 23; i++) {
-                    column += columns.getString(i + 1) + ", ";
-                }
-
-                System.out.println("Column in table " + tableName + ": " + column);
-            }
-        }
-
-        for (int j = 0; j < 3; j++) {
-            Statement state = conn.createStatement();
-            ResultSet resultSet = state.executeQuery("select * from test_kylin_fact");
-
-            ResultSetMetaData metadata = resultSet.getMetaData();
-            System.out.println("Metadata:");
-
-            for (int i = 0; i < metadata.getColumnCount(); i++) {
-                String metaStr = metadata.getCatalogName(i + 1) + " " + metadata.getColumnClassName(i + 1) + " " + metadata.getColumnDisplaySize(i + 1) + " " + metadata.getColumnLabel(i + 1) + " " + metadata.getColumnName(i + 1) + " " + metadata.getColumnType(i + 1) + " " + metadata.getColumnTypeName(i + 1) + " " + metadata.getPrecision(i + 1) + " " + metadata.getScale(i + 1) + " " + metadata.getSchemaName(i + 1) + " " + metadata.getTableName(i + 1);
-                System.out.println(metaStr);
-            }
-
-            System.out.println("Data:");
-            while (resultSet.next()) {
-                String dataStr = resultSet.getFloat(1) + " " + resultSet.getInt(2) + " " + resultSet.getInt(3) + " " + resultSet.getLong(4) + " " + resultSet.getDate(5) + " " + resultSet.getString(6);
-                System.out.println(dataStr);
-            }
-        }
-    }
-
-    @Ignore("not maintaining")
-    @Test
-    public void testPreStatementWithCubeData() throws SQLException {
-        Driver driver = new Driver();
-        Properties info = new Properties();
-        info.put("user", "");
-        info.put("password", "");
-        Connection conn = driver.connect("jdbc:kylin://localhost/default", info);
-        PreparedStatement state = conn.prepareStatement("select * from test_kylin_fact where seller_id=?");
-        state.setLong(1, 10000001);
-        ResultSet resultSet = state.executeQuery();
-
-        ResultSetMetaData metadata = resultSet.getMetaData();
-        System.out.println("Metadata:");
-
-        for (int i = 0; i < metadata.getColumnCount(); i++) {
-            String metaStr = metadata.getCatalogName(i + 1) + " " + metadata.getColumnClassName(i + 1) + " " + metadata.getColumnDisplaySize(i + 1) + " " + metadata.getColumnLabel(i + 1) + " " + metadata.getColumnName(i + 1) + " " + metadata.getColumnType(i + 1) + " " + metadata.getColumnTypeName(i + 1) + " " + metadata.getPrecision(i + 1) + " " + metadata.getScale(i + 1) + " " + metadata.getSchemaName(i + 1) + " " + metadata.getTableName(i + 1);
-            System.out.println(metaStr);
-        }
-
-        System.out.println("Data:");
-        while (resultSet.next()) {
-            String dataStr = resultSet.getFloat(1) + " " + resultSet.getInt(2) + " " + resultSet.getInt(3) + " " + resultSet.getLong(4) + " " + resultSet.getDate(5) + " " + resultSet.getString(6);
-            System.out.println(dataStr);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/test/java/org/apache/kylin/jdbc/DummyClient.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/kylin/jdbc/DummyClient.java b/jdbc/src/test/java/org/apache/kylin/jdbc/DummyClient.java
deleted file mode 100644
index 7af3cb7..0000000
--- a/jdbc/src/test/java/org/apache/kylin/jdbc/DummyClient.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.kylin.jdbc;
-
-import java.sql.Types;
-import java.util.ArrayList;
-import java.util.List;
-
-import net.hydromatic.avatica.AvaticaStatement;
-import net.hydromatic.avatica.ColumnMetaData;
-import net.hydromatic.avatica.ColumnMetaData.Rep;
-import net.hydromatic.linq4j.Enumerator;
-
-import org.apache.kylin.jdbc.stub.ConnectionException;
-import org.apache.kylin.jdbc.stub.DataSet;
-import org.apache.kylin.jdbc.stub.RemoteClient;
-
-/**
- * @author xduo
- * 
- */
-public class DummyClient implements RemoteClient {
-
-    public DummyClient(KylinConnectionImpl conn) {
-    }
-
-    @Override
-    public void connect() throws ConnectionException {
-    }
-
-    @Override
-    public KylinMetaImpl.MetaProject getMetadata(String project) throws ConnectionException {
-        List<ColumnMetaData> meta = new ArrayList<ColumnMetaData>();
-        for (int i = 0; i < 10; i++) {
-            meta.add(ColumnMetaData.dummy(ColumnMetaData.scalar(Types.VARCHAR, "varchar", Rep.STRING), true));
-        }
-
-        List<KylinMetaImpl.MetaTable> tables = new ArrayList<KylinMetaImpl.MetaTable>();
-        KylinMetaImpl.MetaTable table = new KylinMetaImpl.MetaTable("dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", new ArrayList<KylinMetaImpl.MetaColumn>());
-        tables.add(table);
-
-        List<KylinMetaImpl.MetaSchema> schemas = new ArrayList<KylinMetaImpl.MetaSchema>();
-        schemas.add(new KylinMetaImpl.MetaSchema("dummy", "dummy", tables));
-        List<KylinMetaImpl.MetaCatalog> catalogs = new ArrayList<KylinMetaImpl.MetaCatalog>();
-        catalogs.add(new KylinMetaImpl.MetaCatalog("dummy", schemas));
-
-        return new KylinMetaImpl.MetaProject(null, catalogs);
-    }
-
-    @Override
-    public DataSet<Object[]> query(AvaticaStatement statement, String sql) {
-        List<Object[]> data = new ArrayList<Object[]>();
-        Object[] row = new Object[] { "foo", "bar", "tool" };
-        data.add(row);
-        Enumerator<Object[]> enumerator = new KylinEnumerator<Object[]>(data);
-        List<ColumnMetaData> meta = new ArrayList<ColumnMetaData>();
-        meta.add(ColumnMetaData.dummy(ColumnMetaData.scalar(Types.VARCHAR, "varchar", Rep.STRING), true));
-        meta.add(ColumnMetaData.dummy(ColumnMetaData.scalar(Types.VARCHAR, "varchar", Rep.STRING), true));
-        meta.add(ColumnMetaData.dummy(ColumnMetaData.scalar(Types.VARCHAR, "varchar", Rep.STRING), true));
-
-        return new DataSet<Object[]>(meta, enumerator);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/test/java/org/apache/kylin/jdbc/DummyDriver.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/kylin/jdbc/DummyDriver.java b/jdbc/src/test/java/org/apache/kylin/jdbc/DummyDriver.java
deleted file mode 100644
index a5f5383..0000000
--- a/jdbc/src/test/java/org/apache/kylin/jdbc/DummyDriver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.kylin.jdbc;
-
-/**
- * @author xduo
- * 
- */
-public class DummyDriver extends Driver {
-
-    @Override
-    protected String getFactoryClassName(JdbcVersion jdbcVersion) {
-        return "org.apache.kylin.jdbc.DummyJdbc41Factory";
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/test/java/org/apache/kylin/jdbc/DummyJdbc41Factory.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/kylin/jdbc/DummyJdbc41Factory.java b/jdbc/src/test/java/org/apache/kylin/jdbc/DummyJdbc41Factory.java
deleted file mode 100644
index df0b49c..0000000
--- a/jdbc/src/test/java/org/apache/kylin/jdbc/DummyJdbc41Factory.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.kylin.jdbc;
-
-import org.apache.kylin.jdbc.stub.RemoteClient;
-
-/**
- * @author xduo
- * 
- */
-public class DummyJdbc41Factory extends KylinJdbc41Factory {
-
-    // ~ kylin sepcified
-    @Override
-    public RemoteClient newRemoteClient(KylinConnectionImpl connection) {
-        return new DummyClient(connection);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/test/java/org/apache/kylin/jdbc2/DriverTest.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/kylin/jdbc2/DriverTest.java b/jdbc/src/test/java/org/apache/kylin/jdbc2/DriverTest.java
new file mode 100644
index 0000000..6bde11a
--- /dev/null
+++ b/jdbc/src/test/java/org/apache/kylin/jdbc2/DriverTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.kylin.jdbc2;
+
+import static org.junit.Assert.*;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Unit test for Driver.
+ */
+public class DriverTest {
+
+    @Ignore
+    @Test
+    public void testStatementWithMockData() throws SQLException {
+        Driver driver = new DummyDriver();
+
+        Connection conn = driver.connect("jdbc:kylin://test_url/test_db", null);
+
+        ResultSet tables = conn.getMetaData().getTables(null, null, null, null);
+        while (tables.next()) {
+            for (int i = 0; i < 10; i++) {
+                assertEquals("dummy", tables.getString(i + 1));
+            }
+        }
+
+        Statement state = conn.createStatement();
+        ResultSet resultSet = state.executeQuery("select * from test_table");
+
+        ResultSetMetaData metadata = resultSet.getMetaData();
+        assertEquals(12, metadata.getColumnType(1));
+        assertEquals("varchar", metadata.getColumnTypeName(1));
+        assertEquals(1, metadata.isNullable(1));
+
+        while (resultSet.next()) {
+            assertEquals("foo", resultSet.getString(1));
+            assertEquals("bar", resultSet.getString(2));
+            assertEquals("tool", resultSet.getString(3));
+        }
+    }
+
+    @Test
+    public void testPreStatementWithMockData() throws SQLException {
+        Driver driver = new DummyDriver();
+
+        Connection conn = driver.connect("jdbc:kylin://test_url/test_db", null);
+        PreparedStatement state = conn.prepareStatement("select * from test_table where id=?");
+        state.setInt(1, 10);
+        ResultSet resultSet = state.executeQuery();
+
+        ResultSetMetaData metadata = resultSet.getMetaData();
+        assertEquals(12, metadata.getColumnType(1));
+        assertEquals("varchar", metadata.getColumnTypeName(1));
+        assertEquals(1, metadata.isNullable(1));
+
+        while (resultSet.next()) {
+            assertEquals("foo", resultSet.getString(1));
+            assertEquals("bar", resultSet.getString(2));
+            assertEquals("tool", resultSet.getString(3));
+        }
+    }
+
+    @Ignore("not maintaining")
+    @Test
+    public void testWithCubeData() throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException {
+        Driver driver = (Driver) Class.forName("org.apache.kylin.kylin.jdbc.Driver").newInstance();
+        Properties info = new Properties();
+        info.put("user", "");
+        info.put("password", "");
+        Connection conn = driver.connect("jdbc:kylin://localhost/default", info);
+
+        ResultSet catalogs = conn.getMetaData().getCatalogs();
+        while (catalogs.next()) {
+            System.out.println(catalogs.getString("TABLE_CAT"));
+        }
+
+        ResultSet schemas = conn.getMetaData().getSchemas();
+        while (schemas.next()) {
+            System.out.println(schemas.getString(1));
+            System.out.println(schemas.getString(2));
+        }
+
+        ResultSet tables = conn.getMetaData().getTables(null, null, null, null);
+        while (tables.next()) {
+            String tableName = tables.getString(3);
+            assertEquals(tables.getString("TABLE_NAME"), tableName);
+            ResultSet columns = conn.getMetaData().getColumns(null, null, tableName, null);
+
+            while (columns.next()) {
+                System.out.println(columns.getString("COLUMN_NAME"));
+                String column = "";
+                for (int i = 0; i < 23; i++) {
+                    column += columns.getString(i + 1) + ", ";
+                }
+
+                System.out.println("Column in table " + tableName + ": " + column);
+            }
+        }
+
+        for (int j = 0; j < 3; j++) {
+            Statement state = conn.createStatement();
+            ResultSet resultSet = state.executeQuery("select * from test_kylin_fact");
+
+            printResultSetMetaData(resultSet);
+
+            printResultSet(resultSet);
+        }
+    }
+
+    @Test
+    public void testPreStatementWithCubeData() throws SQLException {
+        Driver driver = new Driver();
+        Properties info = new Properties();
+        info.put("user", "ADMIN");
+        info.put("password", "KYLIN");
+        Connection conn = driver.connect("jdbc:kylin://localhost:7070/default", info);
+        
+        PreparedStatement state = conn.prepareStatement("select cal_dt, count(*) from test_kylin_fact where seller_id=? group by cal_dt");
+        state.setLong(1, 10000001);
+        ResultSet resultSet = state.executeQuery();
+
+        printResultSetMetaData(resultSet);
+        printResultSet(resultSet);
+    }
+
+    private void printResultSet(ResultSet rs) throws SQLException {
+        ResultSetMetaData meta = rs.getMetaData();
+        System.out.println("Data:");
+        
+        while (rs.next()) {
+            StringBuilder buf = new StringBuilder();
+            buf.append("[");
+            for (int i = 0; i < meta.getColumnCount(); i++) {
+                if (i > 0)
+                    buf.append(", ");
+                buf.append(rs.getString(i + 1));
+            }
+            buf.append("]");
+            System.out.println(buf);
+        }
+    }
+
+    private void printResultSetMetaData(ResultSet rs) throws SQLException {
+        ResultSetMetaData metadata = rs.getMetaData();
+        System.out.println("Metadata:");
+
+        for (int i = 0; i < metadata.getColumnCount(); i++) {
+            String metaStr = metadata.getCatalogName(i + 1) + " " + metadata.getColumnClassName(i + 1) + " " + metadata.getColumnDisplaySize(i + 1) + " " + metadata.getColumnLabel(i + 1) + " " + metadata.getColumnName(i + 1) + " " + metadata.getColumnType(i + 1) + " " + metadata.getColumnTypeName(i + 1) + " " + metadata.getPrecision(i + 1) + " " + metadata.getScale(i + 1) + " " + metadata.getSchemaName(i + 1) + " " + metadata.getTableName(i + 1);
+            System.out.println(metaStr);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/test/java/org/apache/kylin/jdbc2/DummyClient.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/kylin/jdbc2/DummyClient.java b/jdbc/src/test/java/org/apache/kylin/jdbc2/DummyClient.java
new file mode 100644
index 0000000..2b07818
--- /dev/null
+++ b/jdbc/src/test/java/org/apache/kylin/jdbc2/DummyClient.java
@@ -0,0 +1,76 @@
+/*
+ * 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.kylin.jdbc2;
+
+import java.io.IOException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.ColumnMetaData.Rep;
+import org.apache.kylin.jdbc.KylinMetaImpl;
+import org.apache.kylin.jdbc.KylinMetaImpl.MetaProject;
+
+/**
+ */
+public class DummyClient implements IRemoteClient {
+
+    public DummyClient(KylinConnection conn) {
+    }
+
+    @Override
+    public void connect() throws IOException {
+    }
+
+    @Override
+    public MetaProject retrieveMetaData(String project) throws IOException {
+        List<ColumnMetaData> meta = new ArrayList<ColumnMetaData>();
+        for (int i = 0; i < 10; i++) {
+            meta.add(ColumnMetaData.dummy(ColumnMetaData.scalar(Types.VARCHAR, "varchar", Rep.STRING), true));
+        }
+
+        List<KylinMetaImpl.MetaTable> tables = new ArrayList<KylinMetaImpl.MetaTable>();
+        KylinMetaImpl.MetaTable table = new KylinMetaImpl.MetaTable("dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", new ArrayList<KylinMetaImpl.MetaColumn>());
+        tables.add(table);
+
+        List<KylinMetaImpl.MetaSchema> schemas = new ArrayList<KylinMetaImpl.MetaSchema>();
+        schemas.add(new KylinMetaImpl.MetaSchema("dummy", "dummy", tables));
+        List<KylinMetaImpl.MetaCatalog> catalogs = new ArrayList<KylinMetaImpl.MetaCatalog>();
+        catalogs.add(new KylinMetaImpl.MetaCatalog("dummy", schemas));
+
+        return new KylinMetaImpl.MetaProject(null, catalogs);
+    }
+
+    @Override
+    public QueryResult executeQuery(String sql, List<AvaticaParameter> params, List<Object> paramValues) throws IOException {
+        List<Object> data = new ArrayList<Object>();
+        Object[] row = new Object[] { "foo", "bar", "tool" };
+        data.add(row);
+        
+        List<ColumnMetaData> meta = new ArrayList<ColumnMetaData>();
+        meta.add(ColumnMetaData.dummy(ColumnMetaData.scalar(Types.VARCHAR, "varchar", Rep.STRING), true));
+        meta.add(ColumnMetaData.dummy(ColumnMetaData.scalar(Types.VARCHAR, "varchar", Rep.STRING), true));
+        meta.add(ColumnMetaData.dummy(ColumnMetaData.scalar(Types.VARCHAR, "varchar", Rep.STRING), true));
+
+        return new QueryResult(meta, data);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/776a3a24/jdbc/src/test/java/org/apache/kylin/jdbc2/DummyDriver.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/kylin/jdbc2/DummyDriver.java b/jdbc/src/test/java/org/apache/kylin/jdbc2/DummyDriver.java
new file mode 100644
index 0000000..f4c2ca8
--- /dev/null
+++ b/jdbc/src/test/java/org/apache/kylin/jdbc2/DummyDriver.java
@@ -0,0 +1,30 @@
+/*
+ * 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.kylin.jdbc2;
+
+/**
+ */
+public class DummyDriver extends Driver {
+
+    @Override
+    protected String getFactoryClassName(JdbcVersion jdbcVersion) {
+        return DummyJdbcFactory.class.getName();
+    }
+
+}



Mime
View raw message