You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ha...@apache.org on 2021/08/08 07:58:22 UTC

[iotdb] branch master updated: JDBC - Adjust method not supported to specific prompt (#2444)

This is an automated email from the ASF dual-hosted git repository.

haonan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 860c8de  JDBC - Adjust method not supported to specific prompt (#2444)
860c8de is described below

commit 860c8de52ced88b4440f10bc0b07cd8a9c7441bd
Author: CloudWise-Lukemiao <76...@users.noreply.github.com>
AuthorDate: Sun Aug 8 15:58:01 2021 +0800

    JDBC - Adjust method not supported to specific prompt (#2444)
    
    Co-authored-by: Jialin Qiao <qj...@mails.tsinghua.edu.cn>
    Co-authored-by: sunjincheng121 <su...@gmail.com>
    Co-authored-by: Jialin Qiao <qj...@mails.tsinghua.edu.cn>
---
 .../iotdb/jdbc/AbstractIoTDBJDBCResultSet.java     |   68 +-
 .../main/java/org/apache/iotdb/jdbc/Constant.java  |    3 +
 .../src/main/java/org/apache/iotdb/jdbc/Field.java |   71 +
 .../iotdb/jdbc/GroupedLSBWatermarkEncoder.java     |  139 +
 .../org/apache/iotdb/jdbc/IoTDBConnection.java     |   16 +-
 .../apache/iotdb/jdbc/IoTDBDatabaseMetadata.java   | 2744 +++++++++++++++++---
 .../org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java  |   58 +-
 .../iotdb/jdbc/IoTDBNonAlignJDBCResultSet.java     |   38 +-
 .../apache/iotdb/jdbc/IoTDBPreparedStatement.java  |  585 ++++-
 .../org/apache/iotdb/jdbc/IoTDBResultMetadata.java |  173 +-
 .../java/org/apache/iotdb/jdbc/IoTDBStatement.java |   38 +-
 .../iotdb/jdbc/{Constant.java => ListDataSet.java} |   33 +-
 .../java/org/apache/iotdb/jdbc/StringUtils.java    |   78 +
 .../jdbc/{Constant.java => WatermarkEncoder.java}  |   15 +-
 .../org/apache/iotdb/jdbc/IoTDBConnectionTest.java |    3 +-
 .../iotdb/jdbc/IoTDBDatabaseMetadataTest.java      |  162 ++
 .../iotdb/jdbc/IoTDBPreparedStatementTest.java     |   32 +-
 .../apache/iotdb/jdbc/IoTDBResultMetadataTest.java |   21 +-
 .../org/apache/iotdb/db/service/TSServiceImpl.java |   67 +-
 .../org/apache/iotdb/rpc/IoTDBJDBCDataSet.java     |  618 +++++
 thrift/src/main/thrift/rpc.thrift                  |   13 +
 21 files changed, 4553 insertions(+), 422 deletions(-)

diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/AbstractIoTDBJDBCResultSet.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/AbstractIoTDBJDBCResultSet.java
index 5e13b77..46a5472 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/AbstractIoTDBJDBCResultSet.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/AbstractIoTDBJDBCResultSet.java
@@ -19,7 +19,7 @@
 
 package org.apache.iotdb.jdbc;
 
-import org.apache.iotdb.rpc.IoTDBRpcDataSet;
+import org.apache.iotdb.rpc.IoTDBJDBCDataSet;
 import org.apache.iotdb.rpc.StatementExecutionException;
 import org.apache.iotdb.service.rpc.thrift.TSIService;
 
@@ -45,6 +45,7 @@ import java.sql.SQLXML;
 import java.sql.Statement;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.util.BitSet;
 import java.util.Calendar;
 import java.util.List;
 import java.util.Map;
@@ -54,7 +55,10 @@ public abstract class AbstractIoTDBJDBCResultSet implements ResultSet {
   protected Statement statement;
   protected SQLWarning warningChain = null;
   protected List<String> columnTypeList;
-  protected IoTDBRpcDataSet ioTDBRpcDataSet;
+  protected IoTDBJDBCDataSet ioTDBRpcDataSet;
+  private boolean isRpcFetchResult = true;
+  private List<String> sgColumns;
+  private BitSet aliasColumnMap;
 
   public AbstractIoTDBJDBCResultSet(
       Statement statement,
@@ -66,10 +70,46 @@ public abstract class AbstractIoTDBJDBCResultSet implements ResultSet {
       String sql,
       long queryId,
       long sessionId,
-      long timeout)
+      long timeout,
+      List<String> sgColumns,
+      BitSet aliasColumnMap)
       throws SQLException {
     this.ioTDBRpcDataSet =
-        new IoTDBRpcDataSet(
+        new IoTDBJDBCDataSet(
+            sql,
+            columnNameList,
+            columnTypeList,
+            columnNameIndex,
+            ignoreTimeStamp,
+            queryId,
+            ((IoTDBStatement) statement).getStmtId(),
+            client,
+            sessionId,
+            null,
+            statement.getFetchSize(),
+            timeout,
+            sgColumns,
+            aliasColumnMap);
+    this.statement = statement;
+    this.columnTypeList = columnTypeList;
+    this.aliasColumnMap = aliasColumnMap;
+  }
+
+  public AbstractIoTDBJDBCResultSet(
+      Statement statement,
+      List<String> columnNameList,
+      List<String> columnTypeList,
+      Map<String, Integer> columnNameIndex,
+      boolean ignoreTimeStamp,
+      TSIService.Iface client,
+      String sql,
+      long queryId,
+      long sessionId,
+      long timeout,
+      boolean isRpcFetchResult)
+      throws SQLException {
+    this.ioTDBRpcDataSet =
+        new IoTDBJDBCDataSet(
             sql,
             columnNameList,
             columnTypeList,
@@ -84,6 +124,7 @@ public abstract class AbstractIoTDBJDBCResultSet implements ResultSet {
             timeout);
     this.statement = statement;
     this.columnTypeList = columnTypeList;
+    this.isRpcFetchResult = isRpcFetchResult;
   }
 
   @Override
@@ -398,7 +439,24 @@ public abstract class AbstractIoTDBJDBCResultSet implements ResultSet {
 
   @Override
   public ResultSetMetaData getMetaData() {
+    String operationType = "";
+    boolean nonAlign = false;
+    try {
+      if (statement.getResultSet() instanceof IoTDBJDBCResultSet) {
+        operationType = ((IoTDBJDBCResultSet) statement.getResultSet()).getOperationType();
+        this.sgColumns = ((IoTDBJDBCResultSet) statement.getResultSet()).getSgColumns();
+      } else if (statement.getResultSet() instanceof IoTDBNonAlignJDBCResultSet) {
+        operationType = ((IoTDBNonAlignJDBCResultSet) statement.getResultSet()).getOperationType();
+        this.sgColumns = ((IoTDBNonAlignJDBCResultSet) statement.getResultSet()).getSgColumns();
+        nonAlign = true;
+      }
+    } catch (SQLException throwables) {
+      throwables.printStackTrace();
+    }
     return new IoTDBResultMetadata(
+        nonAlign,
+        sgColumns,
+        operationType,
         ioTDBRpcDataSet.columnNameList,
         ioTDBRpcDataSet.columnTypeList,
         ioTDBRpcDataSet.ignoreTimeStamp);
@@ -656,7 +714,7 @@ public abstract class AbstractIoTDBJDBCResultSet implements ResultSet {
     if (ioTDBRpcDataSet.emptyResultSet) {
       return false;
     }
-    if (fetchResults()) {
+    if (isRpcFetchResult && fetchResults()) {
       constructOneRow();
       return true;
     }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
index 84530b7..f66a529 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
@@ -25,4 +25,7 @@ public class Constant {
   public static final String GLOBAL_DB_NAME = "IoTDB";
 
   static final String METHOD_NOT_SUPPORTED = "Method not supported";
+  static final String PARAMETER_NOT_NULL = "The parameter cannot be null";
+  static final String PARAMETER_SUPPORTED =
+      "Parameter only supports BOOLEAN,INT32,INT64,FLOAT,DOUBLE,TEXT data type";
 }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/Field.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/Field.java
new file mode 100644
index 0000000..87b2095
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/Field.java
@@ -0,0 +1,71 @@
+/*
+ * 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.iotdb.jdbc;
+
+public class Field {
+  private String name;
+  private String tableName;
+  private String sqlType;
+  private Object val;
+
+  public Field(String tableName, String name, String sqlType) {
+    this.name = name;
+    this.tableName = tableName;
+    this.sqlType = sqlType;
+  }
+
+  public Field(String tableName, String name, String sqlType, Object val) {
+    this.name = name;
+    this.sqlType = sqlType;
+    this.tableName = tableName;
+    this.val = val;
+  }
+
+  public Object getVal() {
+    return val;
+  }
+
+  public void setVal(Object val) {
+    this.val = val;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public void setTableName(String tableName) {
+    this.tableName = tableName;
+  }
+
+  public String getSqlType() {
+    return sqlType;
+  }
+
+  public void setSqlType(String sqlType) {
+    this.sqlType = sqlType;
+  }
+}
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/GroupedLSBWatermarkEncoder.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/GroupedLSBWatermarkEncoder.java
new file mode 100644
index 0000000..dc0a15f
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/GroupedLSBWatermarkEncoder.java
@@ -0,0 +1,139 @@
+/*
+ * 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.iotdb.jdbc;
+
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.read.common.Field;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+
+import org.apache.thrift.EncodingUtils;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+public class GroupedLSBWatermarkEncoder implements WatermarkEncoder {
+  private String secretKey;
+  private String bitString;
+  private int markRate = 2;
+  private int groupNumber;
+  private int maxBitPosition = 5;
+  private int minBitPosition = 0;
+
+  public GroupedLSBWatermarkEncoder(
+      String secretKey, String bitString, int markRate, int minBitPosition) {
+    this.secretKey = secretKey;
+    this.bitString = bitString;
+    this.groupNumber = bitString.length();
+    this.markRate = markRate;
+    this.maxBitPosition = minBitPosition;
+  }
+
+  public static int hashMod(String val, Integer base) {
+    MessageDigest md;
+    try {
+      md = MessageDigest.getInstance("MD5");
+    } catch (NoSuchAlgorithmException e) {
+      throw new RuntimeException("ERROR: Cannot find MD5 algorithm!");
+    }
+    md.update(val.getBytes());
+    BigInteger resultInteger = new BigInteger(1, md.digest());
+    return resultInteger.mod(new BigInteger(base.toString())).intValue();
+  }
+
+  public boolean needEncode(long timestamp) {
+    return hashMod(String.format("%s%d", secretKey, timestamp), markRate) == 0;
+  }
+
+  private int getGroupId(long timestamp) {
+    return hashMod(String.format("%d%s", timestamp, secretKey), groupNumber);
+  }
+
+  private int getBitPosition(long timestamp) {
+    if (maxBitPosition <= minBitPosition) {
+      throw new RuntimeException("Error: minBitPosition is bigger than maxBitPosition");
+    }
+    int range = maxBitPosition - minBitPosition;
+    return minBitPosition
+        + hashMod(String.format("%s%d%s", secretKey, timestamp, secretKey), range);
+  }
+
+  private boolean getBitValue(long timestamp) {
+    int groupId = getGroupId(timestamp);
+    int bitIndex = groupId % bitString.length();
+    return bitString.charAt(bitIndex) == '1';
+  }
+
+  public int encodeInt(int value, long timestamp) {
+    int targetBitPosition = getBitPosition(timestamp);
+    boolean targetBitValue = getBitValue(timestamp);
+    return EncodingUtils.setBit(value, targetBitPosition, targetBitValue);
+  }
+
+  public long encodeLong(long value, long timestamp) {
+    int targetBitPosition = getBitPosition(timestamp);
+    boolean targetBitValue = getBitValue(timestamp);
+    return EncodingUtils.setBit(value, targetBitPosition, targetBitValue);
+  }
+
+  public float encodeFloat(float value, long timestamp) {
+    int intBits = Float.floatToIntBits(value);
+    return Float.intBitsToFloat(encodeInt(intBits, timestamp));
+  }
+
+  public double encodeDouble(double value, long timestamp) {
+    long longBits = Double.doubleToLongBits(value);
+    return Double.longBitsToDouble(encodeLong(longBits, timestamp));
+  }
+
+  public RowRecord encodeRecord(RowRecord record) {
+    long timestamp = record.getTimestamp();
+    if (!needEncode(timestamp)) {
+      return record;
+    }
+    List<Field> fields = record.getFields();
+    for (Field field : fields) {
+      if (field == null || field.getDataType() == null) {
+        continue;
+      }
+      TSDataType dataType = field.getDataType();
+      switch (dataType) {
+        case INT32:
+          int originIntValue = field.getIntV();
+          field.setIntV(encodeInt(originIntValue, timestamp));
+          break;
+        case INT64:
+          long originLongValue = field.getLongV();
+          field.setLongV(encodeLong(originLongValue, timestamp));
+          break;
+        case FLOAT:
+          float originFloatValue = field.getFloatV();
+          field.setFloatV(encodeFloat(originFloatValue, timestamp));
+          break;
+        case DOUBLE:
+          double originDoubleValue = field.getDoubleV();
+          field.setDoubleV(encodeDouble(originDoubleValue, timestamp));
+          break;
+        default:
+      }
+    }
+    return record;
+  }
+}
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
index 8a2bf7d..3362edd 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
@@ -84,6 +84,13 @@ public class IoTDBConnection implements Connection {
 
   private ZoneId zoneId;
   private boolean autoCommit;
+  private String url;
+
+  public String getUserName() {
+    return userName;
+  }
+
+  private String userName;
 
   public IoTDBConnection() {
     // allowed to create an instance without parameter input.
@@ -94,7 +101,8 @@ public class IoTDBConnection implements Connection {
       throw new IoTDBURLException("Input url cannot be null");
     }
     params = Utils.parseUrl(url, info);
-
+    this.url = url;
+    this.userName = info.get("user").toString();
     openTransport();
     if (Config.rpcThriftCompressionEnable) {
       setClient(new TSIService.Client(new TCompactProtocol(transport)));
@@ -108,6 +116,10 @@ public class IoTDBConnection implements Connection {
     autoCommit = false;
   }
 
+  public String getUrl() {
+    return url;
+  }
+
   @Override
   public boolean isWrapperFor(Class<?> arg0) throws SQLException {
     throw new SQLException("Does not support isWrapperFor");
@@ -222,7 +234,7 @@ public class IoTDBConnection implements Connection {
 
   @Override
   public String getCatalog() {
-    return "no catalog";
+    return "Apache IoTDB";
   }
 
   @Override
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
index 4a90fed..16fc628 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
@@ -23,16 +23,36 @@ import org.apache.iotdb.rpc.StatementExecutionException;
 import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataReq;
 import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataResp;
 import org.apache.iotdb.service.rpc.thrift.TSIService;
+import org.apache.iotdb.service.rpc.thrift.TSQueryDataSet;
+import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.iotdb.tsfile.utils.Binary;
 
 import org.apache.thrift.TException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
 import java.sql.RowIdLifetime;
 import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 public class IoTDBDatabaseMetadata implements DatabaseMetaData {
 
@@ -47,6 +67,8 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           ? IoTDBDatabaseMetadata.class.getPackage().getImplementationVersion()
           : "UNKNOWN";
   private long sessionId;
+  private WatermarkEncoder groupedLSBWatermarkEncoder;
+  private static String sqlKeywordsThatArentSQL92;
 
   IoTDBDatabaseMetadata(IoTDBConnection connection, TSIService.Iface client, long sessionId) {
     this.connection = connection;
@@ -54,6 +76,221 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
     this.sessionId = sessionId;
   }
 
+  static {
+    String[] allIotdbSQLKeywords = {
+      "ALTER",
+      "ADD",
+      "ALIAS",
+      "ALL",
+      "AVG",
+      "ALIGN",
+      "ATTRIBUTES",
+      "AS",
+      "ASC",
+      "BY",
+      "BOOLEAN",
+      "BITMAP",
+      "CREATE",
+      "CONFIGURATION",
+      "COMPRESSOR",
+      "CHILD",
+      "COUNT",
+      "COMPRESSION",
+      "CLEAR",
+      "CACHE",
+      "CONTAIN",
+      "CONCAT",
+      "DELETE",
+      "DEVICE",
+      "DESCRIBE",
+      "DATATYPE",
+      "DOUBLE",
+      "DIFF",
+      "DROP",
+      "DEVICES",
+      "DISABLE",
+      "DESC",
+      "ENCODING",
+      "FROM",
+      "FILL",
+      "FLOAT",
+      "FLUSH",
+      "FIRST_VALUE",
+      "FULL",
+      "FALSE",
+      "FOR",
+      "FUNCTION",
+      "FUNCTIONS",
+      "GRANT",
+      "GROUP",
+      "GORILLA",
+      "GLOBAL",
+      "GZIP",
+      "INSERT",
+      "INTO",
+      "INT32",
+      "INT64",
+      "INDEX",
+      "INFO",
+      "KILL",
+      "LIMIT",
+      "LINEAR",
+      "LABEL",
+      "LINK",
+      "LIST",
+      "LOAD",
+      "LEVEL",
+      "LAST_VALUE",
+      "LAST",
+      "LZO",
+      "LZ4",
+      "LATEST",
+      "LIKE",
+      "METADATA",
+      "MERGE",
+      "MOVE",
+      "MIN_TIME",
+      "MAX_TIME",
+      "MIN_VALUE",
+      "MAX_VALUE",
+      "NOW",
+      "NODES",
+      "ORDER",
+      "OFFSET",
+      "ON",
+      "OFF",
+      "OF",
+      "PROCESSLIST",
+      "PREVIOUS",
+      "PREVIOUSUNTILLAST",
+      "PROPERTY",
+      "PLAIN",
+      "PLAIN_DICTIONARY",
+      "PRIVILEGES",
+      "PASSWORD",
+      "PATHS",
+      "PAA",
+      "PLA",
+      "PARTITION",
+      "QUERY",
+      "ROOT",
+      "RLE",
+      "REGULAR",
+      "ROLE",
+      "REVOKE",
+      "REMOVE",
+      "RENAME",
+      "SELECT",
+      "SHOW",
+      "SET",
+      "SLIMIT",
+      "SOFFSET",
+      "STORAGE",
+      "SUM",
+      "SNAPPY",
+      "SNAPSHOT",
+      "SCHEMA",
+      "TO",
+      "TIMESERIES",
+      "TIMESTAMP",
+      "TEXT",
+      "TS_2DIFF",
+      "TRACING",
+      "TTL",
+      "TASK",
+      "TIME",
+      "TAGS",
+      "TRUE",
+      "TEMPORARY",
+      "TOP",
+      "TOLERANCE",
+      "UPDATE",
+      "UNLINK",
+      "UPSERT",
+      "USING",
+      "USER",
+      "UNSET",
+      "UNCOMPRESSED",
+      "VALUES",
+      "VERSION",
+      "WHERE",
+      "WITH",
+      "WATERMARK_EMBEDDING"
+    };
+    String[] sql92Keywords = {
+      "ABSOLUTE", "EXEC", "OVERLAPS", "ACTION", "EXECUTE", "PAD", "ADA", "EXISTS", "PARTIAL", "ADD",
+      "EXTERNAL", "PASCAL", "ALL", "EXTRACT", "POSITION", "ALLOCATE", "FALSE", "PRECISION", "ALTER",
+          "FETCH",
+      "PREPARE", "AND", "FIRST", "PRESERVE", "ANY", "FLOAT", "PRIMARY", "ARE", "FOR", "PRIOR",
+      "AS", "FOREIGN", "PRIVILEGES", "ASC", "FORTRAN", "PROCEDURE", "ASSERTION", "FOUND", "PUBLIC",
+          "AT",
+      "FROM", "READ", "AUTHORIZATION", "FULL", "REAL", "AVG", "GET", "REFERENCES", "BEGIN",
+          "GLOBAL",
+      "RELATIVE", "BETWEEN", "GO", "RESTRICT", "BIT", "GOTO", "REVOKE", "BIT_LENGTH", "GRANT",
+          "RIGHT",
+      "BOTH", "GROUP", "ROLLBACK", "BY", "HAVING", "ROWS", "CASCADE", "HOUR", "SCHEMA", "CASCADED",
+      "IDENTITY", "SCROLL", "CASE", "IMMEDIATE", "SECOND", "CAST", "IN", "SECTION", "CATALOG",
+          "INCLUDE",
+      "SELECT", "CHAR", "INDEX", "SESSION", "CHAR_LENGTH", "INDICATOR", "SESSION_USER", "CHARACTER",
+          "INITIALLY", "SET",
+      "CHARACTER_LENGTH", "INNER", "SIZE", "CHECK", "INPUT", "SMALLINT", "CLOSE", "INSENSITIVE",
+          "SOME", "COALESCE",
+      "INSERT", "SPACE", "COLLATE", "INT", "SQL", "COLLATION", "INTEGER", "SQLCA", "COLUMN",
+          "INTERSECT",
+      "SQLCODE", "COMMIT", "INTERVAL", "SQLERROR", "CONNECT", "INTO", "SQLSTATE", "CONNECTION",
+          "IS", "SQLWARNING",
+      "CONSTRAINT", "ISOLATION", "SUBSTRING", "CONSTRAINTS", "JOIN", "SUM", "CONTINUE", "KEY",
+          "SYSTEM_USER", "CONVERT",
+      "LANGUAGE", "TABLE", "CORRESPONDING", "LAST", "TEMPORARY", "COUNT", "LEADING", "THEN",
+          "CREATE", "LEFT",
+      "TIME", "CROSS", "LEVEL", "TIMESTAMP", "CURRENT", "LIKE", "TIMEZONE_HOUR", "CURRENT_DATE",
+          "LOCAL", "TIMEZONE_MINUTE",
+      "CURRENT_TIME", "LOWER", "TO", "CURRENT_TIMESTAMP", "MATCH", "TRAILING", "CURRENT_USER",
+          "MAX", "TRANSACTION", "CURSOR",
+      "MIN", "TRANSLATE", "DATE", "MINUTE", "TRANSLATION", "DAY", "MODULE", "TRIM", "DEALLOCATE",
+          "MONTH",
+      "TRUE", "DEC", "NAMES", "UNION", "DECIMAL", "NATIONAL", "UNIQUE", "DECLARE", "NATURAL",
+          "UNKNOWN",
+      "DEFAULT", "NCHAR", "UPDATE", "DEFERRABLE", "NEXT", "UPPER", "DEFERRED", "NO", "USAGE",
+          "DELETE",
+      "NONE", "USER", "DESC", "NOT", "USING", "DESCRIBE", "NULL", "VALUE", "DESCRIPTOR", "NULLIF",
+      "VALUES", "DIAGNOSTICS", "NUMERIC", "VARCHAR", "DISCONNECT", "OCTET_LENGTH", "VARYING",
+          "DISTINCT", "OF", "VIEW",
+      "DOMAIN", "ON", "WHEN", "DOUBLE", "ONLY", "WHENEVER", "DROP", "OPEN", "WHERE", "ELSE",
+      "OPTION", "WITH", "END", "OR", "WORK", "END-EXEC", "ORDER", "WRITE", "ESCAPE", "OUTER",
+      "YEAR", "EXCEPT", "OUTPUT", "ZONE", "EXCEPTION"
+    };
+    TreeMap myKeywordMap = new TreeMap();
+    for (int i = 0; i < allIotdbSQLKeywords.length; i++)
+      myKeywordMap.put(allIotdbSQLKeywords[i], null);
+    HashMap sql92KeywordMap = new HashMap(sql92Keywords.length);
+    for (int j = 0; j < sql92Keywords.length; j++) sql92KeywordMap.put(sql92Keywords[j], null);
+    Iterator it = sql92KeywordMap.keySet().iterator();
+    while (it.hasNext()) myKeywordMap.remove(it.next());
+    StringBuffer keywordBuf = new StringBuffer();
+    it = myKeywordMap.keySet().iterator();
+    if (it.hasNext()) keywordBuf.append(it.next().toString());
+    while (it.hasNext()) {
+      keywordBuf.append(",");
+      keywordBuf.append(it.next().toString());
+    }
+    sqlKeywordsThatArentSQL92 = keywordBuf.toString();
+  }
+
+  private WatermarkEncoder getWatermarkEncoder() {
+    try {
+      groupedLSBWatermarkEncoder =
+          new GroupedLSBWatermarkEncoder(
+              client.getProperties().getWatermarkSecretKey(),
+              client.getProperties().getWatermarkBitString(),
+              client.getProperties().getWatermarkParamMarkRate(),
+              client.getProperties().getWatermarkParamMaxRightBit());
+    } catch (TException e) {
+      e.printStackTrace();
+    }
+    return groupedLSBWatermarkEncoder;
+  }
+
   @Override
   public boolean isWrapperFor(Class<?> arg0) throws SQLException {
     throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
@@ -65,48 +302,48 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   }
 
   @Override
-  public boolean allProceduresAreCallable() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean allProceduresAreCallable() {
+    return false;
   }
 
   @Override
-  public boolean allTablesAreSelectable() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean allTablesAreSelectable() {
+    return true;
   }
 
   @Override
-  public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean autoCommitFailureClosesAllResultSets() {
+    return false;
   }
 
   @Override
-  public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean dataDefinitionCausesTransactionCommit() {
+    return false;
   }
 
   @Override
-  public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean dataDefinitionIgnoredInTransactions() {
+    return false;
   }
 
   @Override
-  public boolean deletesAreDetected(int arg0) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean deletesAreDetected(int arg0) {
+    return true;
   }
 
   @Override
-  public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean doesMaxRowSizeIncludeBlobs() {
+    return false; // The return value is tentatively FALSE and may be adjusted later
   }
 
   @Override
-  public boolean generatedKeyAlwaysReturned() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean generatedKeyAlwaysReturned() {
+    return true;
   }
 
   @Override
   public long getMaxLogicalLobSize() {
-    return 0;
+    return Long.MAX_VALUE;
   }
 
   @Override
@@ -117,39 +354,471 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   @Override
   public ResultSet getAttributes(String arg0, String arg1, String arg2, String arg3)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[21];
+      fields[0] = new Field("", "TYPE_CAT", "TEXT");
+      fields[1] = new Field("", "TYPE_SCHEM", "TEXT");
+      fields[2] = new Field("", "TYPE_NAME", "TEXT");
+      fields[3] = new Field("", "ATTR_NAME", "TEXT");
+      fields[4] = new Field("", "DATA_TYPE", "INT32");
+      fields[5] = new Field("", "ATTR_TYPE_NAME", "TEXT");
+      fields[6] = new Field("", "ATTR_SIZE", "INT32");
+      fields[7] = new Field("", "DECIMAL_DIGITS", "INT32");
+      fields[8] = new Field("", "NUM_PREC_RADIX", "INT32");
+      fields[9] = new Field("", "NULLABLE ", "INT32");
+      fields[10] = new Field("", "REMARKS", "TEXT");
+      fields[11] = new Field("", "ATTR_DEF", "TEXT");
+      fields[12] = new Field("", "SQL_DATA_TYPE", "INT32");
+      fields[13] = new Field("", "SQL_DATETIME_SUB", "INT32");
+      fields[14] = new Field("", "CHAR_OCTET_LENGTH", "INT32");
+      fields[15] = new Field("", "ORDINAL_POSITION", "INT32");
+      fields[16] = new Field("", "IS_NULLABLE", "TEXT");
+      fields[17] = new Field("", "SCOPE_CATALOG", "TEXT");
+      fields[18] = new Field("", "SCOPE_SCHEMA", "TEXT");
+      fields[19] = new Field("", "SCOPE_TABLE", "TEXT");
+      fields[20] = new Field("", "SOURCE_DATA_TYPE", "INT32");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
   }
 
   @Override
   public ResultSet getBestRowIdentifier(
       String arg0, String arg1, String arg2, int arg3, boolean arg4) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[8];
+      fields[0] = new Field("", "SCOPE", "INT32");
+      fields[1] = new Field("", "COLUMN_NAME", "TEXT");
+      fields[2] = new Field("", "DATA_TYPE", "INT32");
+      fields[3] = new Field("", "TYPE_NAME", "TEXT");
+      fields[4] = new Field("", "COLUMN_SIZE", "INT32");
+      fields[5] = new Field("", "BUFFER_LENGTH", "INT32");
+      fields[6] = new Field("", "DECIMAL_DIGITS", "INT32");
+      fields[7] = new Field("", "PSEUDO_COLUMN", "INT32");
+
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
   }
 
   @Override
-  public String getCatalogSeparator() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getCatalogSeparator() {
+    return ".";
   }
 
   @Override
-  public String getCatalogTerm() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getCatalogTerm() {
+    return "storage group";
   }
 
   @Override
   public ResultSet getCatalogs() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
-  }
+    Statement stmt = this.connection.createStatement();
+    ResultSet rs = stmt.executeQuery("SHOW STORAGE GROUP ");
+    Field[] fields = new Field[1];
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigpaths = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    while (rs.next()) {
+      List<Map> paths = new ArrayList<Map>();
+      Map<String, Object> m = new HashMap<>();
+      m.put("type", TSDataType.TEXT);
+      m.put("val", rs.getString(1));
+      paths.add(m);
+      bigpaths.add(paths);
+    }
+    addToDataSet(bigpaths, dataSet);
+    columnNameList.add("TYPE_CAT");
+    columnTypeList.add("TEXT");
+    columnNameIndex.put("TYPE_CAT", 0);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(rs, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
+  }
+
+  public static TSQueryDataSet convertQueryDataSetByFetchSize(
+      QueryDataSet queryDataSet, int fetchSize, WatermarkEncoder watermarkEncoder)
+      throws IOException {
+    List<TSDataType> dataTypes = queryDataSet.getDataTypes();
+    int columnNum = dataTypes.size();
+    TSQueryDataSet tsQueryDataSet = new TSQueryDataSet();
+    // one time column and each value column has a actual value buffer and a bitmap value to
+    // indicate whether it is a null
+    int columnNumWithTime = columnNum * 2 + 1;
+    DataOutputStream[] dataOutputStreams = new DataOutputStream[columnNumWithTime];
+    ByteArrayOutputStream[] byteArrayOutputStreams = new ByteArrayOutputStream[columnNumWithTime];
+    for (int i = 0; i < columnNumWithTime; i++) {
+      byteArrayOutputStreams[i] = new ByteArrayOutputStream();
+      dataOutputStreams[i] = new DataOutputStream(byteArrayOutputStreams[i]);
+    }
+    int rowCount = 0;
+    int[] valueOccupation = new int[columnNum];
+    // used to record a bitmap for every 8 row record
+    int[] bitmap = new int[columnNum];
+    for (int i = 0; i < fetchSize; i++) {
+      if (queryDataSet.hasNext()) {
+        RowRecord rowRecord = queryDataSet.next();
+        if (watermarkEncoder != null) {
+          rowRecord = watermarkEncoder.encodeRecord(rowRecord);
+        }
+        // use columnOutput to write byte array
+        dataOutputStreams[0].writeLong(rowRecord.getTimestamp());
+        List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+        for (int k = 0; k < fields.size(); k++) {
+          org.apache.iotdb.tsfile.read.common.Field field = fields.get(k);
+          DataOutputStream dataOutputStream = dataOutputStreams[2 * k + 1]; // DO NOT FORGET +1
+          if (field == null || field.getDataType() == null) {
+            bitmap[k] = (bitmap[k] << 1);
+          } else {
+            bitmap[k] = (bitmap[k] << 1) | 0x01;
+            TSDataType type = field.getDataType();
+            switch (type) {
+              case INT32:
+                dataOutputStream.writeInt(field.getIntV());
+                valueOccupation[k] += 4;
+                break;
+              case INT64:
+                dataOutputStream.writeLong(field.getLongV());
+                valueOccupation[k] += 8;
+                break;
+              case FLOAT:
+                dataOutputStream.writeFloat(field.getFloatV());
+                valueOccupation[k] += 4;
+                break;
+              case DOUBLE:
+                dataOutputStream.writeDouble(field.getDoubleV());
+                valueOccupation[k] += 8;
+                break;
+              case BOOLEAN:
+                dataOutputStream.writeBoolean(field.getBoolV());
+                valueOccupation[k] += 1;
+                break;
+              case TEXT:
+                dataOutputStream.writeInt(field.getBinaryV().getLength());
+                dataOutputStream.write(field.getBinaryV().getValues());
+                valueOccupation[k] = valueOccupation[k] + 4 + field.getBinaryV().getLength();
+                break;
+              default:
+                throw new UnSupportedDataTypeException(
+                    String.format("Data type %s is not supported.", type));
+            }
+          }
+        }
+        rowCount++;
+        if (rowCount % 8 == 0) {
+          for (int j = 0; j < bitmap.length; j++) {
+            DataOutputStream dataBitmapOutputStream = dataOutputStreams[2 * (j + 1)];
+            dataBitmapOutputStream.writeByte(bitmap[j]);
+            // we should clear the bitmap every 8 row record
+            bitmap[j] = 0;
+          }
+        }
+      } else {
+        break;
+      }
+    }
 
-  @Override
-  public ResultSet getClientInfoProperties() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    // feed the remaining bitmap
+    int remaining = rowCount % 8;
+    if (remaining != 0) {
+      for (int j = 0; j < bitmap.length; j++) {
+        DataOutputStream dataBitmapOutputStream = dataOutputStreams[2 * (j + 1)];
+        dataBitmapOutputStream.writeByte(bitmap[j] << (8 - remaining));
+      }
+    }
+    // calculate the time buffer size
+    int timeOccupation = rowCount * 8;
+    ByteBuffer timeBuffer = ByteBuffer.allocate(timeOccupation);
+    timeBuffer.put(byteArrayOutputStreams[0].toByteArray());
+    timeBuffer.flip();
+    tsQueryDataSet.setTime(timeBuffer);
+
+    // calculate the bitmap buffer size
+    int bitmapOccupation = rowCount / 8 + (rowCount % 8 == 0 ? 0 : 1);
+
+    List<ByteBuffer> bitmapList = new LinkedList<>();
+    List<ByteBuffer> valueList = new LinkedList<>();
+    for (int i = 1; i < byteArrayOutputStreams.length; i += 2) {
+      ByteBuffer valueBuffer = ByteBuffer.allocate(valueOccupation[(i - 1) / 2]);
+      valueBuffer.put(byteArrayOutputStreams[i].toByteArray());
+      valueBuffer.flip();
+      valueList.add(valueBuffer);
+
+      ByteBuffer bitmapBuffer = ByteBuffer.allocate(bitmapOccupation);
+      bitmapBuffer.put(byteArrayOutputStreams[i + 1].toByteArray());
+      bitmapBuffer.flip();
+      bitmapList.add(bitmapBuffer);
+    }
+    tsQueryDataSet.setBitmapList(bitmapList);
+    tsQueryDataSet.setValueList(valueList);
+    return tsQueryDataSet;
+  }
+
+  private void addToDataSet(List<List<Map>> listbigPaths, ListDataSet dataSet) {
+    List<TSDataType> listType = new ArrayList<>();
+    int i = 0;
+    for (List<Map> listPaths : listbigPaths) {
+      RowRecord record = new RowRecord(0);
+      for (Map<String, Object> map : listPaths) {
+        TSDataType columnType = (TSDataType) map.get("type");
+        Object val = map.get("val");
+        org.apache.iotdb.tsfile.read.common.Field field =
+            new org.apache.iotdb.tsfile.read.common.Field(columnType);
+        switch (columnType) {
+          case TEXT:
+            field.setBinaryV(new Binary(val.toString()));
+            break;
+          case FLOAT:
+            field.setFloatV(((float) val));
+            break;
+          case INT32:
+            field.setIntV(((int) val));
+            break;
+          case INT64:
+            field.setLongV(((long) val));
+            break;
+          case DOUBLE:
+            field.setDoubleV(((double) val));
+            break;
+          case BOOLEAN:
+            field.setBoolV(((boolean) val));
+            break;
+        }
+        record.addField(field);
+        if (i == 0) {
+          listType.add(columnType);
+        }
+      }
+      i++;
+      dataSet.putRecord(record);
+    }
+    dataSet.setDataTypes(listType);
   }
 
   @Override
-  public ResultSet getColumnPrivileges(String arg0, String arg1, String arg2, String arg3)
+  public ResultSet getClientInfoProperties() throws SQLException {
+    Statement stmt = this.connection.createStatement();
+    ResultSet rs = stmt.executeQuery("SHOW STORAGE GROUP ");
+    Field[] fields = new Field[4];
+    fields[0] = new Field("", "NAME", "TEXT");
+    fields[1] = new Field("", "MAX_LEN", "INT32");
+    fields[2] = new Field("", "DEFAULT_VALUE", "INT32");
+    fields[3] = new Field("", "DESCRIPTION", "TEXT");
+    List<TSDataType> listType =
+        Arrays.asList(TSDataType.TEXT, TSDataType.INT32, TSDataType.INT32, TSDataType.TEXT);
+    List<Object> listVal = Arrays.asList("fetch_size", 10, 10, "");
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    List<Map> properties = new ArrayList<Map>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+      Map<String, Object> m = new HashMap<>();
+      m.put("type", listType.get(i));
+      m.put("val", listVal.get(i));
+      properties.add(m);
+    }
+    bigproperties.add(properties);
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(rs, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
+  }
+
+  @Override
+  public ResultSet getColumnPrivileges(
+      String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    Statement stmt = this.connection.createStatement();
+
+    String sql = "SHOW STORAGE GROUP";
+    if (catalog != null && catalog.length() > 0) {
+      sql = sql + " " + catalog;
+    } else if (schemaPattern != null && schemaPattern.length() > 0) {
+      sql = sql + " " + schemaPattern;
+    }
+    if (((catalog != null && catalog.length() > 0)
+            || schemaPattern != null && schemaPattern.length() > 0)
+        && tableNamePattern != null
+        && tableNamePattern.length() > 0) {
+      sql = sql + "." + tableNamePattern;
+    }
+
+    if (((catalog != null && catalog.length() > 0)
+            || schemaPattern != null && schemaPattern.length() > 0)
+        && tableNamePattern != null
+        && tableNamePattern.length() > 0
+        && columnNamePattern != null
+        && columnNamePattern.length() > 0) {
+      sql = sql + "." + columnNamePattern;
+    }
+    ResultSet rs = stmt.executeQuery(sql);
+    Field[] fields = new Field[8];
+    fields[0] = new Field("", "TABLE_CAT", "TEXT");
+    fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+    fields[2] = new Field("", "TABLE_NAME", "TEXT");
+    fields[3] = new Field("", "COLUMN_NAME", "TEXT");
+    fields[4] = new Field("", "GRANTOR", "TEXT");
+    fields[5] = new Field("", "GRANTEE", "TEXT");
+    fields[6] = new Field("", "PRIVILEGE", "TEXT");
+    fields[7] = new Field("", "IS_GRANTABLE", "TEXT");
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+    }
+    while (rs.next()) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        if (i < 4) {
+          m.put("val", rs.getString(1));
+        } else if (i == 5) {
+          m.put("val", getUserName());
+        } else if (i == 6) {
+          m.put("val", "");
+        } else if (i == 7) {
+          m.put("val", "NO");
+        } else {
+          m.put("val", "");
+        }
+
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(rs, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
@@ -161,17 +830,79 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   public ResultSet getCrossReference(
       String arg0, String arg1, String arg2, String arg3, String arg4, String arg5)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[14];
+      fields[0] = new Field("", "PKTABLE_CAT", "TEXT");
+      fields[1] = new Field("", "PKTABLE_SCHEM", "TEXT");
+      fields[2] = new Field("", "PKTABLE_NAME", "TEXT");
+      fields[3] = new Field("", "PKCOLUMN_NAME", "TEXT");
+      fields[4] = new Field("", "FKTABLE_CAT", "TEXT");
+      fields[5] = new Field("", "FKTABLE_SCHEM", "TEXT");
+      fields[6] = new Field("", "FKTABLE_NAME", "TEXT");
+      fields[7] = new Field("", "FKCOLUMN_NAME", "TEXT");
+      fields[8] = new Field("", "KEY_SEQ", "TEXT");
+      fields[9] = new Field("", "UPDATE_RULE ", "TEXT");
+      fields[10] = new Field("", "DELETE_RULE", "TEXT");
+      fields[11] = new Field("", "FK_NAME", "TEXT");
+      fields[12] = new Field("", "PK_NAME", "TEXT");
+      fields[13] = new Field("", "DEFERRABILITY", "TEXT");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
   }
 
   @Override
   public int getDatabaseMajorVersion() {
-    return 0;
+    int major_version = 0;
+    try {
+      String version = client.getProperties().getVersion();
+      String[] versions = version.split(".");
+      if (versions.length >= 2) {
+        major_version = Integer.valueOf(versions[0]);
+      }
+    } catch (TException e) {
+      e.printStackTrace();
+    }
+    return major_version;
   }
 
   @Override
   public int getDatabaseMinorVersion() {
-    return 0;
+    int minor_version = 0;
+    try {
+      String version = client.getProperties().getVersion();
+      String[] versions = version.split(".");
+      if (versions.length >= 2) {
+        minor_version = Integer.valueOf(versions[1]);
+      }
+    } catch (TException e) {
+      e.printStackTrace();
+    }
+    return minor_version;
   }
 
   @Override
@@ -191,12 +922,12 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
 
   @Override
   public int getDriverMajorVersion() {
-    return 1;
+    return 4;
   }
 
   @Override
   public int getDriverMinorVersion() {
-    return 0;
+    return 3;
   }
 
   @Override
@@ -210,75 +941,360 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   }
 
   @Override
-  public ResultSet getExportedKeys(String arg0, String arg1, String arg2) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
-  }
-
-  @Override
-  public String getExtraNameCharacters() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public ResultSet getExportedKeys(String catalog, String schema, final String table)
+      throws SQLException {
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[14];
+      fields[0] = new Field("", "PKTABLE_CAT", "TEXT");
+      fields[1] = new Field("", "PKTABLE_SCHEM", "INT32");
+      fields[2] = new Field("", "PKTABLE_NAME", "TEXT");
+      fields[3] = new Field("", "PKCOLUMN_NAME", "TEXT");
+      fields[4] = new Field("", "FKTABLE_CAT", "TEXT");
+      fields[5] = new Field("", "FKTABLE_SCHEM", "TEXT");
+      fields[6] = new Field("", "FKTABLE_NAME", "TEXT");
+      fields[7] = new Field("", "FKCOLUMN_NAME", "TEXT");
+      fields[8] = new Field("", "KEY_SEQ", "INT32");
+      fields[9] = new Field("", "UPDATE_RULE", "INT32");
+      fields[10] = new Field("", "DELETE_RULE", "INT32");
+      fields[11] = new Field("", "FK_NAME", "TEXT");
+      fields[12] = new Field("", "PK_NAME", "TEXT");
+      fields[13] = new Field("", "DEFERRABILITY", "INT32");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
+  }
+
+  @Override
+  public String getExtraNameCharacters() {
+    return "";
   }
 
   @Override
-  public ResultSet getFunctionColumns(String arg0, String arg1, String arg2, String arg3)
+  public ResultSet getFunctionColumns(
+      String catalog,
+      String schemaPattern,
+      java.lang.String functionNamePattern,
+      java.lang.String columnNamePattern)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
-  }
+    Statement stmt = connection.createStatement();
+    ResultSet rs = stmt.executeQuery("show functions");
+    Field[] fields = new Field[17];
+    fields[0] = new Field("", "FUNCTION_CAT ", "TEXT");
+    fields[1] = new Field("", "FUNCTION_SCHEM", "TEXT");
+    fields[2] = new Field("", "FUNCTION_NAME", "TEXT");
+    fields[3] = new Field("", "COLUMN_NAME", "TEXT");
+    fields[4] = new Field("", "COLUMN_TYPE", "INT32");
+    fields[5] = new Field("", "DATA_TYPE", "INT32");
+    fields[6] = new Field("", "TYPE_NAME", "TEXT");
+    fields[7] = new Field("", "PRECISION", "INT32");
+    fields[8] = new Field("", "LENGTH", "INT32");
+    fields[9] = new Field("", "SCALE", "INT32");
+    fields[10] = new Field("", "RADIX", "INT32");
+    fields[11] = new Field("", "NULLABLE", "INT32");
+    fields[12] = new Field("", "REMARKS", "TEXT");
+    fields[13] = new Field("", "CHAR_OCTET_LENGTH", "INT32");
+    fields[14] = new Field("", "ORDINAL_POSITION", "INT32");
+    fields[15] = new Field("", "IS_NULLABLE", "TEXT");
+    fields[16] = new Field("", "SPECIFIC_NAME", "TEXT");
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.TEXT);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+    }
+    while (rs.next()) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        if (i == 2) {
+          m.put("val", rs.getString(1));
+        } else if (fields[i].getSqlType().equals("INT32")) {
+          m.put("val", 0);
+        } else {
+          m.put("val", "");
+        }
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(rs, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
+  }
+
+  @Override
+  public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern)
+      throws SQLException {
+    Statement stmt = connection.createStatement();
+    ResultSet rs = stmt.executeQuery("show functions");
+    Field[] fields = new Field[6];
+    fields[0] = new Field("", "FUNCTION_CAT ", "TEXT");
+    fields[1] = new Field("", "FUNCTION_SCHEM", "TEXT");
+    fields[2] = new Field("", "FUNCTION_NAME", "TEXT");
+    fields[3] = new Field("", "REMARKS", "TEXT");
+    fields[4] = new Field("", "FUNCTION_TYPE", "INT32");
+    fields[5] = new Field("", "SPECIFIC_NAME", "TEXT");
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.TEXT);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+    }
+    while (rs.next()) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        if (i == 2) {
+          m.put("val", rs.getString(1));
+        } else if (i == 4) {
+          m.put("val", 0);
+        } else {
+          m.put("val", "");
+        }
 
-  @Override
-  public ResultSet getFunctions(String arg0, String arg1, String arg2) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(rs, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
-  public String getIdentifierQuoteString() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getIdentifierQuoteString() {
+    return "\' or \"";
   }
 
   @Override
   public ResultSet getImportedKeys(String arg0, String arg1, String arg2) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[14];
+      fields[0] = new Field("", "PKTABLE_CAT", "TEXT");
+      fields[1] = new Field("", "PKTABLE_SCHEM", "INT32");
+      fields[2] = new Field("", "PKTABLE_NAME", "TEXT");
+      fields[3] = new Field("", "PKCOLUMN_NAME", "TEXT");
+      fields[4] = new Field("", "FKTABLE_CAT", "TEXT");
+      fields[5] = new Field("", "FKTABLE_SCHEM", "TEXT");
+      fields[6] = new Field("", "FKTABLE_NAME", "TEXT");
+      fields[7] = new Field("", "FKCOLUMN_NAME", "TEXT");
+      fields[8] = new Field("", "KEY_SEQ", "INT32");
+      fields[9] = new Field("", "UPDATE_RULE", "INT32");
+      fields[10] = new Field("", "DELETE_RULE", "INT32");
+      fields[11] = new Field("", "FK_NAME", "TEXT");
+      fields[12] = new Field("", "PK_NAME", "TEXT");
+      fields[13] = new Field("", "DEFERRABILITY", "INT32");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
   }
 
   @Override
   public ResultSet getIndexInfo(String arg0, String arg1, String arg2, boolean arg3, boolean arg4)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[14];
+      fields[0] = new Field("", "TABLE_CAT", "TEXT");
+      fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+      fields[2] = new Field("", "TABLE_NAME", "TEXT");
+      fields[3] = new Field("", "NON_UNIQUE", "TEXT");
+      fields[4] = new Field("", "INDEX_QUALIFIER", "TEXT");
+      fields[5] = new Field("", "INDEX_NAME", "TEXT");
+      fields[6] = new Field("", "TYPE", "TEXT");
+      fields[7] = new Field("", "ORDINAL_POSITION", "TEXT");
+      fields[8] = new Field("", "COLUMN_NAME", "TEXT");
+      fields[9] = new Field("", "ASC_OR_DESC", "TEXT");
+      fields[10] = new Field("", "CARDINALITY", "TEXT");
+      fields[11] = new Field("", "PAGES", "TEXT");
+      fields[12] = new Field("", "PK_NAME", "TEXT");
+      fields[13] = new Field("", "FILTER_CONDITION", "TEXT");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
   }
 
   @Override
   public int getJDBCMajorVersion() {
-    return 0;
+    return 4;
   }
 
   @Override
   public int getJDBCMinorVersion() {
-    return 0;
+    return 3;
   }
 
   @Override
   public int getMaxBinaryLiteralLength() {
-    return 0;
+    return Integer.MAX_VALUE;
   }
-
+  /** Although there is no limit, it is not recommended */
   @Override
   public int getMaxCatalogNameLength() {
-    return 0;
+    return 1024;
   }
 
   @Override
   public int getMaxCharLiteralLength() {
-    return 0;
+    return Integer.MAX_VALUE;
   }
-
+  /** Although there is no limit, it is not recommended */
   @Override
   public int getMaxColumnNameLength() {
-    return 0;
+    return 1024;
   }
 
   @Override
   public int getMaxColumnsInGroupBy() {
-    return 0;
+    return 1;
   }
 
   @Override
@@ -288,7 +1304,7 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
 
   @Override
   public int getMaxColumnsInOrderBy() {
-    return 0;
+    return 1;
   }
 
   @Override
@@ -298,12 +1314,18 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
 
   @Override
   public int getMaxColumnsInTable() {
-    return 0;
+    return Integer.MAX_VALUE;
   }
 
   @Override
   public int getMaxConnections() {
-    return 0;
+    int maxcount = 0;
+    try {
+      maxcount = client.getProperties().getMaxConcurrentClientNum();
+    } catch (TException e) {
+      e.printStackTrace();
+    }
+    return maxcount;
   }
 
   @Override
@@ -313,26 +1335,31 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
 
   @Override
   public int getMaxIndexLength() {
-    return 0;
+    return Integer.MAX_VALUE;
   }
 
   @Override
   public int getMaxProcedureNameLength() {
     return 0;
   }
-
+  /** maxrowsize unlimited */
   @Override
   public int getMaxRowSize() {
-    return 0;
+    return 2147483639;
   }
-
+  /** Although there is no limit, it is not recommended */
   @Override
   public int getMaxSchemaNameLength() {
-    return 0;
+    return 1024;
   }
 
   @Override
   public int getMaxStatementLength() {
+    try {
+      return client.getProperties().getThriftMaxFrameSize();
+    } catch (TException e) {
+      e.printStackTrace();
+    }
     return 0;
   }
 
@@ -340,68 +1367,304 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   public int getMaxStatements() {
     return 0;
   }
-
+  /** Although there is no limit, it is not recommended */
   @Override
   public int getMaxTableNameLength() {
-    return 0;
+    return 1024;
   }
-
+  /** Although there is no limit, it is not recommended */
   @Override
   public int getMaxTablesInSelect() {
-    return 0;
+    return 1024;
   }
-
+  /** Although there is no limit, it is not recommended */
   @Override
   public int getMaxUserNameLength() {
-    return 0;
+    return 1024;
   }
 
   @Override
-  public String getNumericFunctions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
-  }
-
-  @Override
-  public ResultSet getPrimaryKeys(String arg0, String arg1, String arg2) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getNumericFunctions() {
+    ResultSet resultSet = null;
+    Statement statement = null;
+    String result = "";
+    try {
+      statement = connection.createStatement();
+      StringBuilder str = new StringBuilder("");
+      resultSet = statement.executeQuery("show functions");
+      List<String> listfunction = Arrays.asList("MAX_TIME", "MIN_TIME", "TIME_DIFFERENCE", "NOW");
+      while (resultSet.next()) {
+        if (listfunction.contains(resultSet.getString(1))) {
+          continue;
+        }
+        str.append(resultSet.getString(1)).append(",");
+      }
+      result = str.toString();
+      if (result.length() > 0) {
+        result = result.substring(0, result.length() - 1);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(resultSet, statement);
+    }
+    return result;
+  }
+
+  @Override
+  public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
+    Statement stmt = connection.createStatement();
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.TEXT);
+    List<Object> listValSub_1 = Arrays.asList(catalog, "", table, "time", 1, "PRIMARY");
+    List<Object> listValSub_2 = Arrays.asList(catalog, "", table, "deivce", 2, "PRIMARY");
+    List<List<Object>> listVal = Arrays.asList(listValSub_1, listValSub_2);
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    Field[] fields = new Field[6];
+    fields[0] = new Field("", "TABLE_CAT", "TEXT");
+    fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+    fields[2] = new Field("", "TABLE_NAME", "TEXT");
+    fields[3] = new Field("", "COLUMN_NAME", "TEXT");
+    fields[4] = new Field("", "KEY_SEQ", "INT32");
+    fields[5] = new Field("", "PK_NAME", "TEXT");
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+    }
+    for (List<Object> listob : listVal) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        m.put("val", listob.get(i));
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
   public ResultSet getProcedureColumns(String arg0, String arg1, String arg2, String arg3)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
-  }
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
 
-  @Override
-  public String getProcedureTerm() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+      Field[] fields = new Field[20];
+      fields[0] = new Field("", "PROCEDURE_CAT", "TEXT");
+      fields[1] = new Field("", "PROCEDURE_SCHEM", "TEXT");
+      fields[2] = new Field("", "PROCEDURE_NAME", "TEXT");
+      fields[3] = new Field("", "COLUMN_NAME", "TEXT");
+      fields[4] = new Field("", "COLUMN_TYPE", "TEXT");
+      fields[5] = new Field("", "DATA_TYPE", "INT32");
+      fields[6] = new Field("", "TYPE_NAME", "TEXT");
+      fields[7] = new Field("", "PRECISION", "TEXT");
+      fields[8] = new Field("", "LENGTH", "TEXT");
+      fields[9] = new Field("", "SCALE", "TEXT");
+      fields[10] = new Field("", "RADIX", "TEXT");
+      fields[11] = new Field("", "NULLABLE", "TEXT");
+      fields[12] = new Field("", "REMARKS", "TEXT");
+      fields[13] = new Field("", "COLUMN_DEF", "TEXT");
+      fields[14] = new Field("", "SQL_DATA_TYPE", "INT32");
+      fields[15] = new Field("", "SQL_DATETIME_SUB", "TEXT");
+      fields[16] = new Field("", "CHAR_OCTET_LENGTH", "TEXT");
+      fields[17] = new Field("", "ORDINAL_POSITION", "TEXT");
+      fields[18] = new Field("", "IS_NULLABLE", "TEXT");
+      fields[19] = new Field("", "SPECIFIC_NAME", "TEXT");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
+  }
+
+  @Override
+  public String getProcedureTerm() {
+    return "";
   }
 
   @Override
   public ResultSet getProcedures(String arg0, String arg1, String arg2) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[6];
+      fields[0] = new Field("", "PROCEDURE_CAT", "TEXT");
+      fields[1] = new Field("", "PROCEDURE_SCHEM", "TEXT");
+      fields[2] = new Field("", "PROCEDURE_NAME", "TEXT");
+      fields[3] = new Field("", "REMARKS", "TEXT");
+      fields[4] = new Field("", "PROCEDURE_TYPE", "TEXT");
+      fields[5] = new Field("", "SPECIFIC_NAME", "TEXT");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
   }
 
   @Override
   public ResultSet getPseudoColumns(
       String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    Statement stmt = connection.createStatement();
+    Field[] fields = new Field[12];
+    fields[0] = new Field("", "TABLE_CAT", "TEXT");
+    fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+    fields[2] = new Field("", "TABLE_NAME", "TEXT");
+    fields[3] = new Field("", "COLUMN_NAME", "TEXT");
+    fields[4] = new Field("", "DATA_TYPE", "INT32");
+    fields[5] = new Field("", "COLUMN_SIZE", "INT32");
+    fields[6] = new Field("", "DECIMAL_DIGITS", "INT32");
+    fields[7] = new Field("", "NUM_PREC_RADIX", "INT32");
+    fields[8] = new Field("", "COLUMN_USAGE", "TEXT");
+    fields[9] = new Field("", "REMARKS", "TEXT");
+    fields[10] = new Field("", "CHAR_OCTET_LENGTH", "INT32");
+    fields[11] = new Field("", "IS_NULLABLE", "TEXT");
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.TEXT);
+    List<Object> listVal =
+        Arrays.asList(
+            catalog, catalog, tableNamePattern, "times", Types.BIGINT, 1, 0, 2, "", "", 13, "NO");
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    List<Map> properties = new ArrayList<Map>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+      Map<String, Object> m = new HashMap<>();
+      m.put("type", listType.get(i));
+      m.put("val", listVal.get(i));
+      properties.add(m);
+    }
+    bigproperties.add(properties);
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
   public int getResultSetHoldability() {
-    return 0;
+    return ResultSet.HOLD_CURSORS_OVER_COMMIT;
   }
 
   @Override
-  public RowIdLifetime getRowIdLifetime() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public RowIdLifetime getRowIdLifetime() {
+    return RowIdLifetime.ROWID_UNSUPPORTED;
   }
 
   @Override
-  public String getSQLKeywords() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getSQLKeywords() {
+    return sqlKeywordsThatArentSQL92;
   }
 
   @Override
@@ -410,558 +1673,1429 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
   }
 
   @Override
-  public String getSchemaTerm() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getSchemaTerm() {
+    return "stroge group";
   }
 
   @Override
   public ResultSet getSchemas() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    Statement stmt = this.connection.createStatement();
+    ResultSet rs = stmt.executeQuery("SHOW STORAGE GROUP ");
+    Field[] fields = new Field[2];
+    fields[0] = new Field("", "TABLE_SCHEM", "TEXT");
+    fields[1] = new Field("", "TABLE_CATALOG", "TEXT");
+    List<TSDataType> listType = Arrays.asList(TSDataType.TEXT, TSDataType.TEXT);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+    }
+    while (rs.next()) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        m.put("val", rs.getString(1));
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(rs, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
   public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    return getSchemas();
   }
 
   @Override
-  public String getSearchStringEscape() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getSearchStringEscape() {
+    return "\\";
   }
 
   @Override
-  public String getStringFunctions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getStringFunctions() {
+    return getSystemFunctions();
   }
 
   @Override
   public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[4];
+      fields[0] = new Field("", "TABLE_CAT", "TEXT");
+      fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+      fields[2] = new Field("", "TABLE_NAME", "TEXT");
+      fields[3] = new Field("", "SUPERTABLE_NAME", "TEXT");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
   }
 
   @Override
   public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
-  }
-
-  @Override
-  public String getSystemFunctions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[6];
+      fields[0] = new Field("", "TABLE_CAT", "TEXT");
+      fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+      fields[2] = new Field("", "TABLE_NAME", "TEXT");
+      fields[3] = new Field("", "SUPERTYPE_CAT", "TEXT");
+      fields[4] = new Field("", "SUPERTYPE_SCHEM", "TEXT");
+      fields[5] = new Field("", "SUPERTYPE_NAME", "TEXT");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
+  }
+
+  @Override
+  public String getSystemFunctions() {
+    String result = "";
+    Statement statement = null;
+    ResultSet resultSet = null;
+    try {
+      statement = connection.createStatement();
+      StringBuilder str = new StringBuilder("");
+      resultSet = statement.executeQuery("show functions");
+      while (resultSet.next()) {
+        str.append(resultSet.getString(1)).append(",");
+      }
+      result = str.toString();
+      if (result.length() > 0) {
+        result = result.substring(0, result.length() - 1);
+      }
+    } catch (Exception ex) {
+      ex.printStackTrace();
+    } finally {
+      colse(resultSet, statement);
+    }
+    return result;
   }
 
   @Override
   public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    Statement stmt = this.connection.createStatement();
+
+    String sql = "SHOW STORAGE GROUP";
+    if (catalog != null && catalog.length() > 0) {
+      sql = sql + " " + catalog;
+    } else if (schemaPattern != null && schemaPattern.length() > 0) {
+      sql = sql + " " + schemaPattern;
+    }
+    if (((catalog != null && catalog.length() > 0)
+            || schemaPattern != null && schemaPattern.length() > 0)
+        && tableNamePattern != null
+        && tableNamePattern.length() > 0) {
+      sql = sql + "." + tableNamePattern;
+    }
+
+    ResultSet rs = stmt.executeQuery(sql);
+    Field[] fields = new Field[8];
+    fields[0] = new Field("", "TABLE_CAT", "TEXT");
+    fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+    fields[2] = new Field("", "TABLE_NAME", "TEXT");
+    fields[3] = new Field("", "COLUMN_NAME", "TEXT");
+    fields[4] = new Field("", "GRANTOR", "TEXT");
+    fields[5] = new Field("", "GRANTEE", "TEXT");
+    fields[6] = new Field("", "PRIVILEGE", "TEXT");
+    fields[7] = new Field("", "IS_GRANTABLE", "TEXT");
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+    }
+    while (rs.next()) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        if (i < 4) {
+          m.put("val", rs.getString(1));
+        } else if (i == 5) {
+          m.put("val", getUserName());
+        } else if (i == 6) {
+          m.put("val", "");
+        } else if (i == 7) {
+          m.put("val", "NO");
+        } else {
+          m.put("val", "");
+        }
+
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(rs, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
   public ResultSet getTableTypes() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    Statement stmt = this.connection.createStatement();
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigpaths = new ArrayList<List<Map>>();
+    List<Map> paths = new ArrayList<Map>();
+    ListDataSet dataSet = new ListDataSet();
+    Map<String, Object> m = new HashMap<>();
+    m.put("type", TSDataType.TEXT);
+    m.put("val", "table");
+    paths.add(m);
+    bigpaths.add(paths);
+    addToDataSet(bigpaths, dataSet);
+    columnNameList.add("TABLE_TYPE");
+    columnTypeList.add("TEXT");
+    columnNameIndex.put("TABLE_TYPE", 0);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
   public ResultSet getColumns(
-      String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) {
-    return null;
+      String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)
+      throws SQLException {
+    Statement stmt = this.connection.createStatement();
+
+    String sql = "SHOW STORAGE GROUP";
+    if (catalog != null && catalog.length() > 0) {
+      sql = sql + " " + catalog;
+    } else if (schemaPattern != null && schemaPattern.length() > 0) {
+      sql = sql + " " + schemaPattern;
+    }
+    if (((catalog != null && catalog.length() > 0)
+            || schemaPattern != null && schemaPattern.length() > 0)
+        && tableNamePattern != null
+        && tableNamePattern.length() > 0) {
+      sql = sql + "." + tableNamePattern;
+    }
+
+    if (((catalog != null && catalog.length() > 0)
+            || schemaPattern != null && schemaPattern.length() > 0)
+        && tableNamePattern != null
+        && tableNamePattern.length() > 0
+        && columnNamePattern != null
+        && columnNamePattern.length() > 0) {
+      sql = sql + "." + columnNamePattern;
+    }
+    ResultSet rs = stmt.executeQuery(sql);
+    Field[] fields = new Field[24];
+    fields[0] = new Field("", "TABLE_CAT", "TEXT");
+    fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+    fields[2] = new Field("", "TABLE_NAME", "TEXT");
+    fields[3] = new Field("", "COLUMN_NAME", "TEXT");
+    fields[4] = new Field("", "DATA_TYPE", "INT32");
+    fields[5] = new Field("", "TYPE_NAME", "TEXT");
+    fields[6] = new Field("", "COLUMN_SIZE", "INT32");
+    fields[7] = new Field("", "BUFFER_LENGTH", "INT32");
+    fields[8] = new Field("", "DECIMAL_DIGITS", "INT32");
+    fields[9] = new Field("", "NUM_PREC_RADIX", "INT32");
+    fields[10] = new Field("", "NULLABLE", "INT32");
+    fields[11] = new Field("", "REMARKS", "TEXT");
+    fields[12] = new Field("", "COLUMN_DEF", "TEXT");
+    fields[13] = new Field("", "SQL_DATA_TYPE", "INT32");
+    fields[14] = new Field("", "SQL_DATETIME_SUB", "INT32");
+    fields[15] = new Field("", "CHAR_OCTET_LENGTH", "INT32");
+    fields[16] = new Field("", "ORDINAL_POSITION", "INT32");
+    fields[17] = new Field("", "IS_NULLABLE", "TEXT");
+    fields[18] = new Field("", "SCOPE_CATALOG", "TEXT");
+    fields[19] = new Field("", "SCOPE_SCHEMA", "TEXT");
+    fields[20] = new Field("", "SCOPE_TABLE", "TEXT");
+    fields[21] = new Field("", "SOURCE_DATA_TYPE", "INT32");
+    fields[22] = new Field("", "IS_AUTOINCREMENT", "TEXT");
+    fields[23] = new Field("", "IS_GENERATEDCOLUMN", "TEXT");
+
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.TEXT);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+    }
+    while (rs.next()) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        if (i < 4) {
+          m.put("val", rs.getString(1));
+        } else if (i == 4) {
+          m.put("val", getSQLType(fields[i].getSqlType()));
+        } else if (i == 6) {
+          m.put("val", getTypePrecision(fields[i].getSqlType()));
+        } else if (i == 7) {
+          m.put("val", 0);
+        } else if (i == 8) {
+          m.put("val", getTypeScale(fields[i].getSqlType()));
+        } else if (i == 9) {
+          m.put("val", 10);
+        } else if (i == 10) {
+          m.put("val", 0);
+        } else if (i == 11) {
+          m.put("val", "");
+        } else if (i == 12) {
+          m.put("val", "");
+        } else if (i == 13) {
+          m.put("val", 0);
+        } else if (i == 14) {
+          m.put("val", 0);
+        } else if (i == 15) {
+          m.put("val", getTypePrecision(fields[i].getSqlType()));
+        } else if (i == 16) {
+          m.put("val", 1);
+        } else if (i == 17) {
+          m.put("val", "NO");
+        } else if (i == 18) {
+          m.put("val", "");
+        } else if (i == 19) {
+          m.put("val", "");
+        } else if (i == 20) {
+          m.put("val", "");
+        } else if (i == 21) {
+          m.put("val", 0);
+        } else if (i == 22) {
+          m.put("val", "NO");
+        } else if (i == 23) {
+          m.put("val", "NO");
+        } else {
+          m.put("val", "");
+        }
+
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(rs, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
+  }
+
+  private void colse(ResultSet rs, Statement stmt) {
+
+    try {
+      if (rs != null) {
+        rs.close();
+      }
+    } catch (Exception ex) {
+      rs = null;
+    }
+    try {
+      if (stmt != null) {
+        stmt.close();
+      }
+    } catch (Exception ex) {
+      stmt = null;
+    }
+  }
+
+  public int getTypeScale(String columnType) {
+    switch (columnType.toUpperCase()) {
+      case "BOOLEAN":
+      case "INT32":
+      case "INT64":
+      case "TEXT":
+        return 0;
+      case "FLOAT":
+        return 6;
+      case "DOUBLE":
+        return 15;
+      default:
+        break;
+    }
+    return 0;
+  }
+
+  private int getSQLType(String columnType) {
+    switch (columnType.toUpperCase()) {
+      case "BOOLEAN":
+        return Types.BOOLEAN;
+      case "INT32":
+        return Types.INTEGER;
+      case "INT64":
+        return Types.BIGINT;
+      case "FLOAT":
+        return Types.FLOAT;
+      case "DOUBLE":
+        return Types.DOUBLE;
+      case "TEXT":
+        return Types.LONGVARCHAR;
+      default:
+        break;
+    }
+    return 0;
+  }
+
+  private int getTypePrecision(String columnType) {
+    // BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT,
+    switch (columnType.toUpperCase()) {
+      case "BOOLEAN":
+        return 1;
+      case "INT32":
+        return 10;
+      case "INT64":
+        return 19;
+      case "FLOAT":
+        return 38;
+      case "DOUBLE":
+        return 308;
+      case "TEXT":
+        return Integer.MAX_VALUE;
+      default:
+        break;
+    }
+    return 0;
   }
 
   @Override
   public ResultSet getTables(
       String catalog, String schemaPattern, String tableNamePattern, String[] types)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    Statement stmt = this.connection.createStatement();
+
+    String sql = "SHOW timeseries";
+    if (catalog != null && catalog.length() > 0) {
+      sql = sql + " " + catalog;
+    } else if (schemaPattern != null && schemaPattern.length() > 0) {
+      sql = sql + " " + schemaPattern;
+    }
+    if (((catalog != null && catalog.length() > 0)
+            || schemaPattern != null && schemaPattern.length() > 0)
+        && tableNamePattern != null
+        && tableNamePattern.length() > 0) {
+      sql = sql + "." + tableNamePattern;
+    }
+    ResultSet rs = stmt.executeQuery(sql);
+    Field[] fields = new Field[10];
+    fields[0] = new Field("", "TABLE_CAT", "TEXT");
+    fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+    fields[2] = new Field("", "TABLE_NAME", "TEXT");
+    fields[3] = new Field("", "TABLE_TYPE", "TEXT");
+    fields[4] = new Field("", "REMARKS", "TEXT");
+    fields[5] = new Field("", "TYPE_CAT", "TEXT");
+    fields[6] = new Field("", "TYPE_SCHEM", "TEXT");
+    fields[7] = new Field("", "TYPE_NAME", "TEXT");
+    fields[8] = new Field("", "SELF_REFERENCING_COL_NAME", "TEXT");
+    fields[9] = new Field("", "REF_GENERATION", "TEXT");
+
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+    }
+    while (rs.next()) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        if (i < 2) {
+          m.put("val", rs.getString(3));
+        } else if (i == 2) {
+          m.put("val", rs.getString(1));
+        } else if (i == 3) {
+          m.put("val", "TABLE");
+        } else {
+          m.put("val", "");
+        }
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
-  public String getTimeDateFunctions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public String getTimeDateFunctions() {
+    return "MAX_TIME,MIN_TIME,TIME_DIFFERENCE,NOW";
   }
 
   @Override
   public ResultSet getTypeInfo() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    Statement stmt = connection.createStatement();
+    Field[] fields = new Field[18];
+    fields[0] = new Field("", "TYPE_NAME", "TEXT");
+    fields[1] = new Field("", "DATA_TYPE", "INT32");
+    fields[2] = new Field("", "PRECISION", "INT32");
+    fields[3] = new Field("", "LITERAL_PREFIX", "TEXT");
+    fields[4] = new Field("", "LITERAL_SUFFIX", "TEXT");
+    fields[5] = new Field("", "CREATE_PARAMS", "TEXT");
+    fields[6] = new Field("", "NULLABLE", "INT32");
+    fields[7] = new Field("", "CASE_SENSITIVE", "BOOLEAN");
+    fields[8] = new Field("", "SEARCHABLE", "TEXT");
+    fields[9] = new Field("", "UNSIGNED_ATTRIBUTE", "BOOLEAN");
+    fields[10] = new Field("", "FIXED_PREC_SCALE", "BOOLEAN");
+    fields[11] = new Field("", "AUTO_INCREMENT", "BOOLEAN");
+    fields[12] = new Field("", "LOCAL_TYPE_NAME", "TEXT");
+    fields[13] = new Field("", "MINIMUM_SCALE", "INT32");
+    fields[14] = new Field("", "MAXIMUM_SCALE", "INT32");
+    fields[15] = new Field("", "SQL_DATA_TYPE", "INT32");
+    fields[16] = new Field("", "SQL_DATETIME_SUB", "INT32");
+    fields[17] = new Field("", "NUM_PREC_RADIX", "INT32");
+    List<TSDataType> listType =
+        Arrays.asList(
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.BOOLEAN,
+            TSDataType.TEXT,
+            TSDataType.BOOLEAN,
+            TSDataType.BOOLEAN,
+            TSDataType.BOOLEAN,
+            TSDataType.TEXT,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32,
+            TSDataType.INT32);
+    List<Object> listValSub_1 =
+        Arrays.asList(
+            "INT32",
+            Types.INTEGER,
+            10,
+            "",
+            "",
+            "",
+            1,
+            true,
+            "",
+            false,
+            true,
+            false,
+            "",
+            0,
+            10,
+            0,
+            0,
+            10);
+    List<Object> listValSub_2 =
+        Arrays.asList(
+            "INT64",
+            Types.BIGINT,
+            19,
+            "",
+            "",
+            "",
+            1,
+            true,
+            "",
+            false,
+            true,
+            false,
+            "",
+            0,
+            10,
+            0,
+            0,
+            10);
+    List<Object> listValSub_3 =
+        Arrays.asList(
+            "BOOLEAN",
+            Types.BOOLEAN,
+            1,
+            "",
+            "",
+            "",
+            1,
+            true,
+            "",
+            false,
+            true,
+            false,
+            "",
+            0,
+            10,
+            0,
+            0,
+            10);
+    List<Object> listValSub_4 =
+        Arrays.asList(
+            "FLOAT",
+            Types.FLOAT,
+            38,
+            "",
+            "",
+            "",
+            1,
+            true,
+            "",
+            false,
+            true,
+            false,
+            "",
+            0,
+            10,
+            0,
+            0,
+            10);
+    List<Object> listValSub_5 =
+        Arrays.asList(
+            "DOUBLE",
+            Types.DOUBLE,
+            308,
+            "",
+            "",
+            "",
+            1,
+            true,
+            "",
+            false,
+            true,
+            false,
+            "",
+            0,
+            10,
+            0,
+            0,
+            10);
+    List<Object> listValSub_6 =
+        Arrays.asList(
+            "TEXT",
+            Types.LONGVARCHAR,
+            64,
+            "",
+            "",
+            "",
+            1,
+            true,
+            "",
+            false,
+            true,
+            false,
+            "",
+            0,
+            10,
+            0,
+            0,
+            10);
+    List<List<Object>> listVal =
+        Arrays.asList(
+            listValSub_1, listValSub_2, listValSub_3, listValSub_4, listValSub_5, listValSub_6);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    List<List<Map>> bigproperties = new ArrayList<List<Map>>();
+    ListDataSet dataSet = new ListDataSet();
+    for (int i = 0; i < fields.length; i++) {
+      columnNameList.add(fields[i].getName());
+      columnTypeList.add(fields[i].getSqlType());
+      columnNameIndex.put(fields[i].getName(), i);
+      Map<String, Object> m = new HashMap<>();
+    }
+    for (List<Object> listob : listVal) {
+      List<Map> properties = new ArrayList<Map>();
+      for (int i = 0; i < fields.length; i++) {
+        Map<String, Object> m = new HashMap<>();
+        m.put("type", listType.get(i));
+        m.put("val", listob.get(i));
+        properties.add(m);
+      }
+      bigproperties.add(properties);
+    }
+    addToDataSet(bigproperties, dataSet);
+    TSQueryDataSet tsdataset = null;
+    try {
+      tsdataset =
+          convertQueryDataSetByFetchSize(dataSet, stmt.getFetchSize(), getWatermarkEncoder());
+    } catch (IOException e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        true,
+        client,
+        null,
+        0,
+        sessionId,
+        tsdataset,
+        (long) 60 * 1000,
+        false);
   }
 
   @Override
   public ResultSet getUDTs(
       String catalog, String schemaPattern, String typeNamePattern, int[] types)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[7];
+      fields[0] = new Field("", "TABLE_CAT", "TEXT");
+      fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
+      fields[2] = new Field("", "TABLE_NAME", "TEXT");
+      fields[3] = new Field("", "CLASS_NAME", "TEXT");
+      fields[4] = new Field("", "DATA_TYPE", "INT32");
+      fields[5] = new Field("", "REMARKS", "TEXT");
+      fields[6] = new Field("", "BASE_TYPE", "TEXT");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
   }
 
   @Override
   public String getURL() {
     // TODO: Return the URL for this DBMS or null if it cannot be generated
-    return null;
+    return this.connection.getUrl();
   }
 
   @Override
-  public String getUserName() {
-    return client.toString();
+  public String getUserName() throws SQLException {
+    return connection.getUserName();
   }
 
   @Override
   public ResultSet getVersionColumns(String catalog, String schema, String table)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
-  }
-
-  @Override
-  public boolean insertsAreDetected(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    List<String> columnNameList = new ArrayList<String>();
+    List<String> columnTypeList = new ArrayList<String>();
+    Map<String, Integer> columnNameIndex = new HashMap<String, Integer>();
+    Statement stmt = connection.createStatement();
+    try {
+      Field[] fields = new Field[8];
+      fields[0] = new Field("", "SCOPE", "INT32");
+      fields[1] = new Field("", "COLUMN_NAME", "TEXT");
+      fields[2] = new Field("", "DATA_TYPE", "INT32");
+      fields[3] = new Field("", "TYPE_NAME", "TEXT");
+      fields[4] = new Field("", "COLUMN_SIZE", "INT32");
+      fields[5] = new Field("", "BUFFER_LENGTH", "INT32");
+      fields[6] = new Field("", "DECIMAL_DIGITS", "INT32");
+      fields[7] = new Field("", "PSEUDO_COLUMN", "INT32");
+      for (int i = 0; i < fields.length; i++) {
+        columnNameList.add(fields[i].getName());
+        columnTypeList.add(fields[i].getSqlType());
+        columnNameIndex.put(fields[i].getName(), i);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    } finally {
+      colse(null, stmt);
+    }
+    return new IoTDBJDBCResultSet(
+        stmt,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        false,
+        client,
+        null,
+        0,
+        sessionId,
+        null,
+        (long) 60 * 1000,
+        true);
+  }
+
+  @Override
+  public boolean insertsAreDetected(int type) {
+    return false;
   }
 
   @Override
-  public boolean isCatalogAtStart() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean isCatalogAtStart() {
+    return false;
   }
 
   @Override
   public boolean isReadOnly() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    try {
+      return client.getProperties().isReadOnly;
+    } catch (TException e) {
+      e.printStackTrace();
+    }
+    throw new SQLException("Can not get the read-only mode");
   }
 
   @Override
-  public boolean locatorsUpdateCopy() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean locatorsUpdateCopy() {
+    return false;
   }
 
   @Override
-  public boolean nullPlusNonNullIsNull() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean nullPlusNonNullIsNull() {
+    return false;
   }
 
   @Override
-  public boolean nullsAreSortedAtEnd() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean nullsAreSortedAtEnd() {
+    return false;
   }
 
   @Override
-  public boolean nullsAreSortedAtStart() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean nullsAreSortedAtStart() {
+    return false;
   }
 
   @Override
-  public boolean nullsAreSortedHigh() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean nullsAreSortedHigh() {
+    return false;
   }
 
   @Override
-  public boolean nullsAreSortedLow() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean nullsAreSortedLow() {
+    return false;
   }
 
   @Override
-  public boolean othersDeletesAreVisible(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean othersDeletesAreVisible(int type) {
+    return true;
   }
 
   @Override
-  public boolean othersInsertsAreVisible(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean othersInsertsAreVisible(int type) {
+    return true;
   }
 
   @Override
-  public boolean othersUpdatesAreVisible(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean othersUpdatesAreVisible(int type) {
+    return true;
   }
 
   @Override
-  public boolean ownDeletesAreVisible(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean ownDeletesAreVisible(int type) {
+    return true;
   }
 
   @Override
-  public boolean ownInsertsAreVisible(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean ownInsertsAreVisible(int type) {
+    return true;
   }
 
   @Override
-  public boolean ownUpdatesAreVisible(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean ownUpdatesAreVisible(int type) {
+    return true;
   }
 
   @Override
-  public boolean storesLowerCaseIdentifiers() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean storesLowerCaseIdentifiers() {
+    return false;
   }
 
   @Override
-  public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean storesLowerCaseQuotedIdentifiers() {
+    return false;
   }
 
   @Override
-  public boolean storesMixedCaseIdentifiers() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean storesMixedCaseIdentifiers() {
+    return true;
   }
 
   @Override
-  public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean storesMixedCaseQuotedIdentifiers() {
+    return true;
   }
 
   @Override
-  public boolean storesUpperCaseIdentifiers() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean storesUpperCaseIdentifiers() {
+    return true;
   }
 
   @Override
-  public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean storesUpperCaseQuotedIdentifiers() {
+    return true;
   }
 
   @Override
-  public boolean supportsANSI92EntryLevelSQL() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsANSI92EntryLevelSQL() {
+    return false;
   }
 
   @Override
-  public boolean supportsANSI92FullSQL() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsANSI92FullSQL() {
+    return false;
   }
 
   @Override
-  public boolean supportsANSI92IntermediateSQL() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsANSI92IntermediateSQL() {
+    return false;
   }
 
   @Override
-  public boolean supportsAlterTableWithAddColumn() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsAlterTableWithAddColumn() {
+    return true;
   }
 
   @Override
-  public boolean supportsAlterTableWithDropColumn() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsAlterTableWithDropColumn() {
+    return true;
   }
 
   @Override
-  public boolean supportsBatchUpdates() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsBatchUpdates() {
+    return true;
   }
 
   @Override
-  public boolean supportsCatalogsInDataManipulation() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsCatalogsInDataManipulation() {
+    return true;
   }
 
   @Override
-  public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsCatalogsInIndexDefinitions() {
+    return true;
   }
 
   @Override
-  public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsCatalogsInPrivilegeDefinitions() {
+    return true;
   }
 
   @Override
-  public boolean supportsCatalogsInProcedureCalls() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsCatalogsInProcedureCalls() {
+    return true;
   }
 
   @Override
-  public boolean supportsCatalogsInTableDefinitions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsCatalogsInTableDefinitions() {
+    return false;
   }
 
   @Override
-  public boolean supportsColumnAliasing() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsColumnAliasing() {
+    return true;
   }
 
   @Override
-  public boolean supportsConvert() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsConvert() {
+    return false;
   }
 
   @Override
-  public boolean supportsConvert(int fromType, int toType) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsConvert(int fromType, int toType) {
+    return false;
   }
 
   @Override
-  public boolean supportsCoreSQLGrammar() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsCoreSQLGrammar() {
+    return false;
   }
 
   @Override
-  public boolean supportsCorrelatedSubqueries() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsCorrelatedSubqueries() {
+    return false;
   }
 
   @Override
-  public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsDataDefinitionAndDataManipulationTransactions() {
+    return false;
   }
 
   @Override
-  public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsDataManipulationTransactionsOnly() {
+    return true;
   }
 
   @Override
-  public boolean supportsDifferentTableCorrelationNames() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsDifferentTableCorrelationNames() {
+    return false;
   }
 
   @Override
-  public boolean supportsExpressionsInOrderBy() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsExpressionsInOrderBy() {
+    return true;
   }
 
   @Override
-  public boolean supportsExtendedSQLGrammar() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsExtendedSQLGrammar() {
+    return false;
   }
 
   @Override
-  public boolean supportsFullOuterJoins() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsFullOuterJoins() {
+    return true;
   }
 
   @Override
-  public boolean supportsGetGeneratedKeys() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsGetGeneratedKeys() {
+    return false;
   }
 
   @Override
-  public boolean supportsGroupBy() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsGroupBy() {
+    return true;
   }
 
   @Override
-  public boolean supportsGroupByBeyondSelect() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsGroupByBeyondSelect() {
+    return true;
   }
 
   @Override
-  public boolean supportsGroupByUnrelated() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsGroupByUnrelated() {
+    return true;
   }
 
   @Override
-  public boolean supportsIntegrityEnhancementFacility() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsIntegrityEnhancementFacility() {
+    return false;
   }
 
   @Override
-  public boolean supportsLikeEscapeClause() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsLikeEscapeClause() {
+    return false;
   }
 
   @Override
-  public boolean supportsLimitedOuterJoins() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsLimitedOuterJoins() {
+    return true;
   }
 
   @Override
-  public boolean supportsMinimumSQLGrammar() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsMinimumSQLGrammar() {
+    return false;
   }
 
   @Override
-  public boolean supportsMixedCaseIdentifiers() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsMixedCaseIdentifiers() {
+    return true;
   }
 
   @Override
-  public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsMixedCaseQuotedIdentifiers() {
+    return true;
   }
 
   @Override
-  public boolean supportsMultipleOpenResults() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsMultipleOpenResults() {
+    return false;
   }
 
   @Override
-  public boolean supportsMultipleResultSets() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsMultipleResultSets() {
+    return false;
   }
 
   @Override
-  public boolean supportsMultipleTransactions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsMultipleTransactions() {
+    return true;
   }
 
   @Override
-  public boolean supportsNamedParameters() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsNamedParameters() {
+    return false;
   }
 
   @Override
-  public boolean supportsNonNullableColumns() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsNonNullableColumns() {
+    return false;
   }
 
   @Override
-  public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsOpenCursorsAcrossCommit() {
+    return false;
   }
 
   @Override
-  public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsOpenCursorsAcrossRollback() {
+    return false;
   }
 
   @Override
-  public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsOpenStatementsAcrossCommit() {
+    return false;
   }
 
   @Override
-  public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsOpenStatementsAcrossRollback() {
+    return false;
   }
 
   @Override
-  public boolean supportsOrderByUnrelated() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsOrderByUnrelated() {
+    return true;
   }
 
   @Override
-  public boolean supportsOuterJoins() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsOuterJoins() {
+    return true;
   }
 
   @Override
-  public boolean supportsPositionedDelete() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsPositionedDelete() {
+    return false;
   }
 
   @Override
-  public boolean supportsPositionedUpdate() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsPositionedUpdate() {
+    return false;
   }
 
   @Override
-  public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsResultSetConcurrency(int type, int concurrency) {
+    return false;
   }
 
   @Override
-  public boolean supportsResultSetHoldability(int holdability) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsResultSetHoldability(int holdability) {
+    if (ResultSet.HOLD_CURSORS_OVER_COMMIT == holdability) {
+      return true;
+    }
+    return false;
   }
 
   @Override
   public boolean supportsResultSetType(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    if (ResultSet.FETCH_FORWARD == type || ResultSet.TYPE_FORWARD_ONLY == type) {
+      return true;
+    }
+    return false;
   }
 
   @Override
-  public boolean supportsSavepoints() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSavepoints() {
+    return false;
   }
 
   @Override
-  public boolean supportsSchemasInDataManipulation() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSchemasInDataManipulation() {
+    return false;
   }
 
   @Override
-  public boolean supportsSchemasInIndexDefinitions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSchemasInIndexDefinitions() {
+    return false;
   }
 
   @Override
-  public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSchemasInPrivilegeDefinitions() {
+    return false;
   }
 
   @Override
-  public boolean supportsSchemasInProcedureCalls() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSchemasInProcedureCalls() {
+    return false;
   }
 
   @Override
-  public boolean supportsSchemasInTableDefinitions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSchemasInTableDefinitions() {
+    return false;
   }
 
   @Override
-  public boolean supportsSelectForUpdate() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSelectForUpdate() {
+    return false;
   }
 
   @Override
-  public boolean supportsStatementPooling() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsStatementPooling() {
+    return false;
   }
 
   @Override
-  public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsStoredFunctionsUsingCallSyntax() {
+    return false;
   }
 
   @Override
-  public boolean supportsStoredProcedures() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsStoredProcedures() {
+    return false;
   }
 
   @Override
-  public boolean supportsSubqueriesInComparisons() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSubqueriesInComparisons() {
+    return false;
   }
 
   @Override
-  public boolean supportsSubqueriesInExists() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSubqueriesInExists() {
+    return false;
   }
 
   @Override
-  public boolean supportsSubqueriesInIns() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSubqueriesInIns() {
+    return false;
   }
 
   @Override
-  public boolean supportsSubqueriesInQuantifieds() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsSubqueriesInQuantifieds() {
+    return false;
   }
 
   @Override
-  public boolean supportsTableCorrelationNames() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsTableCorrelationNames() {
+    return false;
   }
 
   @Override
-  public boolean supportsTransactionIsolationLevel(int level) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsTransactionIsolationLevel(int level) {
+    return false;
   }
 
   @Override
-  public boolean supportsTransactions() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsTransactions() {
+    return false;
   }
 
   @Override
-  public boolean supportsUnion() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsUnion() {
+    return false;
   }
 
   @Override
-  public boolean supportsUnionAll() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean supportsUnionAll() {
+    return false;
   }
 
   @Override
-  public boolean updatesAreDetected(int type) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean updatesAreDetected(int type) {
+    return false;
   }
 
   @Override
-  public boolean usesLocalFilePerTable() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean usesLocalFilePerTable() {
+    return false;
   }
 
   @Override
-  public boolean usesLocalFiles() throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+  public boolean usesLocalFiles() {
+    return false;
   }
 
   /** @deprecated recommend using getMetadataInJson() instead of toString() */
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java
index 9039a1c..b7ea02d 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java
@@ -26,10 +26,14 @@ import org.apache.iotdb.service.rpc.thrift.TSQueryDataSet;
 
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.BitSet;
 import java.util.List;
 import java.util.Map;
 
 public class IoTDBJDBCResultSet extends AbstractIoTDBJDBCResultSet {
+  private String operationType = "";
+  private List<String> columns = null;
+  private List<String> sgColumns = null;
 
   public IoTDBJDBCResultSet(
       Statement statement,
@@ -42,7 +46,11 @@ public class IoTDBJDBCResultSet extends AbstractIoTDBJDBCResultSet {
       long queryId,
       long sessionId,
       TSQueryDataSet dataset,
-      long timeout)
+      long timeout,
+      String operationType,
+      List<String> columns,
+      List<String> sgColumns,
+      BitSet aliasColumnMap)
       throws SQLException {
     super(
         statement,
@@ -54,7 +62,41 @@ public class IoTDBJDBCResultSet extends AbstractIoTDBJDBCResultSet {
         sql,
         queryId,
         sessionId,
-        timeout);
+        timeout,
+        sgColumns,
+        aliasColumnMap);
+    ioTDBRpcDataSet.setTsQueryDataSet(dataset);
+    this.operationType = operationType;
+    this.columns = columns;
+    this.sgColumns = sgColumns;
+  }
+
+  public IoTDBJDBCResultSet(
+      Statement statement,
+      List<String> columnNameList,
+      List<String> columnTypeList,
+      Map<String, Integer> columnNameIndex,
+      boolean ignoreTimeStamp,
+      TSIService.Iface client,
+      String sql,
+      long queryId,
+      long sessionId,
+      TSQueryDataSet dataset,
+      long timeout,
+      boolean isRpcFetchResult)
+      throws SQLException {
+    super(
+        statement,
+        columnNameList,
+        columnTypeList,
+        columnNameIndex,
+        ignoreTimeStamp,
+        client,
+        sql,
+        queryId,
+        sessionId,
+        timeout,
+        isRpcFetchResult);
     ioTDBRpcDataSet.setTsQueryDataSet(dataset);
   }
 
@@ -116,4 +158,16 @@ public class IoTDBJDBCResultSet extends AbstractIoTDBJDBCResultSet {
   public boolean isIgnoreTimeStamp() {
     return ioTDBRpcDataSet.ignoreTimeStamp;
   }
+
+  public String getOperationType() {
+    return this.operationType;
+  }
+
+  public List<String> getColumns() {
+    return this.columns;
+  }
+
+  public List<String> getSgColumns() {
+    return sgColumns;
+  }
 }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBNonAlignJDBCResultSet.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBNonAlignJDBCResultSet.java
index da0831a..b04b20d 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBNonAlignJDBCResultSet.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBNonAlignJDBCResultSet.java
@@ -36,6 +36,7 @@ import java.nio.ByteBuffer;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -48,10 +49,10 @@ public class IoTDBNonAlignJDBCResultSet extends AbstractIoTDBJDBCResultSet {
 
   private static final int TIMESTAMP_STR_LENGTH = 4;
   private static final String EMPTY_STR = "";
-
+  private String operationType = "";
   private TSQueryNonAlignDataSet tsQueryNonAlignDataSet;
   private byte[][] times; // used for disable align
-
+  private List<String> sgColumns = null;
   // for disable align clause
   IoTDBNonAlignJDBCResultSet(
       Statement statement,
@@ -64,7 +65,10 @@ public class IoTDBNonAlignJDBCResultSet extends AbstractIoTDBJDBCResultSet {
       long queryId,
       long sessionId,
       TSQueryNonAlignDataSet dataset,
-      long timeout)
+      long timeout,
+      String operationType,
+      List<String> sgColumns,
+      BitSet aliasColumnMap)
       throws SQLException {
     super(
         statement,
@@ -76,10 +80,11 @@ public class IoTDBNonAlignJDBCResultSet extends AbstractIoTDBJDBCResultSet {
         sql,
         queryId,
         sessionId,
-        timeout);
-
+        timeout,
+        sgColumns,
+        aliasColumnMap);
     times = new byte[columnNameList.size()][Long.BYTES];
-
+    this.operationType = operationType;
     ioTDBRpcDataSet.columnNameList = new ArrayList<>();
     ioTDBRpcDataSet.columnTypeList = new ArrayList<>();
     // deduplicate and map
@@ -90,8 +95,18 @@ public class IoTDBNonAlignJDBCResultSet extends AbstractIoTDBJDBCResultSet {
     for (int i = 0; i < columnNameIndex.size(); i++) {
       ioTDBRpcDataSet.columnTypeDeduplicatedList.add(null);
     }
+    List<String> newSgColumns = new ArrayList<>();
     for (int i = 0; i < columnNameList.size(); i++) {
-      String name = columnNameList.get(i);
+      String name = "";
+      if (sgColumns != null && sgColumns.size() > 0) {
+        name = sgColumns.get(i) + "." + columnNameList.get(i);
+        newSgColumns.add(sgColumns.get(i));
+        newSgColumns.add(sgColumns.get(i));
+      } else {
+        name = columnNameList.get(i);
+        newSgColumns.add("");
+        newSgColumns.add("");
+      }
       ioTDBRpcDataSet.columnNameList.add(TIMESTAMP_STR + name);
       ioTDBRpcDataSet.columnNameList.add(name);
       ioTDBRpcDataSet.columnTypeList.add(String.valueOf(TSDataType.INT64));
@@ -103,6 +118,7 @@ public class IoTDBNonAlignJDBCResultSet extends AbstractIoTDBJDBCResultSet {
             index, TSDataType.valueOf(columnTypeList.get(i)));
       }
     }
+    this.sgColumns = newSgColumns;
     this.tsQueryNonAlignDataSet = dataset;
   }
 
@@ -280,4 +296,12 @@ public class IoTDBNonAlignJDBCResultSet extends AbstractIoTDBJDBCResultSet {
     return ioTDBRpcDataSet.getObject(
         index, ioTDBRpcDataSet.columnTypeDeduplicatedList.get(index), ioTDBRpcDataSet.values);
   }
+
+  public String getOperationType() {
+    return this.operationType;
+  }
+
+  public List<String> getSgColumns() {
+    return sgColumns;
+  }
 }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java
index ea8c2b7..aa7e130 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBPreparedStatement.java
@@ -19,12 +19,15 @@
 package org.apache.iotdb.jdbc;
 
 import org.apache.iotdb.service.rpc.thrift.TSIService.Iface;
+import org.apache.iotdb.tsfile.utils.Binary;
 
+import org.apache.thrift.TException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.InputStream;
 import java.io.Reader;
+import java.io.StringReader;
 import java.math.BigDecimal;
 import java.net.URL;
 import java.sql.Array;
@@ -42,11 +45,20 @@ import java.sql.SQLException;
 import java.sql.SQLXML;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.sql.Types;
+import java.text.DateFormat;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 
 public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedStatement {
 
@@ -177,58 +189,58 @@ public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedSt
 
   @Override
   public void setArray(int parameterIndex, Array x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setBlob(int parameterIndex, Blob x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setBlob(int parameterIndex, InputStream inputStream, long length)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
@@ -238,54 +250,55 @@ public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedSt
 
   @Override
   public void setByte(int parameterIndex, byte x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setBytes(int parameterIndex, byte[] x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    Binary binary = new Binary(x);
+    this.parameters.put(parameterIndex, binary.getStringValue());
   }
 
   @Override
   public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setCharacterStream(int parameterIndex, Reader reader, int length)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setCharacterStream(int parameterIndex, Reader reader, long length)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setClob(int parameterIndex, Clob x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setClob(int parameterIndex, Reader reader) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setDate(int parameterIndex, Date x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
@@ -310,43 +323,43 @@ public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedSt
 
   @Override
   public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setNCharacterStream(int parameterIndex, Reader value, long length)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setNClob(int parameterIndex, NClob value) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setNClob(int parameterIndex, Reader reader) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setNString(int parameterIndex, String value) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setNull(int parameterIndex, int sqlType) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_NOT_NULL);
   }
 
   @Override
   public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_NOT_NULL);
   }
 
   @Override
@@ -365,6 +378,8 @@ public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedSt
       setBoolean(parameterIndex, (Boolean) x);
     } else if (x instanceof Timestamp) {
       setTimestamp(parameterIndex, (Timestamp) x);
+    } else if (x instanceof Time) {
+      setTime(parameterIndex, (Time) x);
     } else {
       // Can't infer a type.
       throw new SQLException(
@@ -377,18 +392,454 @@ public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedSt
 
   @Override
   public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    if (!(x instanceof BigDecimal)) {
+      setObject(parameterIndex, x, targetSqlType, 0);
+    } else {
+      setObject(parameterIndex, x, targetSqlType, ((BigDecimal) x).scale());
+    }
   }
 
   @Override
-  public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)
+  public void setObject(int parameterIndex, Object parameterObj, int targetSqlType, int scale)
       throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    if (parameterObj == null) {
+      setNull(parameterIndex, java.sql.Types.OTHER);
+    } else {
+      try {
+        switch (targetSqlType) {
+          case Types.BOOLEAN:
+            if (parameterObj instanceof Boolean) {
+              setBoolean(parameterIndex, ((Boolean) parameterObj).booleanValue());
+              break;
+            } else if (parameterObj instanceof String) {
+              if ("true".equalsIgnoreCase((String) parameterObj)
+                  || "Y".equalsIgnoreCase((String) parameterObj)) {
+                setBoolean(parameterIndex, true);
+              } else if ("false".equalsIgnoreCase((String) parameterObj)
+                  || "N".equalsIgnoreCase((String) parameterObj)) {
+                setBoolean(parameterIndex, false);
+              } else if (((String) parameterObj).matches("-?\\d+\\.?\\d*")) {
+                setBoolean(parameterIndex, !((String) parameterObj).matches("-?[0]+[.]*[0]*"));
+              } else {
+                throw new SQLException(
+                    "No conversion from " + parameterObj + " to Types.BOOLEAN possible.");
+              }
+              break;
+            } else if (parameterObj instanceof Number) {
+              int intValue = ((Number) parameterObj).intValue();
+
+              setBoolean(parameterIndex, intValue != 0);
+
+              break;
+            } else {
+              throw new SQLException(
+                  "No conversion from " + parameterObj + " to Types.BOOLEAN possible.");
+            }
+
+          case Types.BIT:
+          case Types.TINYINT:
+          case Types.SMALLINT:
+          case Types.INTEGER:
+          case Types.BIGINT:
+          case Types.REAL:
+          case Types.FLOAT:
+          case Types.DOUBLE:
+          case Types.DECIMAL:
+          case Types.NUMERIC:
+            setNumericObject(parameterIndex, parameterObj, targetSqlType, scale);
+            break;
+          case Types.CHAR:
+          case Types.VARCHAR:
+          case Types.LONGVARCHAR:
+            if (parameterObj instanceof BigDecimal) {
+              setString(
+                  parameterIndex,
+                  StringUtils.fixDecimalExponent(
+                      StringUtils.consistentToString((BigDecimal) parameterObj)));
+            } else {
+              setString(parameterIndex, parameterObj.toString());
+            }
+
+            break;
+
+          case Types.CLOB:
+            if (parameterObj instanceof java.sql.Clob) {
+              setClob(parameterIndex, (java.sql.Clob) parameterObj);
+            } else {
+              setString(parameterIndex, parameterObj.toString());
+            }
+
+            break;
+
+          case Types.BINARY:
+          case Types.VARBINARY:
+          case Types.LONGVARBINARY:
+          case Types.BLOB:
+            throw new SQLException(Constant.PARAMETER_SUPPORTED);
+          case Types.DATE:
+          case Types.TIMESTAMP:
+            java.util.Date parameterAsDate;
+
+            if (parameterObj instanceof String) {
+              ParsePosition pp = new ParsePosition(0);
+              DateFormat sdf =
+                  new SimpleDateFormat(getDateTimePattern((String) parameterObj, false), Locale.US);
+              parameterAsDate = sdf.parse((String) parameterObj, pp);
+            } else {
+              parameterAsDate = (Date) parameterObj;
+            }
+
+            switch (targetSqlType) {
+              case Types.DATE:
+                if (parameterAsDate instanceof java.sql.Date) {
+                  setDate(parameterIndex, (java.sql.Date) parameterAsDate);
+                } else {
+                  setDate(parameterIndex, new java.sql.Date(parameterAsDate.getTime()));
+                }
+
+                break;
+
+              case Types.TIMESTAMP:
+                if (parameterAsDate instanceof java.sql.Timestamp) {
+                  setTimestamp(parameterIndex, (java.sql.Timestamp) parameterAsDate);
+                } else {
+                  setTimestamp(parameterIndex, new java.sql.Timestamp(parameterAsDate.getTime()));
+                }
+
+                break;
+            }
+
+            break;
+
+          case Types.TIME:
+            if (parameterObj instanceof String) {
+              DateFormat sdf =
+                  new SimpleDateFormat(getDateTimePattern((String) parameterObj, true), Locale.US);
+              setTime(parameterIndex, new Time(sdf.parse((String) parameterObj).getTime()));
+            } else if (parameterObj instanceof Timestamp) {
+              Timestamp xT = (Timestamp) parameterObj;
+              setTime(parameterIndex, new Time(xT.getTime()));
+            } else {
+              setTime(parameterIndex, (Time) parameterObj);
+            }
+
+            break;
+
+          case Types.OTHER:
+            throw new SQLException(Constant.PARAMETER_SUPPORTED); //
+          default:
+            throw new SQLException(Constant.PARAMETER_SUPPORTED); //
+        }
+      } catch (Exception ex) {
+        if (ex instanceof SQLException) {
+          throw (SQLException) ex;
+        }
+
+        throw new SQLException(Constant.PARAMETER_SUPPORTED); //
+      }
+    }
+  }
+
+  private final String getDateTimePattern(String dt, boolean toTime) throws Exception {
+    //
+    // Special case
+    //
+    int dtLength = (dt != null) ? dt.length() : 0;
+
+    if ((dtLength >= 8) && (dtLength <= 10)) {
+      int dashCount = 0;
+      boolean isDateOnly = true;
+
+      for (int i = 0; i < dtLength; i++) {
+        char c = dt.charAt(i);
+
+        if (!Character.isDigit(c) && (c != '-')) {
+          isDateOnly = false;
+
+          break;
+        }
+
+        if (c == '-') {
+          dashCount++;
+        }
+      }
+
+      if (isDateOnly && (dashCount == 2)) {
+        return "yyyy-MM-dd";
+      }
+    }
+    boolean colonsOnly = true;
+
+    for (int i = 0; i < dtLength; i++) {
+      char c = dt.charAt(i);
+
+      if (!Character.isDigit(c) && (c != ':')) {
+        colonsOnly = false;
+
+        break;
+      }
+    }
+
+    if (colonsOnly) {
+      return "HH:mm:ss";
+    }
+
+    int n;
+    int z;
+    int count;
+    int maxvecs;
+    char c;
+    char separator;
+    StringReader reader = new StringReader(dt + " ");
+    ArrayList<Object[]> vec = new ArrayList<Object[]>();
+    ArrayList<Object[]> vecRemovelist = new ArrayList<Object[]>();
+    Object[] nv = new Object[3];
+    Object[] v;
+    nv[0] = Character.valueOf('y');
+    nv[1] = new StringBuilder();
+    nv[2] = Integer.valueOf(0);
+    vec.add(nv);
+
+    if (toTime) {
+      nv = new Object[3];
+      nv[0] = Character.valueOf('h');
+      nv[1] = new StringBuilder();
+      nv[2] = Integer.valueOf(0);
+      vec.add(nv);
+    }
+
+    while ((z = reader.read()) != -1) {
+      separator = (char) z;
+      maxvecs = vec.size();
+
+      for (count = 0; count < maxvecs; count++) {
+        v = vec.get(count);
+        n = ((Integer) v[2]).intValue();
+        c = getSuccessor(((Character) v[0]).charValue(), n);
+
+        if (!Character.isLetterOrDigit(separator)) {
+          if ((c == ((Character) v[0]).charValue()) && (c != 'S')) {
+            vecRemovelist.add(v);
+          } else {
+            ((StringBuilder) v[1]).append(separator);
+
+            if ((c == 'X') || (c == 'Y')) {
+              v[2] = Integer.valueOf(4);
+            }
+          }
+        } else {
+          if (c == 'X') {
+            c = 'y';
+            nv = new Object[3];
+            nv[1] = (new StringBuilder(((StringBuilder) v[1]).toString())).append('M');
+            nv[0] = Character.valueOf('M');
+            nv[2] = Integer.valueOf(1);
+            vec.add(nv);
+          } else if (c == 'Y') {
+            c = 'M';
+            nv = new Object[3];
+            nv[1] = (new StringBuilder(((StringBuilder) v[1]).toString())).append('d');
+            nv[0] = Character.valueOf('d');
+            nv[2] = Integer.valueOf(1);
+            vec.add(nv);
+          }
+
+          ((StringBuilder) v[1]).append(c);
+
+          if (c == ((Character) v[0]).charValue()) {
+            v[2] = Integer.valueOf(n + 1);
+          } else {
+            v[0] = Character.valueOf(c);
+            v[2] = Integer.valueOf(1);
+          }
+        }
+      }
+
+      int size = vecRemovelist.size();
+
+      for (int i = 0; i < size; i++) {
+        v = vecRemovelist.get(i);
+        vec.remove(v);
+      }
+
+      vecRemovelist.clear();
+    }
+
+    int size = vec.size();
+
+    for (int i = 0; i < size; i++) {
+      v = vec.get(i);
+      c = ((Character) v[0]).charValue();
+      n = ((Integer) v[2]).intValue();
+
+      boolean bk = getSuccessor(c, n) != c;
+      boolean atEnd = (((c == 's') || (c == 'm') || ((c == 'h') && toTime)) && bk);
+      boolean finishesAtDate = (bk && (c == 'd') && !toTime);
+      boolean containsEnd = (((StringBuilder) v[1]).toString().indexOf('W') != -1);
+
+      if ((!atEnd && !finishesAtDate) || (containsEnd)) {
+        vecRemovelist.add(v);
+      }
+    }
+
+    size = vecRemovelist.size();
+
+    for (int i = 0; i < size; i++) {
+      vec.remove(vecRemovelist.get(i));
+    }
+
+    vecRemovelist.clear();
+    v = vec.get(0); // might throw exception
+
+    StringBuilder format = (StringBuilder) v[1];
+    format.setLength(format.length() - 1);
+
+    return format.toString();
+  }
+
+  private final char getSuccessor(char c, int n) {
+    return ((c == 'y') && (n == 2))
+        ? 'X'
+        : (((c == 'y') && (n < 4))
+            ? 'y'
+            : ((c == 'y')
+                ? 'M'
+                : (((c == 'M') && (n == 2))
+                    ? 'Y'
+                    : (((c == 'M') && (n < 3))
+                        ? 'M'
+                        : ((c == 'M')
+                            ? 'd'
+                            : (((c == 'd') && (n < 2))
+                                ? 'd'
+                                : ((c == 'd')
+                                    ? 'H'
+                                    : (((c == 'H') && (n < 2))
+                                        ? 'H'
+                                        : ((c == 'H')
+                                            ? 'm'
+                                            : (((c == 'm') && (n < 2))
+                                                ? 'm'
+                                                : ((c == 'm')
+                                                    ? 's'
+                                                    : (((c == 's') && (n < 2))
+                                                        ? 's'
+                                                        : 'W'))))))))))));
+  }
+
+  private void setNumericObject(
+      int parameterIndex, Object parameterObj, int targetSqlType, int scale) throws SQLException {
+    Number parameterAsNum;
+
+    if (parameterObj instanceof Boolean) {
+      parameterAsNum =
+          ((Boolean) parameterObj).booleanValue() ? Integer.valueOf(1) : Integer.valueOf(0);
+    } else if (parameterObj instanceof String) {
+      switch (targetSqlType) {
+        case Types.BIT:
+          if ("1".equals(parameterObj) || "0".equals(parameterObj)) {
+            parameterAsNum = Integer.valueOf((String) parameterObj);
+          } else {
+            boolean parameterAsBoolean = "true".equalsIgnoreCase((String) parameterObj);
+
+            parameterAsNum = parameterAsBoolean ? Integer.valueOf(1) : Integer.valueOf(0);
+          }
+
+          break;
+
+        case Types.TINYINT:
+        case Types.SMALLINT:
+        case Types.INTEGER:
+          parameterAsNum = Integer.valueOf((String) parameterObj);
+
+          break;
+
+        case Types.BIGINT:
+          parameterAsNum = Long.valueOf((String) parameterObj);
+
+          break;
+
+        case Types.REAL:
+          parameterAsNum = Float.valueOf((String) parameterObj);
+
+          break;
+
+        case Types.FLOAT:
+        case Types.DOUBLE:
+          parameterAsNum = Double.valueOf((String) parameterObj);
+
+          break;
+
+        case Types.DECIMAL:
+        case Types.NUMERIC:
+        default:
+          parameterAsNum = new java.math.BigDecimal((String) parameterObj);
+      }
+    } else {
+      parameterAsNum = (Number) parameterObj;
+    }
+
+    switch (targetSqlType) {
+      case Types.BIT:
+      case Types.TINYINT:
+      case Types.SMALLINT:
+      case Types.INTEGER:
+        setInt(parameterIndex, parameterAsNum.intValue());
+        break;
+
+      case Types.BIGINT:
+        setLong(parameterIndex, parameterAsNum.longValue());
+        break;
+
+      case Types.REAL:
+        setFloat(parameterIndex, parameterAsNum.floatValue());
+        break;
+
+      case Types.FLOAT:
+        setFloat(parameterIndex, parameterAsNum.floatValue());
+        break;
+      case Types.DOUBLE:
+        setDouble(parameterIndex, parameterAsNum.doubleValue());
+
+        break;
+
+      case Types.DECIMAL:
+      case Types.NUMERIC:
+        if (parameterAsNum instanceof java.math.BigDecimal) {
+          BigDecimal scaledBigDecimal = null;
+
+          try {
+            scaledBigDecimal = ((java.math.BigDecimal) parameterAsNum).setScale(scale);
+          } catch (ArithmeticException ex) {
+            try {
+              scaledBigDecimal =
+                  ((java.math.BigDecimal) parameterAsNum).setScale(scale, BigDecimal.ROUND_HALF_UP);
+            } catch (ArithmeticException arEx) {
+              throw new SQLException(
+                  "Can't set scale of '"
+                      + scale
+                      + "' for DECIMAL argument '"
+                      + parameterAsNum
+                      + "'");
+            }
+          }
+
+          setBigDecimal(parameterIndex, scaledBigDecimal);
+        } else if (parameterAsNum instanceof java.math.BigInteger) {
+          setBigDecimal(
+              parameterIndex,
+              new java.math.BigDecimal((java.math.BigInteger) parameterAsNum, scale));
+        } else {
+          setBigDecimal(parameterIndex, BigDecimal.valueOf(parameterAsNum.doubleValue()));
+        }
+
+        break;
+    }
   }
 
   @Override
   public void setRef(int parameterIndex, Ref x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
@@ -403,7 +854,7 @@ public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedSt
 
   @Override
   public void setShort(int parameterIndex, short x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
@@ -413,12 +864,57 @@ public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedSt
 
   @Override
   public void setTime(int parameterIndex, Time x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    try {
+      long time = x.getTime();
+      String timeprecision = client.getProperties().getTimestampPrecision();
+      switch (timeprecision.toLowerCase()) {
+        case "ms":
+          break;
+        case "us":
+          time = time * 1000;
+          break;
+        case "ns":
+          time = time * 1000000;
+          break;
+        default:
+          break;
+      }
+      setLong(parameterIndex, time);
+    } catch (TException e) {
+      e.printStackTrace();
+    }
   }
 
   @Override
   public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    try {
+      ZonedDateTime zonedDateTime = null;
+      long time = x.getTime();
+      String timeprecision = client.getProperties().getTimestampPrecision();
+      switch (timeprecision.toLowerCase()) {
+        case "ms":
+          break;
+        case "us":
+          time = time * 1000;
+          break;
+        case "ns":
+          time = time * 1000000;
+          break;
+        default:
+          break;
+      }
+      if (cal != null) {
+        zonedDateTime =
+            ZonedDateTime.ofInstant(
+                Instant.ofEpochMilli(time), ZoneId.of(cal.getTimeZone().getID()));
+      } else {
+        zonedDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(time), super.zoneId);
+      }
+      this.parameters.put(
+          parameterIndex, zonedDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
+    } catch (TException e) {
+      e.printStackTrace();
+    }
   }
 
   @Override
@@ -431,17 +927,26 @@ public class IoTDBPreparedStatement extends IoTDBStatement implements PreparedSt
 
   @Override
   public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    ZonedDateTime zonedDateTime = null;
+    if (cal != null) {
+      zonedDateTime =
+          ZonedDateTime.ofInstant(
+              Instant.ofEpochMilli(x.getTime()), ZoneId.of(cal.getTimeZone().getID()));
+    } else {
+      zonedDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(x.getTime()), super.zoneId);
+    }
+    this.parameters.put(
+        parameterIndex, zonedDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
   }
 
   @Override
   public void setURL(int parameterIndex, URL x) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   @Override
   public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
-    throw new SQLException(METHOD_NOT_SUPPORTED_STRING);
+    throw new SQLException(Constant.PARAMETER_SUPPORTED);
   }
 
   private String createCompleteSql(final String sql, Map<Integer, String> parameters)
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBResultMetadata.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBResultMetadata.java
index e4ed8e5..d8e117b 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBResultMetadata.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBResultMetadata.java
@@ -28,13 +28,24 @@ public class IoTDBResultMetadata implements ResultSetMetaData {
   private List<String> columnInfoList;
   private List<String> columnTypeList;
   private boolean ignoreTimestamp;
+  private List<String> sgColumns;
+  private String operationType = "";
+  private boolean nonAlign = false;
 
   /** Constructor of IoTDBResultMetadata. */
   public IoTDBResultMetadata(
-      List<String> columnInfoList, List<String> columnTypeList, boolean ignoreTimestamp) {
+      Boolean nonAlign,
+      List<String> sgColumns,
+      String operationType,
+      List<String> columnInfoList,
+      List<String> columnTypeList,
+      boolean ignoreTimestamp) {
+    this.sgColumns = sgColumns;
+    this.operationType = operationType;
     this.columnInfoList = columnInfoList;
     this.columnTypeList = columnTypeList;
     this.ignoreTimestamp = ignoreTimestamp;
+    this.nonAlign = nonAlign;
   }
 
   @Override
@@ -48,8 +59,65 @@ public class IoTDBResultMetadata implements ResultSetMetaData {
   }
 
   @Override
-  public String getCatalogName(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+  public String getCatalogName(int column) throws SQLException {
+    String system_schmea = "_system_schmea";
+    String system = "_system";
+    String system_user = "_system_user";
+    String system_role = "_system_role";
+    String system_auths = "_system_auths";
+    String system_database = "_system_database";
+    String system_null = "";
+    String columnName = columnInfoList.get(column - 1);
+    List<String> listColumns = columnInfoList;
+    if (column < 1 || column > columnInfoList.size()) {
+      throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    }
+    if (operationType.equals("SHOW")) {
+      if (listColumns.get(0).equals("count")) {
+        return system_database;
+      } else if (listColumns.get(0).equals("storage group")
+          && listColumns.size() > 1
+          && listColumns.get(1).equals("ttl")) {
+        return "";
+      } else if (listColumns.get(0).trim().equals("version") && listColumns.size() == 1) {
+        return system;
+      } else if (listColumns.get(0).equals("storage group")
+          || listColumns.get(0).equals("devices")
+          || listColumns.get(0).equals("child paths")
+          || listColumns.get(0).equals("child nodes")
+          || listColumns.get(0).equals("timeseries")) {
+        return system_schmea;
+      }
+    } else if (operationType.equals("LIST_USER")) {
+      return system_user;
+    } else if (operationType.equals("LIST_ROLE")) {
+      return system_role;
+    } else if (operationType.equals("LIST_USER_PRIVILEGE")) {
+      return system_auths;
+    } else if (operationType.equals("LIST_ROLE_PRIVILEGE")) {
+      return system_auths;
+    } else if (operationType.equals("LIST_USER_ROLES")) {
+      return system_role;
+    } else if (operationType.equals("LIST_ROLE_USERS")) {
+      return system_user;
+    } else if (operationType.equals("QUERY")) {
+      if ((columnName.toLowerCase().equals("time") && columnInfoList.size() != 2)
+          || columnName.toLowerCase().equals("timeseries")
+          || columnName.toLowerCase().equals("device")) {
+        return system_null;
+      } else if (columnInfoList.size() >= 2
+          && columnInfoList.get(0).toLowerCase().equals("time")
+          && columnInfoList.get(1).toLowerCase().equals("device")) {
+        return system_null;
+      }
+    } else if (!operationType.equals("FILL")) {
+      return system_null;
+    }
+    if (nonAlign) {
+      return sgColumns.get(column - 1);
+    } else {
+      return sgColumns.get(column - 2);
+    }
   }
 
   @Override
@@ -114,7 +182,6 @@ public class IoTDBResultMetadata implements ResultSetMetaData {
     if (column == 1 && !ignoreTimestamp) {
       return Types.TIMESTAMP;
     }
-    // BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT,
     String columnType = columnTypeList.get(column - 1);
 
     switch (columnType.toUpperCase()) {
@@ -140,9 +207,8 @@ public class IoTDBResultMetadata implements ResultSetMetaData {
   public String getColumnTypeName(int column) throws SQLException {
     checkColumnIndex(column);
     if (column == 1 && !ignoreTimestamp) {
-      return "TIMESTAMP";
+      return "TIME";
     }
-    // BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT,
     String columnType;
     if (!ignoreTimestamp) {
       columnType = columnTypeList.get(column - 2);
@@ -162,67 +228,128 @@ public class IoTDBResultMetadata implements ResultSetMetaData {
   }
 
   @Override
-  public int getPrecision(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+  public int getPrecision(int column) throws SQLException {
+    checkColumnIndex(column);
+    if (column == 1 && !ignoreTimestamp) {
+      return 13;
+    }
+    String columnType;
+    if (!ignoreTimestamp) {
+      columnType = columnTypeList.get(column - 2);
+    } else {
+      columnType = columnTypeList.get(column - 1);
+    }
+    switch (columnType.toUpperCase()) {
+      case "BOOLEAN":
+        return 1;
+      case "INT32":
+        return 10;
+      case "INT64":
+        return 19;
+      case "FLOAT":
+        return 38;
+      case "DOUBLE":
+        return 308;
+      case "TEXT":
+        return Integer.MAX_VALUE;
+      default:
+        break;
+    }
+    return 0;
   }
 
   @Override
-  public int getScale(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+  public int getScale(int column) throws SQLException {
+    checkColumnIndex(column);
+    if (column == 1 && !ignoreTimestamp) {
+      return 0;
+    }
+    String columnType;
+    if (!ignoreTimestamp) {
+      columnType = columnTypeList.get(column - 2);
+    } else {
+      columnType = columnTypeList.get(column - 1);
+    }
+    switch (columnType.toUpperCase()) {
+      case "BOOLEAN":
+      case "INT32":
+      case "INT64":
+      case "TEXT":
+        return 0;
+      case "FLOAT":
+        return 6;
+      case "DOUBLE":
+        return 15;
+      default:
+        break;
+    }
+    return 0;
   }
 
   @Override
-  public String getSchemaName(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+  public String getSchemaName(int column) throws SQLException {
+    checkColumnIndex(column);
+    return getCatalogName(column);
   }
 
   @Override
-  public String getTableName(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+  public String getTableName(int column) throws SQLException {
+    checkColumnIndex(column);
+    if (column == 1 && !ignoreTimestamp) {
+      return "TIME";
+    }
+    // Temporarily use column names as table names
+    String columName;
+    if (!ignoreTimestamp) {
+      columName = columnInfoList.get(column - 2);
+    } else {
+      columName = columnInfoList.get(column - 1);
+    }
+    return columName;
   }
 
   @Override
   public boolean isAutoIncrement(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return false;
   }
 
   @Override
   public boolean isCaseSensitive(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return true;
   }
 
   @Override
   public boolean isCurrency(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return false;
   }
 
   @Override
   public boolean isDefinitelyWritable(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return false;
   }
 
   @Override
   public int isNullable(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return 1;
   }
 
   @Override
   public boolean isReadOnly(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return true;
   }
 
   @Override
   public boolean isSearchable(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return true;
   }
 
   @Override
   public boolean isSigned(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return true;
   }
 
   @Override
   public boolean isWritable(int arg0) throws SQLException {
-    throw new SQLException(Constant.METHOD_NOT_SUPPORTED);
+    return false;
   }
 }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java
index f9ae38f..36536c8 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBStatement.java
@@ -44,6 +44,7 @@ import java.sql.SQLWarning;
 import java.sql.Statement;
 import java.time.ZoneId;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
@@ -267,6 +268,7 @@ public class IoTDBStatement implements Statement {
     if (execResp.isSetColumns()) {
       queryId = execResp.getQueryId();
       if (execResp.queryDataSet == null) {
+        BitSet aliasColumn = listToBitSet(execResp.getAliasColumns());
         this.resultSet =
             new IoTDBNonAlignJDBCResultSet(
                 this,
@@ -279,7 +281,10 @@ public class IoTDBStatement implements Statement {
                 queryId,
                 sessionId,
                 execResp.nonAlignQueryDataSet,
-                execReq.timeout);
+                execReq.timeout,
+                execResp.operationType,
+                execResp.getSgColumns(),
+                aliasColumn);
       } else {
         this.resultSet =
             new IoTDBJDBCResultSet(
@@ -293,7 +298,8 @@ public class IoTDBStatement implements Statement {
                 queryId,
                 sessionId,
                 execResp.queryDataSet,
-                execReq.timeout);
+                execReq.timeout,
+                true);
       }
       return true;
     }
@@ -318,6 +324,8 @@ public class IoTDBStatement implements Statement {
         throw new SQLException(
             "Fail to reconnect to server when executing batch sqls. please check server status", e);
       }
+    } finally {
+      clearBatch();
     }
   }
 
@@ -397,6 +405,7 @@ public class IoTDBStatement implements Statement {
     }
     execReq.setFetchSize(rows);
     execReq.setTimeout(timeoutInMS);
+    execReq.setJdbcQuery(true);
     TSExecuteStatementResp execResp = client.executeQueryStatement(execReq);
     queryId = execResp.getQueryId();
     try {
@@ -409,7 +418,10 @@ public class IoTDBStatement implements Statement {
     // comsumed
     // result timely, the latter will overlap the former byte buffer, thus problem will occur
     deepCopyResp(execResp);
-
+    BitSet aliasColumn = null;
+    if (execResp.getAliasColumns() != null && execResp.getAliasColumns().size() > 0) {
+      aliasColumn = listToBitSet(execResp.getAliasColumns());
+    }
     if (execResp.queryDataSet == null) {
       this.resultSet =
           new IoTDBNonAlignJDBCResultSet(
@@ -423,7 +435,10 @@ public class IoTDBStatement implements Statement {
               queryId,
               sessionId,
               execResp.nonAlignQueryDataSet,
-              execReq.timeout);
+              execReq.timeout,
+              execResp.operationType,
+              execResp.sgColumns,
+              aliasColumn);
     } else {
       this.resultSet =
           new IoTDBJDBCResultSet(
@@ -437,11 +452,24 @@ public class IoTDBStatement implements Statement {
               queryId,
               sessionId,
               execResp.queryDataSet,
-              execReq.timeout);
+              execReq.timeout,
+              execResp.operationType,
+              execResp.columns,
+              execResp.sgColumns,
+              aliasColumn);
     }
     return resultSet;
   }
 
+  private BitSet listToBitSet(List<Byte> listAlias) {
+    byte[] byteAlias = new byte[listAlias.size()];
+    for (int i = 0; i < listAlias.size(); i++) {
+      byteAlias[i] = listAlias.get(i);
+    }
+    BitSet aliasColumn = BitSet.valueOf(byteAlias);
+    return aliasColumn;
+  }
+
   private void deepCopyResp(TSExecuteStatementResp queryRes) {
     final TSQueryDataSet tsQueryDataSet = queryRes.getQueryDataSet();
     final TSQueryNonAlignDataSet nonAlignDataSet = queryRes.getNonAlignQueryDataSet();
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/ListDataSet.java
similarity index 51%
copy from jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
copy to jdbc/src/main/java/org/apache/iotdb/jdbc/ListDataSet.java
index 84530b7..62fabf8 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/ListDataSet.java
@@ -18,11 +18,36 @@
  */
 package org.apache.iotdb.jdbc;
 
-public class Constant {
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 
-  private Constant() {}
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
 
-  public static final String GLOBAL_DB_NAME = "IoTDB";
+public class ListDataSet extends QueryDataSet {
+  private final List<RowRecord> records = new ArrayList<>();
+  private int index = 0;
 
-  static final String METHOD_NOT_SUPPORTED = "Method not supported";
+  @Override
+  public boolean hasNextWithoutConstraint() {
+    return index < records.size();
+  }
+
+  @Override
+  public RowRecord nextWithoutConstraint() {
+    return records.get(index++);
+  }
+
+  public void putRecord(RowRecord newRecord) {
+    records.add(newRecord);
+  }
+
+  public void sortByTimeDesc() {
+    records.sort((o1, o2) -> Long.compare(o2.getTimestamp(), o1.getTimestamp()));
+  }
+
+  public void sort(Comparator<RowRecord> c) {
+    records.sort(c);
+  }
 }
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/StringUtils.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/StringUtils.java
new file mode 100644
index 0000000..8c7c249
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/StringUtils.java
@@ -0,0 +1,78 @@
+/*
+ * 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.iotdb.jdbc;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+
+public class StringUtils {
+
+  private static byte[] allBytes = new byte[256];
+
+  private static char[] byteToChars = new char[256];
+
+  private static Method toPlainStringMethod;
+
+  static final int WILD_COMPARE_MATCH_NO_WILD = 0;
+
+  static final int WILD_COMPARE_MATCH_WITH_WILD = 1;
+
+  static final int WILD_COMPARE_NO_MATCH = -1;
+
+  static {
+    for (int i = -128; i <= 127; i++) allBytes[i - -128] = (byte) i;
+    String allBytesString = new String(allBytes, 0, 255);
+    int allBytesStringLen = allBytesString.length();
+    int j = 0;
+    for (; j < 255 && j < allBytesStringLen; j++) byteToChars[j] = allBytesString.charAt(j);
+    try {
+      toPlainStringMethod = BigDecimal.class.getMethod("toPlainString", new Class[0]);
+    } catch (NoSuchMethodException nsme) {
+    }
+  }
+
+  public static String consistentToString(BigDecimal decimal) {
+    if (decimal == null) return null;
+    if (toPlainStringMethod != null)
+      try {
+        return (String) toPlainStringMethod.invoke(decimal, null);
+      } catch (InvocationTargetException invokeEx) {
+
+      } catch (IllegalAccessException accessEx) {
+      }
+    return decimal.toString();
+  }
+
+  public static final String fixDecimalExponent(String dString) {
+    int ePos = dString.indexOf("E");
+    if (ePos == -1) ePos = dString.indexOf("e");
+    if (ePos != -1 && dString.length() > ePos + 1) {
+      char maybeMinusChar = dString.charAt(ePos + 1);
+      if (maybeMinusChar != '-' && maybeMinusChar != '+') {
+        StringBuffer buf = new StringBuffer(dString.length() + 1);
+        buf.append(dString.substring(0, ePos + 1));
+        buf.append('+');
+        buf.append(dString.substring(ePos + 1, dString.length()));
+        dString = buf.toString();
+      }
+    }
+    return dString;
+  }
+}
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/WatermarkEncoder.java
similarity index 70%
copy from jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
copy to jdbc/src/main/java/org/apache/iotdb/jdbc/WatermarkEncoder.java
index 84530b7..074c87a 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/Constant.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/WatermarkEncoder.java
@@ -18,11 +18,18 @@
  */
 package org.apache.iotdb.jdbc;
 
-public class Constant {
+import org.apache.iotdb.tsfile.read.common.RowRecord;
 
-  private Constant() {}
+public interface WatermarkEncoder {
+  int encodeInt(int value, long time);
 
-  public static final String GLOBAL_DB_NAME = "IoTDB";
+  long encodeLong(long value, long time);
 
-  static final String METHOD_NOT_SUPPORTED = "Method not supported";
+  float encodeFloat(float value, long time);
+
+  double encodeDouble(double value, long time);
+
+  boolean needEncode(long timestamp);
+
+  RowRecord encodeRecord(RowRecord record);
 }
diff --git a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBConnectionTest.java b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBConnectionTest.java
index 25ea6e6..7a04484 100644
--- a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBConnectionTest.java
+++ b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBConnectionTest.java
@@ -88,8 +88,9 @@ public class IoTDBConnectionTest {
           }
         };
     final String timestampPrecision = "ms";
+    new ServerProperties();
     when(client.getProperties())
-        .thenReturn(new ServerProperties(version, supportedAggregationTime, timestampPrecision));
+        .thenReturn(new ServerProperties(version, supportedAggregationTime, timestampPrecision, 1));
     connection.setClient(client);
     assertEquals(connection.getServerProperties().getVersion(), version);
     for (int i = 0; i < supportedAggregationTime.size(); i++) {
diff --git a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
new file mode 100644
index 0000000..312ba17
--- /dev/null
+++ b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.iotdb.jdbc;
+
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+import org.apache.iotdb.service.rpc.thrift.ServerProperties;
+import org.apache.iotdb.service.rpc.thrift.TSExecuteBatchStatementReq;
+import org.apache.iotdb.service.rpc.thrift.TSExecuteStatementReq;
+import org.apache.iotdb.service.rpc.thrift.TSExecuteStatementResp;
+import org.apache.iotdb.service.rpc.thrift.TSIService;
+import org.apache.iotdb.service.rpc.thrift.TSStatus;
+
+import org.apache.thrift.TException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+public class IoTDBDatabaseMetadataTest {
+  @Mock TSExecuteStatementResp execStatementResp;
+  private long queryId;
+  private long sessionId;
+  private TSStatus resp;
+  @Mock private IoTDBConnection connection;
+  @Mock private TSIService.Iface client;
+  @Mock private Statement statement;
+  @Mock private DatabaseMetaData databaseMetaData;
+  @Mock private TSStatus successStatus = new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
+  @Mock private ServerProperties properties;
+
+  private ZoneId zoneID = ZoneId.systemDefault();
+
+  @Before
+  public void before() throws Exception {
+    MockitoAnnotations.initMocks(this);
+
+    when(connection.createStatement())
+        .thenReturn(new IoTDBStatement(connection, client, sessionId, zoneID, 0, 1L));
+    databaseMetaData = new IoTDBDatabaseMetadata(connection, client, sessionId);
+    when(client.executeStatement(any(TSExecuteStatementReq.class))).thenReturn(execStatementResp);
+    when(client.getProperties()).thenReturn(properties);
+    when(execStatementResp.getStatus()).thenReturn(successStatus);
+    when(execStatementResp.getQueryId()).thenReturn(queryId);
+  }
+
+  @Test
+  public void testGetAttributes() throws SQLException {
+    ResultSet resultSet = databaseMetaData.getExportedKeys(null, null, null);
+    Assert.assertEquals("Time", resultSet.getMetaData().getColumnName(1));
+    Assert.assertEquals("PKTABLE_CAT", resultSet.getMetaData().getColumnName(2));
+  }
+
+  @Test
+  public void testGetBestRowIdentifier() throws SQLException {
+    ResultSet resultSet = databaseMetaData.getBestRowIdentifier(null, null, null, 0, true);
+    Assert.assertEquals("Time", resultSet.getMetaData().getColumnName(1));
+    Assert.assertEquals("SCOPE", resultSet.getMetaData().getColumnName(2));
+    Assert.assertEquals("COLUMN_NAME", resultSet.getMetaData().getColumnName(3));
+    Assert.assertEquals("DATA_TYPE", resultSet.getMetaData().getColumnName(4));
+    Assert.assertEquals("TYPE_NAME", resultSet.getMetaData().getColumnName(5));
+    Assert.assertEquals("COLUMN_SIZE", resultSet.getMetaData().getColumnName(6));
+    Assert.assertEquals("BUFFER_LENGTH", resultSet.getMetaData().getColumnName(7));
+    Assert.assertEquals("DECIMAL_DIGITS", resultSet.getMetaData().getColumnName(8));
+    Assert.assertEquals("PSEUDO_COLUMN", resultSet.getMetaData().getColumnName(9));
+  }
+
+  @Test
+  public void testGetCatalogs() throws SQLException, TException {
+    Statement statement = connection.createStatement();
+    resp = new TSStatus();
+    resp =
+        RpcUtils.getStatus(
+            Collections.singletonList(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS)));
+    when(client.executeBatchStatement(any(TSExecuteBatchStatementReq.class))).thenReturn(resp);
+    List<TSStatus> resExpected =
+        new ArrayList<TSStatus>() {
+          {
+            add(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS));
+            add(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS));
+          }
+        };
+    resp.setSubStatus(resExpected);
+
+    statement.clearBatch();
+    statement.addBatch("SET STORAGE GROUP TO root.ln.wf01.wt01");
+    statement.addBatch(
+        "CREATE TIMESERIES root.ln.wf01.wt01.status WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
+    int[] result = statement.executeBatch();
+    assertEquals(resp.getSubStatus().size(), result.length);
+    for (int i = 0; i < resp.getSubStatus().size(); i++) {
+      assertEquals(resExpected.get(i).code, result[i]);
+    }
+    List<String> dataTypeList = new ArrayList<String>();
+    dataTypeList.add("TEXT");
+    List<String> columnsList = new ArrayList<String>();
+    columnsList.add("storage group");
+    Map<String, Integer> columnNameIndexMap = new HashMap<String, Integer>();
+    columnNameIndexMap.put("storage group", 0);
+    when(client.executeQueryStatement(any(TSExecuteStatementReq.class)))
+        .thenReturn(execStatementResp);
+    when(execStatementResp.getStatus()).thenReturn(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS));
+    when(execStatementResp.getQueryId()).thenReturn(queryId);
+    when(execStatementResp.getDataTypeList()).thenReturn(dataTypeList);
+    when(execStatementResp.getColumns()).thenReturn(columnsList);
+    execStatementResp.columnNameIndexMap = columnNameIndexMap;
+    when(client.getProperties().getWatermarkSecretKey()).thenReturn("IoTDB*2019@Beijing");
+    when(client.getProperties().getWatermarkBitString()).thenReturn("100101110100");
+    when(client.getProperties().getWatermarkParamMarkRate()).thenReturn(5);
+    when(client.getProperties().getWatermarkParamMaxRightBit()).thenReturn(5);
+    ResultSet rs = databaseMetaData.getCatalogs();
+    assertEquals(2, rs.findColumn("TYPE_CAT"));
+  }
+
+  @Test
+  public void testGetImportedKeys() throws SQLException {
+    ResultSet resultSet = databaseMetaData.getImportedKeys(null, null, null);
+    Assert.assertEquals("Time", resultSet.getMetaData().getColumnName(1));
+    Assert.assertEquals("PKTABLE_CAT", resultSet.getMetaData().getColumnName(2));
+    Assert.assertEquals("PKTABLE_SCHEM", resultSet.getMetaData().getColumnName(3));
+  }
+
+  @Test
+  public void testGetIndexInfo() throws SQLException {
+    ResultSet resultSet = databaseMetaData.getIndexInfo(null, null, null, false, false);
+    Assert.assertEquals("Time", resultSet.getMetaData().getColumnName(1));
+    Assert.assertEquals("TABLE_CAT", resultSet.getMetaData().getColumnName(2));
+    Assert.assertEquals("TABLE_SCHEM", resultSet.getMetaData().getColumnName(3));
+  }
+}
diff --git a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java
index ee57d35..c09680c 100644
--- a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java
+++ b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBPreparedStatementTest.java
@@ -30,6 +30,7 @@ import org.mockito.MockitoAnnotations;
 
 import java.sql.SQLException;
 import java.sql.Timestamp;
+import java.sql.Types;
 import java.time.ZoneId;
 
 import static org.junit.Assert.assertEquals;
@@ -302,7 +303,7 @@ public class IoTDBPreparedStatementTest {
   @SuppressWarnings("resource")
   @Test
   public void testInsertStatement1() throws Exception {
-    String sql = "INSERT INTO root.ln.wf01.wt01(timestamp,a,b,c,d,e,f) VALUES(?,?,?,?,?,?,?)";
+    String sql = "INSERT INTO root.ln.wf01.wt01(time,a,b,c,d,e,f) VALUES(?,?,?,?,?,?,?)";
 
     IoTDBPreparedStatement ps =
         new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
@@ -319,14 +320,14 @@ public class IoTDBPreparedStatementTest {
         ArgumentCaptor.forClass(TSExecuteStatementReq.class);
     verify(client).executeStatement(argument.capture());
     assertEquals(
-        "INSERT INTO root.ln.wf01.wt01(timestamp,a,b,c,d,e,f) VALUES(12324,false,123,123234345,123.423,-1323.0,'abc')",
+        "INSERT INTO root.ln.wf01.wt01(time,a,b,c,d,e,f) VALUES(12324,false,123,123234345,123.423,-1323.0,'abc')",
         argument.getValue().getStatement());
   }
 
   @SuppressWarnings("resource")
   @Test
   public void testInsertStatement2() throws Exception {
-    String sql = "INSERT INTO root.ln.wf01.wt01(timestamp,a,b,c,d,e,f) VALUES(?,?,?,?,?,?,?)";
+    String sql = "INSERT INTO root.ln.wf01.wt01(time,a,b,c,d,e,f) VALUES(?,?,?,?,?,?,?)";
 
     IoTDBPreparedStatement ps =
         new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
@@ -343,7 +344,30 @@ public class IoTDBPreparedStatementTest {
         ArgumentCaptor.forClass(TSExecuteStatementReq.class);
     verify(client).executeStatement(argument.capture());
     assertEquals(
-        "INSERT INTO root.ln.wf01.wt01(timestamp,a,b,c,d,e,f) VALUES(2017-11-01T00:13:00,false,123,123234345,123.423,-1323.0,\"abc\")",
+        "INSERT INTO root.ln.wf01.wt01(time,a,b,c,d,e,f) VALUES(2017-11-01T00:13:00,false,123,123234345,123.423,-1323.0,\"abc\")",
+        argument.getValue().getStatement());
+  }
+
+  @Test
+  public void testInsertStatement3() throws Exception {
+    String sql = "INSERT INTO root.ln.wf01.wt02(time,a,b,c,d,e,f) VALUES(?,?,?,?,?,?,?)";
+
+    IoTDBPreparedStatement ps =
+        new IoTDBPreparedStatement(connection, client, sessionId, sql, zoneId);
+    ps.setObject(1, "2020-01-01 10:10:10", Types.TIMESTAMP, -1);
+    ps.setObject(2, false, Types.BOOLEAN, -1);
+    ps.setObject(3, 123, Types.INTEGER, -1);
+    ps.setObject(4, 123234345, Types.BIGINT);
+    ps.setObject(5, 123.423f, Types.FLOAT);
+    ps.setObject(6, -1323.0, Types.DOUBLE);
+    ps.setObject(7, "\"abc\"", Types.VARCHAR);
+    ps.execute();
+
+    ArgumentCaptor<TSExecuteStatementReq> argument =
+        ArgumentCaptor.forClass(TSExecuteStatementReq.class);
+    verify(client).executeStatement(argument.capture());
+    assertEquals(
+        "INSERT INTO root.ln.wf01.wt02(time,a,b,c,d,e,f) VALUES(2020-01-01T10:10:10,false,123,123234345,123.423,-1323.0,\"abc\")",
         argument.getValue().getStatement());
   }
 }
diff --git a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBResultMetadataTest.java b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBResultMetadataTest.java
index a10bd05..fde7c83 100644
--- a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBResultMetadataTest.java
+++ b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBResultMetadataTest.java
@@ -45,7 +45,7 @@ public class IoTDBResultMetadataTest {
 
   @Test
   public void testGetColumnCount() {
-    metadata = new IoTDBResultMetadata(null, null, false);
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", null, null, false);
     boolean flag = false;
     try {
       metadata.getColumnCount();
@@ -56,7 +56,8 @@ public class IoTDBResultMetadataTest {
 
     flag = false;
     try {
-      metadata = new IoTDBResultMetadata(Collections.emptyList(), null, false);
+      metadata =
+          new IoTDBResultMetadata(false, null, "QUERY", Collections.emptyList(), null, false);
       metadata.getColumnCount();
     } catch (Exception e) {
       flag = true;
@@ -65,13 +66,13 @@ public class IoTDBResultMetadataTest {
 
     List<String> columnInfoList = new ArrayList<>();
     columnInfoList.add("root.a.b.c");
-    metadata = new IoTDBResultMetadata(columnInfoList, null, false);
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", columnInfoList, null, false);
     assertEquals(1, metadata.getColumnCount());
   }
 
   @Test
   public void testGetColumnName() throws SQLException {
-    metadata = new IoTDBResultMetadata(null, null, false);
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", null, null, false);
     boolean flag = false;
     try {
       metadata.getColumnName(1);
@@ -81,7 +82,7 @@ public class IoTDBResultMetadataTest {
     assertTrue(flag);
 
     List<String> columnInfoList = new ArrayList<>();
-    metadata = new IoTDBResultMetadata(columnInfoList, null, false);
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", columnInfoList, null, false);
     flag = false;
     try {
       metadata.getColumnName(1);
@@ -91,7 +92,7 @@ public class IoTDBResultMetadataTest {
     assertTrue(flag);
 
     String[] colums = {"root.a.b.c1", "root.a.b.c2", "root.a.b.c3"};
-    metadata = new IoTDBResultMetadata(Arrays.asList(colums), null, false);
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", Arrays.asList(colums), null, false);
     flag = false;
     try {
       metadata.getColumnName(colums.length + 1);
@@ -115,7 +116,7 @@ public class IoTDBResultMetadataTest {
 
   @Test
   public void testGetColumnType() throws SQLException {
-    metadata = new IoTDBResultMetadata(null, null, false);
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", null, null, false);
     boolean flag = false;
     try {
       metadata.getColumnType(1);
@@ -125,7 +126,7 @@ public class IoTDBResultMetadataTest {
     assertTrue(flag);
 
     List<String> columnInfoList = new ArrayList<>();
-    metadata = new IoTDBResultMetadata(columnInfoList, null, false);
+    metadata = new IoTDBResultMetadata(false, null, "QUERY", columnInfoList, null, false);
     flag = false;
     try {
       metadata.getColumnType(1);
@@ -147,7 +148,9 @@ public class IoTDBResultMetadataTest {
     int[] types = {
       Types.BOOLEAN, Types.INTEGER, Types.BIGINT, Types.FLOAT, Types.DOUBLE, Types.VARCHAR
     };
-    metadata = new IoTDBResultMetadata(Arrays.asList(columns), Arrays.asList(typesString), false);
+    metadata =
+        new IoTDBResultMetadata(
+            false, null, "QUERY", Arrays.asList(columns), Arrays.asList(typesString), false);
     flag = false;
     try {
       metadata.getColumnType(columns.length + 1);
diff --git a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
index 59cff3e..59ec25f 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
@@ -132,6 +132,7 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.common.Path;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 
+import com.google.common.primitives.Bytes;
 import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.apache.thrift.TException;
 import org.slf4j.Logger;
@@ -143,6 +144,7 @@ import java.sql.SQLException;
 import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -600,7 +602,8 @@ public class TSServiceImpl implements TSIService.Iface {
               req.fetchSize,
               req.timeout,
               req.getSessionId(),
-              req.isEnableRedirectQuery())
+              req.isEnableRedirectQuery(),
+              req.isJdbcQuery())
           : executeUpdateStatement(
               statement,
               req.statementId,
@@ -636,7 +639,8 @@ public class TSServiceImpl implements TSIService.Iface {
               req.fetchSize,
               req.timeout,
               req.getSessionId(),
-              req.isEnableRedirectQuery())
+              req.isEnableRedirectQuery(),
+              req.isJdbcQuery())
           : RpcUtils.getTSExecuteStatementResp(
               TSStatusCode.EXECUTE_STATEMENT_ERROR, "Statement is not a query statement.");
     } catch (InterruptedException e) {
@@ -667,7 +671,8 @@ public class TSServiceImpl implements TSIService.Iface {
               req.fetchSize,
               config.getQueryTimeoutThreshold(),
               req.sessionId,
-              req.isEnableRedirectQuery())
+              req.isEnableRedirectQuery(),
+              req.isJdbcQuery())
           : RpcUtils.getTSExecuteStatementResp(
               TSStatusCode.EXECUTE_STATEMENT_ERROR, "Statement is not a query statement.");
     } catch (InterruptedException e) {
@@ -698,7 +703,8 @@ public class TSServiceImpl implements TSIService.Iface {
               req.fetchSize,
               config.getQueryTimeoutThreshold(),
               req.sessionId,
-              req.isEnableRedirectQuery())
+              req.isEnableRedirectQuery(),
+              req.isJdbcQuery())
           : RpcUtils.getTSExecuteStatementResp(
               TSStatusCode.EXECUTE_STATEMENT_ERROR, "Statement is not a query statement.");
     } catch (InterruptedException e) {
@@ -724,7 +730,8 @@ public class TSServiceImpl implements TSIService.Iface {
       int fetchSize,
       long timeout,
       long sessionId,
-      boolean enableRedirect)
+      boolean enableRedirect,
+      boolean isJdbcQuery)
       throws QueryProcessException, SQLException, StorageEngineException,
           QueryFilterOptimizationException, MetadataException, IOException, InterruptedException,
           TException, AuthException {
@@ -752,7 +759,7 @@ public class TSServiceImpl implements TSIService.Iface {
       TSExecuteStatementResp resp = null;
       // execute it before createDataSet since it may change the content of query plan
       if (plan instanceof QueryPlan && !(plan instanceof UDFPlan)) {
-        resp = getQueryColumnHeaders(plan, username);
+        resp = getQueryColumnHeaders(plan, username, isJdbcQuery);
       }
       if (plan instanceof QueryPlan) {
         ((QueryPlan) plan).setEnableRedirect(enableRedirect);
@@ -776,7 +783,7 @@ public class TSServiceImpl implements TSIService.Iface {
       if (plan instanceof ShowPlan || plan instanceof AuthorPlan) {
         resp = getListDataSetHeaders(newDataSet);
       } else if (plan instanceof UDFPlan) {
-        resp = getQueryColumnHeaders(plan, username);
+        resp = getQueryColumnHeaders(plan, username, isJdbcQuery);
       }
 
       resp.setOperationType(plan.getOperatorType().toString());
@@ -850,7 +857,8 @@ public class TSServiceImpl implements TSIService.Iface {
   }
 
   /** get ResultSet schema */
-  private TSExecuteStatementResp getQueryColumnHeaders(PhysicalPlan physicalPlan, String username)
+  private TSExecuteStatementResp getQueryColumnHeaders(
+      PhysicalPlan physicalPlan, String username, boolean isJdbcQuery)
       throws AuthException, TException, QueryProcessException, MetadataException {
 
     List<String> respColumns = new ArrayList<>();
@@ -882,8 +890,14 @@ public class TSServiceImpl implements TSIService.Iface {
         columnsTypes.add(entry.getValue().getResultDataType().toString());
       }
     } else {
-      getWideQueryHeaders(plan, respColumns, columnsTypes);
+      List<String> respSgColumns = new ArrayList<>();
+      BitSet aliasMap = new BitSet();
+      getWideQueryHeaders(plan, respColumns, columnsTypes, respSgColumns, isJdbcQuery, aliasMap);
       resp.setColumnNameIndexMap(plan.getPathToIndex());
+      resp.setSgColumns(respSgColumns);
+      List<Byte> byteList = new ArrayList<>();
+      byteList.addAll(Bytes.asList(aliasMap.toByteArray()));
+      resp.setAliasColumns(byteList);
     }
     resp.setColumns(respColumns);
     resp.setDataTypeList(columnsTypes);
@@ -892,7 +906,12 @@ public class TSServiceImpl implements TSIService.Iface {
 
   // wide means not align by device
   private void getWideQueryHeaders(
-      QueryPlan plan, List<String> respColumns, List<String> columnTypes)
+      QueryPlan plan,
+      List<String> respColumns,
+      List<String> columnTypes,
+      List<String> respSgColumns,
+      Boolean isJdbcQuery,
+      BitSet aliasList)
       throws TException, MetadataException {
     List<ResultColumn> resultColumns = plan.getResultColumns();
     List<PartialPath> paths = plan.getPaths();
@@ -901,7 +920,20 @@ public class TSServiceImpl implements TSIService.Iface {
       case QUERY:
       case FILL:
         for (int i = 0; i < resultColumns.size(); ++i) {
-          respColumns.add(resultColumns.get(i).getResultColumnName());
+          if (isJdbcQuery) {
+            String sgName =
+                IoTDB.metaManager.getStorageGroupPath(plan.getPaths().get(i)).getFullPath();
+            respSgColumns.add(sgName);
+            if (resultColumns.get(i).getAlias() == null) {
+              respColumns.add(
+                  resultColumns.get(i).getResultColumnName().substring(sgName.length() + 1));
+            } else {
+              aliasList.set(i);
+              respColumns.add(resultColumns.get(i).getResultColumnName());
+            }
+          } else {
+            respColumns.add(resultColumns.get(i).getResultColumnName());
+          }
           seriesTypes.add(getSeriesTypeByPath(paths.get(i)));
         }
         break;
@@ -1295,6 +1327,19 @@ public class TSServiceImpl implements TSIService.Iface {
     properties.getSupportedTimeAggregationOperations().add(IoTDBConstant.MIN_TIME);
     properties.setTimestampPrecision(
         IoTDBDescriptor.getInstance().getConfig().getTimestampPrecision());
+    properties.setMaxConcurrentClientNum(
+        IoTDBDescriptor.getInstance().getConfig().getRpcMaxConcurrentClientNum());
+    properties.setWatermarkSecretKey(
+        IoTDBDescriptor.getInstance().getConfig().getWatermarkSecretKey());
+    properties.setWatermarkBitString(
+        IoTDBDescriptor.getInstance().getConfig().getWatermarkBitString());
+    properties.setWatermarkParamMarkRate(
+        IoTDBDescriptor.getInstance().getConfig().getWatermarkParamMarkRate());
+    properties.setWatermarkParamMaxRightBit(
+        IoTDBDescriptor.getInstance().getConfig().getWatermarkParamMaxRightBit());
+    properties.setIsReadOnly(IoTDBDescriptor.getInstance().getConfig().isReadOnly());
+    properties.setThriftMaxFrameSize(
+        IoTDBDescriptor.getInstance().getConfig().getThriftMaxFrameSize());
     return properties;
   }
 
diff --git a/service-rpc/src/main/java/org/apache/iotdb/rpc/IoTDBJDBCDataSet.java b/service-rpc/src/main/java/org/apache/iotdb/rpc/IoTDBJDBCDataSet.java
new file mode 100644
index 0000000..3b11ccd
--- /dev/null
+++ b/service-rpc/src/main/java/org/apache/iotdb/rpc/IoTDBJDBCDataSet.java
@@ -0,0 +1,618 @@
+/*
+ * 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.iotdb.rpc;
+
+import org.apache.iotdb.service.rpc.thrift.TSCloseOperationReq;
+import org.apache.iotdb.service.rpc.thrift.TSFetchResultsReq;
+import org.apache.iotdb.service.rpc.thrift.TSFetchResultsResp;
+import org.apache.iotdb.service.rpc.thrift.TSIService;
+import org.apache.iotdb.service.rpc.thrift.TSQueryDataSet;
+import org.apache.iotdb.service.rpc.thrift.TSStatus;
+import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.utils.BytesUtils;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
+
+import org.apache.thrift.TException;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+public class IoTDBJDBCDataSet {
+
+  public static final String TIMESTAMP_STR = "Time";
+  public static final String VALUE_IS_NULL = "The value got by %s (column name) is NULL.";
+  public static final int START_INDEX = 2;
+  public String sql;
+  public boolean isClosed = false;
+  public TSIService.Iface client;
+  public List<String> columnNameList; // no deduplication
+  public List<String> columnTypeList; // no deduplication
+  public Map<String, Integer>
+      columnOrdinalMap; // used because the server returns deduplicated columns
+  public List<TSDataType> columnTypeDeduplicatedList; // deduplicated from columnTypeList
+  public int fetchSize;
+  public final long timeout;
+  public boolean emptyResultSet = false;
+  public boolean hasCachedRecord = false;
+  public boolean lastReadWasNull;
+
+  public byte[][] values; // used to cache the current row record value
+  // column size
+  public int columnSize;
+
+  public long sessionId;
+  public long queryId;
+  public long statementId;
+  public boolean ignoreTimeStamp;
+
+  public int rowsIndex = 0; // used to record the row index in current TSQueryDataSet
+
+  public TSQueryDataSet tsQueryDataSet = null;
+  public byte[] time; // used to cache the current time value
+  public byte[] currentBitmap; // used to cache the current bitmap for every column
+  public static final int FLAG =
+      0x80; // used to do `and` operation with bitmap to judge whether the value is null
+
+  @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
+  public IoTDBJDBCDataSet(
+      String sql,
+      List<String> columnNameList,
+      List<String> columnTypeList,
+      Map<String, Integer> columnNameIndex,
+      boolean ignoreTimeStamp,
+      long queryId,
+      long statementId,
+      TSIService.Iface client,
+      long sessionId,
+      TSQueryDataSet queryDataSet,
+      int fetchSize,
+      long timeout) {
+    this.sessionId = sessionId;
+    this.statementId = statementId;
+    this.ignoreTimeStamp = ignoreTimeStamp;
+    this.sql = sql;
+    this.queryId = queryId;
+    this.client = client;
+    this.fetchSize = fetchSize;
+    this.timeout = timeout;
+    columnSize = columnNameList.size();
+
+    this.columnNameList = new ArrayList<>();
+    this.columnTypeList = new ArrayList<>();
+    if (!ignoreTimeStamp) {
+      this.columnNameList.add(TIMESTAMP_STR);
+      this.columnTypeList.add(String.valueOf(TSDataType.INT64));
+    }
+    // deduplicate and map
+    this.columnOrdinalMap = new HashMap<>();
+    if (!ignoreTimeStamp) {
+      this.columnOrdinalMap.put(TIMESTAMP_STR, 1);
+    }
+
+    // deduplicate and map
+    if (columnNameIndex != null) {
+      this.columnTypeDeduplicatedList = new ArrayList<>(columnNameIndex.size());
+      for (int i = 0; i < columnNameIndex.size(); i++) {
+        columnTypeDeduplicatedList.add(null);
+      }
+      for (int i = 0; i < columnNameList.size(); i++) {
+        String name = columnNameList.get(i);
+        this.columnNameList.add(name);
+        this.columnTypeList.add(columnTypeList.get(i));
+        if (!columnOrdinalMap.containsKey(name)) {
+          int index = columnNameIndex.get(name);
+          columnOrdinalMap.put(name, index + START_INDEX);
+          columnTypeDeduplicatedList.set(index, TSDataType.valueOf(columnTypeList.get(i)));
+        }
+      }
+    } else {
+      this.columnTypeDeduplicatedList = new ArrayList<>();
+      int index = START_INDEX;
+      for (int i = 0; i < columnNameList.size(); i++) {
+        String name = columnNameList.get(i);
+        this.columnNameList.add(name);
+        this.columnTypeList.add(columnTypeList.get(i));
+        if (!columnOrdinalMap.containsKey(name)) {
+          columnOrdinalMap.put(name, index++);
+          columnTypeDeduplicatedList.add(TSDataType.valueOf(columnTypeList.get(i)));
+        }
+      }
+    }
+
+    time = new byte[Long.BYTES];
+    currentBitmap = new byte[columnTypeDeduplicatedList.size()];
+    values = new byte[columnTypeDeduplicatedList.size()][];
+    for (int i = 0; i < values.length; i++) {
+      TSDataType dataType = columnTypeDeduplicatedList.get(i);
+      switch (dataType) {
+        case BOOLEAN:
+          values[i] = new byte[1];
+          break;
+        case INT32:
+          values[i] = new byte[Integer.BYTES];
+          break;
+        case INT64:
+          values[i] = new byte[Long.BYTES];
+          break;
+        case FLOAT:
+          values[i] = new byte[Float.BYTES];
+          break;
+        case DOUBLE:
+          values[i] = new byte[Double.BYTES];
+          break;
+        case TEXT:
+          values[i] = null;
+          break;
+        default:
+          throw new UnSupportedDataTypeException(
+              String.format("Data type %s is not supported.", columnTypeDeduplicatedList.get(i)));
+      }
+    }
+    this.tsQueryDataSet = queryDataSet;
+    this.emptyResultSet = (queryDataSet == null || !queryDataSet.time.hasRemaining());
+  }
+
+  public IoTDBJDBCDataSet(
+      String sql,
+      List<String> columnNameList,
+      List<String> columnTypeList,
+      Map<String, Integer> columnNameIndex,
+      boolean ignoreTimeStamp,
+      long queryId,
+      long statementId,
+      TSIService.Iface client,
+      long sessionId,
+      TSQueryDataSet queryDataSet,
+      int fetchSize,
+      long timeout,
+      List<String> sgList,
+      BitSet aliasColumnMap) {
+    this.sessionId = sessionId;
+    this.statementId = statementId;
+    this.ignoreTimeStamp = ignoreTimeStamp;
+    this.sql = sql;
+    this.queryId = queryId;
+    this.client = client;
+    this.fetchSize = fetchSize;
+    this.timeout = timeout;
+    columnSize = columnNameList.size();
+
+    this.columnNameList = new ArrayList<>();
+    this.columnTypeList = new ArrayList<>();
+    if (!ignoreTimeStamp) {
+      this.columnNameList.add(TIMESTAMP_STR);
+      this.columnTypeList.add(String.valueOf(TSDataType.INT64));
+    }
+    // deduplicate and map
+    this.columnOrdinalMap = new HashMap<>();
+    if (!ignoreTimeStamp) {
+      this.columnOrdinalMap.put(TIMESTAMP_STR, 1);
+    }
+
+    // deduplicate and map
+    if (columnNameIndex != null) {
+      this.columnTypeDeduplicatedList = new ArrayList<>(columnNameIndex.size());
+      for (int i = 0; i < columnNameIndex.size(); i++) {
+        columnTypeDeduplicatedList.add(null);
+      }
+      for (int i = 0; i < columnNameList.size(); i++) {
+        String name = "";
+        if (sgList != null
+            && sgList.size() > 0
+            && (aliasColumnMap == null || !aliasColumnMap.get(i))) {
+          name = sgList.get(i) + "." + columnNameList.get(i);
+        } else {
+          name = columnNameList.get(i);
+        }
+
+        this.columnNameList.add(name);
+        this.columnTypeList.add(columnTypeList.get(i));
+        if (!columnOrdinalMap.containsKey(name)) {
+          int index = columnNameIndex.get(name);
+          columnOrdinalMap.put(name, index + START_INDEX);
+          columnTypeDeduplicatedList.set(index, TSDataType.valueOf(columnTypeList.get(i)));
+        }
+      }
+    } else {
+      this.columnTypeDeduplicatedList = new ArrayList<>();
+      int index = START_INDEX;
+      for (int i = 0; i < columnNameList.size(); i++) {
+        String name = columnNameList.get(i);
+        this.columnNameList.add(name);
+        this.columnTypeList.add(columnTypeList.get(i));
+        if (!columnOrdinalMap.containsKey(name)) {
+          columnOrdinalMap.put(name, index++);
+          columnTypeDeduplicatedList.add(TSDataType.valueOf(columnTypeList.get(i)));
+        }
+      }
+    }
+
+    time = new byte[Long.BYTES];
+    currentBitmap = new byte[columnTypeDeduplicatedList.size()];
+    values = new byte[columnTypeDeduplicatedList.size()][];
+    for (int i = 0; i < values.length; i++) {
+      TSDataType dataType = columnTypeDeduplicatedList.get(i);
+      switch (dataType) {
+        case BOOLEAN:
+          values[i] = new byte[1];
+          break;
+        case INT32:
+          values[i] = new byte[Integer.BYTES];
+          break;
+        case INT64:
+          values[i] = new byte[Long.BYTES];
+          break;
+        case FLOAT:
+          values[i] = new byte[Float.BYTES];
+          break;
+        case DOUBLE:
+          values[i] = new byte[Double.BYTES];
+          break;
+        case TEXT:
+          values[i] = null;
+          break;
+        default:
+          throw new UnSupportedDataTypeException(
+              String.format("Data type %s is not supported.", columnTypeDeduplicatedList.get(i)));
+      }
+    }
+    this.tsQueryDataSet = queryDataSet;
+    this.emptyResultSet = (queryDataSet == null || !queryDataSet.time.hasRemaining());
+  }
+
+  public void close() throws StatementExecutionException, TException {
+    if (isClosed) {
+      return;
+    }
+    if (client != null) {
+      try {
+        TSCloseOperationReq closeReq = new TSCloseOperationReq(sessionId);
+        closeReq.setStatementId(statementId);
+        closeReq.setQueryId(queryId);
+        TSStatus closeResp = client.closeOperation(closeReq);
+        RpcUtils.verifySuccess(closeResp);
+      } catch (StatementExecutionException e) {
+        throw new StatementExecutionException(
+            "Error occurs for close operation in server side because ", e);
+      } catch (TException e) {
+        throw new TException("Error occurs when connecting to server for close operation ", e);
+      }
+    }
+    client = null;
+    isClosed = true;
+  }
+
+  public boolean next() throws StatementExecutionException, IoTDBConnectionException {
+    if (hasCachedResults()) {
+      constructOneRow();
+      return true;
+    }
+    if (emptyResultSet) {
+      try {
+        close();
+        return false;
+      } catch (TException e) {
+        throw new IoTDBConnectionException(
+            "Cannot close dataset, because of network connection: {} ", e);
+      }
+    }
+    if (fetchResults() && hasCachedResults()) {
+      constructOneRow();
+      return true;
+    } else {
+      try {
+        close();
+        return false;
+      } catch (TException e) {
+        throw new IoTDBConnectionException(
+            "Cannot close dataset, because of network connection: {} ", e);
+      }
+    }
+  }
+
+  public boolean fetchResults() throws StatementExecutionException, IoTDBConnectionException {
+    rowsIndex = 0;
+    TSFetchResultsReq req = new TSFetchResultsReq(sessionId, sql, fetchSize, queryId, true);
+    req.setTimeout(timeout);
+    try {
+      TSFetchResultsResp resp = client.fetchResults(req);
+
+      RpcUtils.verifySuccess(resp.getStatus());
+      if (!resp.hasResultSet) {
+        emptyResultSet = true;
+        close();
+      } else {
+        tsQueryDataSet = resp.getQueryDataSet();
+      }
+      return resp.hasResultSet;
+    } catch (TException e) {
+      throw new IoTDBConnectionException(
+          "Cannot fetch result from server, because of network connection: {} ", e);
+    }
+  }
+
+  public boolean hasCachedResults() {
+    return (tsQueryDataSet != null && tsQueryDataSet.time.hasRemaining());
+  }
+
+  public void constructOneRow() {
+    tsQueryDataSet.time.get(time);
+    for (int i = 0; i < tsQueryDataSet.bitmapList.size(); i++) {
+      ByteBuffer bitmapBuffer = tsQueryDataSet.bitmapList.get(i);
+      // another new 8 row, should move the bitmap buffer position to next byte
+      if (rowsIndex % 8 == 0) {
+        currentBitmap[i] = bitmapBuffer.get();
+      }
+      if (!isNull(i, rowsIndex)) {
+        ByteBuffer valueBuffer = tsQueryDataSet.valueList.get(i);
+        TSDataType dataType = columnTypeDeduplicatedList.get(i);
+        switch (dataType) {
+          case BOOLEAN:
+          case INT32:
+          case INT64:
+          case FLOAT:
+          case DOUBLE:
+            valueBuffer.get(values[i]);
+            break;
+          case TEXT:
+            int length = valueBuffer.getInt();
+            values[i] = ReadWriteIOUtils.readBytes(valueBuffer, length);
+            break;
+          default:
+            throw new UnSupportedDataTypeException(
+                String.format("Data type %s is not supported.", columnTypeDeduplicatedList.get(i)));
+        }
+      }
+    }
+    rowsIndex++;
+    hasCachedRecord = true;
+  }
+
+  public boolean isNull(int columnIndex) throws StatementExecutionException {
+    int index = columnOrdinalMap.get(findColumnNameByIndex(columnIndex)) - START_INDEX;
+    // time column will never be null
+    if (index < 0) {
+      return true;
+    }
+    return isNull(index, rowsIndex - 1);
+  }
+
+  public boolean isNull(String columnName) {
+    int index = columnOrdinalMap.get(columnName) - START_INDEX;
+    // time column will never be null
+    if (index < 0) {
+      return true;
+    }
+    return isNull(index, rowsIndex - 1);
+  }
+
+  private boolean isNull(int index, int rowNum) {
+    byte bitmap = currentBitmap[index];
+    int shift = rowNum % 8;
+    return ((FLAG >>> shift) & (bitmap & 0xff)) == 0;
+  }
+
+  public boolean getBoolean(int columnIndex) throws StatementExecutionException {
+    return getBoolean(findColumnNameByIndex(columnIndex));
+  }
+
+  public boolean getBoolean(String columnName) throws StatementExecutionException {
+    checkRecord();
+    int index = columnOrdinalMap.get(columnName) - START_INDEX;
+    if (!isNull(index, rowsIndex - 1)) {
+      lastReadWasNull = false;
+      return BytesUtils.bytesToBool(values[index]);
+    } else {
+      lastReadWasNull = true;
+      return false;
+    }
+  }
+
+  public double getDouble(int columnIndex) throws StatementExecutionException {
+    return getDouble(findColumnNameByIndex(columnIndex));
+  }
+
+  public double getDouble(String columnName) throws StatementExecutionException {
+    checkRecord();
+    int index = columnOrdinalMap.get(columnName) - START_INDEX;
+    if (!isNull(index, rowsIndex - 1)) {
+      lastReadWasNull = false;
+      return BytesUtils.bytesToDouble(values[index]);
+    } else {
+      lastReadWasNull = true;
+      return 0;
+    }
+  }
+
+  public float getFloat(int columnIndex) throws StatementExecutionException {
+    return getFloat(findColumnNameByIndex(columnIndex));
+  }
+
+  public float getFloat(String columnName) throws StatementExecutionException {
+    checkRecord();
+    int index = columnOrdinalMap.get(columnName) - START_INDEX;
+    if (!isNull(index, rowsIndex - 1)) {
+      lastReadWasNull = false;
+      return BytesUtils.bytesToFloat(values[index]);
+    } else {
+      lastReadWasNull = true;
+      return 0;
+    }
+  }
+
+  public int getInt(int columnIndex) throws StatementExecutionException {
+    return getInt(findColumnNameByIndex(columnIndex));
+  }
+
+  public int getInt(String columnName) throws StatementExecutionException {
+    checkRecord();
+    int index = columnOrdinalMap.get(columnName) - START_INDEX;
+    if (!isNull(index, rowsIndex - 1)) {
+      lastReadWasNull = false;
+      return BytesUtils.bytesToInt(values[index]);
+    } else {
+      lastReadWasNull = true;
+      return 0;
+    }
+  }
+
+  public long getLong(int columnIndex) throws StatementExecutionException {
+    return getLong(findColumnNameByIndex(columnIndex));
+  }
+
+  public long getLong(String columnName) throws StatementExecutionException {
+    checkRecord();
+    if (columnName.equals(TIMESTAMP_STR)) {
+      return BytesUtils.bytesToLong(time);
+    }
+    int index = columnOrdinalMap.get(columnName) - START_INDEX;
+    if (!isNull(index, rowsIndex - 1)) {
+      lastReadWasNull = false;
+      return BytesUtils.bytesToLong(values[index]);
+    } else {
+      lastReadWasNull = true;
+      return 0;
+    }
+  }
+
+  public Object getObject(int columnIndex) throws StatementExecutionException {
+    return getObject(findColumnNameByIndex(columnIndex));
+  }
+
+  public Object getObject(String columnName) throws StatementExecutionException {
+    return getObjectByName(columnName);
+  }
+
+  public String getString(int columnIndex) throws StatementExecutionException {
+    return getString(findColumnNameByIndex(columnIndex));
+  }
+
+  public String getString(String columnName) throws StatementExecutionException {
+    return getValueByName(columnName);
+  }
+
+  public Timestamp getTimestamp(int columnIndex) throws StatementExecutionException {
+    return new Timestamp(getLong(columnIndex));
+  }
+
+  public Timestamp getTimestamp(String columnName) throws StatementExecutionException {
+    return getTimestamp(findColumn(columnName));
+  }
+
+  public int findColumn(String columnName) {
+    return columnOrdinalMap.get(columnName);
+  }
+
+  public String getValueByName(String columnName) throws StatementExecutionException {
+    checkRecord();
+    if (columnName.equals(TIMESTAMP_STR)) {
+      return String.valueOf(BytesUtils.bytesToLong(time));
+    }
+    int index = columnOrdinalMap.get(columnName) - START_INDEX;
+    if (index < 0 || index >= values.length || isNull(index, rowsIndex - 1)) {
+      lastReadWasNull = true;
+      return null;
+    }
+    lastReadWasNull = false;
+    return getString(index, columnTypeDeduplicatedList.get(index), values);
+  }
+
+  public String getString(int index, TSDataType tsDataType, byte[][] values) {
+    switch (tsDataType) {
+      case BOOLEAN:
+        return String.valueOf(BytesUtils.bytesToBool(values[index]));
+      case INT32:
+        return String.valueOf(BytesUtils.bytesToInt(values[index]));
+      case INT64:
+        return String.valueOf(BytesUtils.bytesToLong(values[index]));
+      case FLOAT:
+        return String.valueOf(BytesUtils.bytesToFloat(values[index]));
+      case DOUBLE:
+        return String.valueOf(BytesUtils.bytesToDouble(values[index]));
+      case TEXT:
+        return new String(values[index], StandardCharsets.UTF_8);
+      default:
+        return null;
+    }
+  }
+
+  public Object getObjectByName(String columnName) throws StatementExecutionException {
+    checkRecord();
+    if (columnName.equals(TIMESTAMP_STR)) {
+      return BytesUtils.bytesToLong(time);
+    }
+    int index = columnOrdinalMap.get(columnName) - START_INDEX;
+    if (index < 0 || index >= values.length || isNull(index, rowsIndex - 1)) {
+      lastReadWasNull = true;
+      return null;
+    }
+    lastReadWasNull = false;
+    return getObject(index, columnTypeDeduplicatedList.get(index), values);
+  }
+
+  public Object getObject(int index, TSDataType tsDataType, byte[][] values) {
+    switch (tsDataType) {
+      case BOOLEAN:
+        return BytesUtils.bytesToBool(values[index]);
+      case INT32:
+        return BytesUtils.bytesToInt(values[index]);
+      case INT64:
+        return BytesUtils.bytesToLong(values[index]);
+      case FLOAT:
+        return BytesUtils.bytesToFloat(values[index]);
+      case DOUBLE:
+        return BytesUtils.bytesToDouble(values[index]);
+      case TEXT:
+        return new String(values[index], StandardCharsets.UTF_8);
+      default:
+        return null;
+    }
+  }
+
+  public String findColumnNameByIndex(int columnIndex) throws StatementExecutionException {
+    if (columnIndex <= 0) {
+      throw new StatementExecutionException("column index should start from 1");
+    }
+    if (columnIndex > columnNameList.size()) {
+      throw new StatementExecutionException(
+          String.format("column index %d out of range %d", columnIndex, columnNameList.size()));
+    }
+    return columnNameList.get(columnIndex - 1);
+  }
+
+  public void checkRecord() throws StatementExecutionException {
+    if (Objects.isNull(tsQueryDataSet)) {
+      throw new StatementExecutionException("No record remains");
+    }
+  }
+
+  public void setTsQueryDataSet(TSQueryDataSet tsQueryDataSet) {
+    this.tsQueryDataSet = tsQueryDataSet;
+    this.emptyResultSet = (tsQueryDataSet == null || !tsQueryDataSet.time.hasRemaining());
+  }
+}
diff --git a/thrift/src/main/thrift/rpc.thrift b/thrift/src/main/thrift/rpc.thrift
index 13aac39..f0079bb 100644
--- a/thrift/src/main/thrift/rpc.thrift
+++ b/thrift/src/main/thrift/rpc.thrift
@@ -61,6 +61,8 @@ struct TSExecuteStatementResp {
   // for disable align statements, queryDataSet is null and nonAlignQueryDataSet is not null
   8: optional TSQueryNonAlignDataSet nonAlignQueryDataSet
   9: optional map<string, i32> columnNameIndexMap
+  10: optional list<string> sgColumns
+  11: optional list<byte> aliasColumns
 }
 
 enum TSProtocolVersion {
@@ -119,6 +121,8 @@ struct TSExecuteStatementReq {
   5: optional i64 timeout
 
   6: optional bool enableRedirectQuery;
+
+  7: optional bool jdbcQuery;
 }
 
 struct TSExecuteBatchStatementReq{
@@ -291,6 +295,7 @@ struct TSRawDataQueryReq {
   5: required i64 endTime
   6: required i64 statementId
   7: optional bool enableRedirectQuery;
+  8: optional bool jdbcQuery;
 }
 
 struct TSLastDataQueryReq {
@@ -300,6 +305,7 @@ struct TSLastDataQueryReq {
   4: required i64 time
   5: required i64 statementId
   6: optional bool enableRedirectQuery;
+  7: optional bool jdbcQuery;
 }
 
 struct TSCreateMultiTimeseriesReq {
@@ -318,6 +324,13 @@ struct ServerProperties {
   1: required string version;
   2: required list<string> supportedTimeAggregationOperations;
   3: required string timestampPrecision;
+  4: i32 maxConcurrentClientNum;
+  5: optional string watermarkSecretKey;
+  6: optional string watermarkBitString
+  7: optional i32 watermarkParamMarkRate;
+  8: optional i32 watermarkParamMaxRightBit;
+  9: optional i32 thriftMaxFrameSize;
+  10:optional bool isReadOnly;
 }
 
 struct TSSetSchemaTemplateReq {