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

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


The following commit(s) were added to refs/heads/master by this push:
     new 72eb5af  [IOTDB-447] query not exist measurement and constant 
measurement (#772)
72eb5af is described below

commit 72eb5afc31656ba92e186f2b2e5834ab1a4c63d7
Author: SilverNarcissus <[email protected]>
AuthorDate: Sat Feb 8 13:06:29 2020 +0800

    [IOTDB-447] query not exist measurement and constant measurement (#772)
    
    * Add constant and not exist column support in group by device query
    
    * enable session handle duplicate columns
---
 .../org/apache/iotdb/db/qp/strategy/SqlBase.g4     |   1 +
 .../db/engine/storagegroup/TsFileProcessor.java    |   1 +
 .../iotdb/db/qp/physical/crud/QueryPlan.java       |  70 ++
 .../iotdb/db/qp/strategy/LogicalGenerator.java     |   9 +
 .../iotdb/db/qp/strategy/PhysicalGenerator.java    |  88 ++-
 .../qp/strategy/optimizer/ConcatPathOptimizer.java |   8 -
 .../qp/strategy/optimizer/RemoveNotOptimizer.java  |   6 +
 .../db/query/dataset/DeviceIterateDataSet.java     |  47 +-
 .../org/apache/iotdb/db/service/TSServiceImpl.java | 146 +++-
 .../iotdb/db/integration/IoTDBGroupbyDeviceIT.java | 823 ++++++++++++++++++++-
 .../iotdb/db/integration/IoTDBMultiSeriesIT.java   |  20 +-
 .../org/apache/iotdb/session/SessionDataSet.java   | 141 ++--
 .../org/apache/iotdb/session/IoTDBSessionIT.java   |  53 ++
 .../org/apache/iotdb/tsfile/read/common/Field.java |  30 +
 .../apache/iotdb/tsfile/read/common/RowRecord.java |   5 +
 15 files changed, 1322 insertions(+), 126 deletions(-)

diff --git a/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4 
b/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4
index ba925a5..0964d7f 100644
--- a/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4
+++ b/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4
@@ -97,6 +97,7 @@ statement
 selectElements
     : functionCall (COMMA functionCall)* #functionElement
     | suffixPath (COMMA suffixPath)* #selectElement
+    | STRING_LITERAL (COMMA STRING_LITERAL)* #selectConstElement
     ;
 
 functionCall
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
index c680a7c..a90debd 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
@@ -505,6 +505,7 @@ public class TsFileProcessor {
     tsFileResource.serialize();
     writer.endFile(schema);
     tsFileResource.cleanCloseFlag();
+    tsFileResource.close();
 
     // remove this processor from Closing list in StorageGroupProcessor,
     // mark the TsFileResource closed, no need writer anymore
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java
index 11f452a..82b3804 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java
@@ -53,6 +53,76 @@ public class QueryPlan extends PhysicalPlan {
   private Map<String, IExpression> deviceToFilterMap; // for group by device 
sql
   private Map<Path, TSDataType> dataTypeMapping = new HashMap<>(); // for 
group by device sql
 
+  public List<String> getNotExistMeasurements() {
+    return notExistMeasurements;
+  }
+
+  public void setNotExistMeasurements(List<String> notExistMeasurements) {
+    this.notExistMeasurements = notExistMeasurements;
+  }
+
+  public List<Integer> getPositionOfNotExistMeasurements() {
+    return positionOfNotExistMeasurements;
+  }
+
+  public void setPositionOfNotExistMeasurements(
+      List<Integer> positionOfNotExistMeasurements) {
+    this.positionOfNotExistMeasurements = positionOfNotExistMeasurements;
+  }
+
+  public List<String> getConstMeasurements() {
+    return constMeasurements;
+  }
+
+  public void setConstMeasurements(List<String> constMeasurements) {
+    this.constMeasurements = constMeasurements;
+  }
+
+  public List<Integer> getPositionOfConstMeasurements() {
+    return positionOfConstMeasurements;
+  }
+
+  public void setPositionOfConstMeasurements(List<Integer> 
positionOfConstMeasurements) {
+    this.positionOfConstMeasurements = positionOfConstMeasurements;
+  }
+
+  //the measurements that do not exist in any device,
+  // data type is considered as Boolean. The value is considered as null
+  private List<String> notExistMeasurements = new ArrayList<>();; // for group 
by device sql
+  private List<Integer> positionOfNotExistMeasurements = new ArrayList<>(); // 
for group by device sql
+  //the measurements that have quotation mark. e.g., "abc",
+  // '11', the data type is considered as String and the value  is considered 
is the same with measurement name
+  private List<String> constMeasurements = new ArrayList<>(); // for group by 
device sql
+  private List<Integer> positionOfConstMeasurements = new ArrayList<>(); // 
for group by device sql
+
+  //we use the following algorithm to reproduce the order of measurements that 
user writes.
+  //suppose user writes SELECT 'c1',a1,b1,b2,'c2',a2,a3,'c3',b3,a4,a5 FROM ... 
where for each a_i
+  // column there is at least one device having it, and for each b_i column 
there is no device
+  // having it, and 'c_i' is a const column.
+  // Then, measurements = {a1, a2, a3, a4, a5};
+  // notExistMeasurements = {b1, b2, b3}, and positionOfNotExistMeasurements = 
{2, 3, 8};
+  // constMeasurements = {'c1', 'c2', 'c3'}, and positionOfConstMeasurements = 
{0, 4, 7}.
+  // When to reproduce the order of measurements. The pseudocode is:
+  //<pre>
+  // current = 0;
+  // if (min(notExist, const) <= current) {
+  //  pull min_element(notExist, const);
+  // } else {
+  //  pull from measurements;
+  // }
+  // current ++;
+  //</pre>
+
+  public void addNotExistMeasurement(int position, String measurement) {
+    notExistMeasurements.add(measurement);
+    positionOfNotExistMeasurements.add(position);
+  }
+
+  public void addConstMeasurement(int position, String measurement) {
+    constMeasurements.add(measurement);
+    positionOfConstMeasurements.add(position);
+  }
+
   public QueryPlan() {
     super(true);
     setOperatorType(Operator.OperatorType.QUERY);
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
index 3757b33..a6ef2ae 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
@@ -123,6 +123,7 @@ import 
org.apache.iotdb.db.qp.strategy.SqlBaseParser.RevokeRoleFromUserContext;
 import org.apache.iotdb.db.qp.strategy.SqlBaseParser.RevokeUserContext;
 import 
org.apache.iotdb.db.qp.strategy.SqlBaseParser.RevokeWatermarkEmbeddingContext;
 import org.apache.iotdb.db.qp.strategy.SqlBaseParser.RootOrIdContext;
+import org.apache.iotdb.db.qp.strategy.SqlBaseParser.SelectConstElementContext;
 import org.apache.iotdb.db.qp.strategy.SqlBaseParser.SelectElementContext;
 import org.apache.iotdb.db.qp.strategy.SqlBaseParser.SelectStatementContext;
 import org.apache.iotdb.db.qp.strategy.SqlBaseParser.SetColContext;
@@ -1002,6 +1003,14 @@ public class LogicalGenerator extends 
SqlBaseBaseListener {
   }
 
   @Override
+  public void enterSelectConstElement(SelectConstElementContext ctx) {
+    super.enterSelectConstElement(ctx);
+    operatorType = SQLConstant.TOK_QUERY;
+    queryOp = new QueryOperator(SQLConstant.TOK_QUERY);
+    initializedOperator = queryOp;
+  }
+
+  @Override
   public void enterFromClause(FromClauseContext ctx) {
     super.enterFromClause(ctx);
     FromOperator fromOp = new FromOperator(SQLConstant.TOK_FROM);
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
index 3162c30..ac5fccf 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java
@@ -18,6 +18,14 @@
  */
 package org.apache.iotdb.db.qp.strategy;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import org.apache.iotdb.db.auth.AuthException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.path.PathException;
@@ -29,19 +37,58 @@ import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.executor.IQueryProcessExecutor;
 import org.apache.iotdb.db.qp.logical.Operator;
 import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
-import org.apache.iotdb.db.qp.logical.crud.*;
-import org.apache.iotdb.db.qp.logical.sys.*;
+import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
+import org.apache.iotdb.db.qp.logical.crud.DeleteDataOperator;
+import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
+import org.apache.iotdb.db.qp.logical.crud.InsertOperator;
+import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+import org.apache.iotdb.db.qp.logical.sys.AuthorOperator;
+import org.apache.iotdb.db.qp.logical.sys.CountOperator;
+import org.apache.iotdb.db.qp.logical.sys.CreateTimeSeriesOperator;
+import org.apache.iotdb.db.qp.logical.sys.DataAuthOperator;
+import org.apache.iotdb.db.qp.logical.sys.DeleteStorageGroupOperator;
+import org.apache.iotdb.db.qp.logical.sys.DeleteTimeSeriesOperator;
+import org.apache.iotdb.db.qp.logical.sys.LoadDataOperator;
+import org.apache.iotdb.db.qp.logical.sys.LoadFilesOperator;
+import org.apache.iotdb.db.qp.logical.sys.MoveFileOperator;
+import org.apache.iotdb.db.qp.logical.sys.PropertyOperator;
+import org.apache.iotdb.db.qp.logical.sys.RemoveFileOperator;
+import org.apache.iotdb.db.qp.logical.sys.SetStorageGroupOperator;
+import org.apache.iotdb.db.qp.logical.sys.SetTTLOperator;
+import org.apache.iotdb.db.qp.logical.sys.ShowChildPathsOperator;
+import org.apache.iotdb.db.qp.logical.sys.ShowDevicesOperator;
+import org.apache.iotdb.db.qp.logical.sys.ShowTTLOperator;
+import org.apache.iotdb.db.qp.logical.sys.ShowTimeSeriesOperator;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
-import org.apache.iotdb.db.qp.physical.crud.*;
-import org.apache.iotdb.db.qp.physical.sys.*;
+import org.apache.iotdb.db.qp.physical.crud.AggregationPlan;
+import org.apache.iotdb.db.qp.physical.crud.DeletePlan;
+import org.apache.iotdb.db.qp.physical.crud.FillQueryPlan;
+import org.apache.iotdb.db.qp.physical.crud.GroupByPlan;
+import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
+import org.apache.iotdb.db.qp.physical.crud.QueryPlan;
+import org.apache.iotdb.db.qp.physical.sys.AuthorPlan;
+import org.apache.iotdb.db.qp.physical.sys.CountPlan;
+import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DataAuthPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.LoadConfigurationPlan;
+import org.apache.iotdb.db.qp.physical.sys.LoadDataPlan;
+import org.apache.iotdb.db.qp.physical.sys.OperateFilePlan;
+import org.apache.iotdb.db.qp.physical.sys.PropertyPlan;
+import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
+import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowChildPathsPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowDevicesPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowPlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowPlan.ShowContentType;
+import org.apache.iotdb.db.qp.physical.sys.ShowTTLPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
 import org.apache.iotdb.db.service.TSServiceImpl;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.read.common.Path;
 import org.apache.iotdb.tsfile.read.expression.IExpression;
 
-import java.util.*;
-
 /**
  * Used to convert logical operator to physical plan
  */
@@ -216,17 +263,33 @@ public class PhysicalGenerator {
       Map<String, TSDataType> dataTypeConsistencyChecker = new HashMap<>();
       List<Path> paths = new ArrayList<>();
 
+      // cur loc for path
+      int loc = 0;
+
       for (int i = 0; i < suffixPaths.size(); i++) { // per suffix
         Path suffixPath = suffixPaths.get(i);
         Set<String> deviceSetOfGivenSuffix = new HashSet<>();
         Set<String> measurementSetOfGivenSuffix = new LinkedHashSet<>();
+        if(suffixPath.startWith("'") || suffixPath.startWith("\"")){
+          queryPlan.addConstMeasurement(loc++, suffixPath.getMeasurement());
+          continue;
+        }
 
+        Set<String> nonExistMeasurement = new HashSet<>();
         for (Path prefixPath : prefixPaths) { // per prefix
           Path fullPath = Path.addPrefixPath(suffixPath, prefixPath);
+          // for constant path
+
           Set<String> tmpDeviceSet = new HashSet<>();
           try {
             List<String> actualPaths = executor
                 .getAllMatchedPaths(fullPath.getFullPath());  // remove stars 
to get actual paths
+
+            if(actualPaths.isEmpty() && originAggregations.isEmpty()){
+              // for actual non exist path
+              nonExistMeasurement.add(fullPath.getMeasurement());
+            }
+
             for (String pathStr : actualPaths) {
               Path path = new Path(pathStr);
               String device = path.getDevice();
@@ -269,7 +332,9 @@ public class PhysicalGenerator {
               }
 
               // update measurementSetOfGivenSuffix
-              measurementSetOfGivenSuffix.add(measurementChecked);
+              if(measurementSetOfGivenSuffix.add(measurementChecked)){
+                loc++;
+              }
               // update measurementColumnsGroupByDevice
               if (!measurementsGroupByDevice.containsKey(device)) {
                 measurementsGroupByDevice.put(device, new HashSet<>());
@@ -287,6 +352,11 @@ public class PhysicalGenerator {
                     fullPath.getFullPath()) + e.getMessage());
           }
         }
+
+        nonExistMeasurement.removeAll(measurementSetOfGivenSuffix);
+        for(String notExistMeasurementString : nonExistMeasurement){
+          queryPlan.addNotExistMeasurement(loc++, notExistMeasurementString);
+        }
         // update measurements
         // Note that in the loop of a suffix path, set is used.
         // And across the loops of suffix paths, list is used.
@@ -297,7 +367,9 @@ public class PhysicalGenerator {
         measurements.addAll(measurementSetOfGivenSuffix);
       }
 
-      if (measurements.isEmpty()) {
+      if (measurements.isEmpty()
+          && queryPlan.getConstMeasurements().isEmpty()
+          && queryPlan.getNotExistMeasurements().isEmpty()) {
         throw new QueryProcessException("do not select any existing series");
       }
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
index a8b0f0c..1f8b2b2 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
@@ -275,10 +275,6 @@ public class ConcatPathOptimizer implements 
ILogicalOptimizer {
       for (Path path : paths) {
         List<String> all;
         all = executor.getAllMatchedPaths(path.getFullPath());
-        if (all.isEmpty()) {
-          throw new LogicalOptimizeException(
-              "Path: \"" + path + "\" doesn't correspond to any known time 
series");
-        }
         for (String subPath : all) {
           if (!pathMap.containsKey(subPath)) {
             pathMap.put(subPath, 1);
@@ -301,10 +297,6 @@ public class ConcatPathOptimizer implements 
ILogicalOptimizer {
     for (int i = 0; i < paths.size(); i++) {
       try {
         List<String> actualPaths = 
executor.getAllMatchedPaths(paths.get(i).getFullPath());
-        if (actualPaths.isEmpty()) {
-          throw new LogicalOptimizeException(
-              "Path: \"" + paths.get(i) + "\" doesn't correspond to any known 
time series");
-        }
         for (String actualPath : actualPaths) {
           retPaths.add(new Path(actualPath));
           if (afterConcatAggregations != null && 
!afterConcatAggregations.isEmpty()) {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java
 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java
index 4d31fd6..6c4b98e 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java
@@ -53,10 +53,16 @@ public class RemoveNotOptimizer implements IFilterOptimizer 
{
       case KW_OR:
         // replace children in-place for efficiency
         List<FilterOperator> children = filter.getChildren();
+        if(children.size() < 2){
+         throw new LogicalOptimizeException("Filter has some time series don't 
correspond to any known time series");
+        }
         children.set(0, removeNot(children.get(0)));
         children.set(1, removeNot(children.get(1)));
         return filter;
       case KW_NOT:
+        if(filter.getChildren().size() < 1){
+          throw new LogicalOptimizeException("Filter has some time series 
don't correspond to any known time series");
+        }
         return reverseFilter(filter.getChildren().get(0));
       default:
         throw new LogicalOptimizeException("removeNot", tokenInt);
diff --git 
a/server/src/main/java/org/apache/iotdb/db/query/dataset/DeviceIterateDataSet.java
 
b/server/src/main/java/org/apache/iotdb/db/query/dataset/DeviceIterateDataSet.java
index 244ceb4..792e85d 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/query/dataset/DeviceIterateDataSet.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/query/dataset/DeviceIterateDataSet.java
@@ -57,6 +57,15 @@ public class DeviceIterateDataSet extends QueryDataSet {
   private Map<String, Set<String>> measurementColumnsGroupByDevice;
   private Map<String, IExpression> deviceToFilterMap;
 
+  //the measurements that do not exist in any device,
+  // data type is considered as Boolean. The value is considered as null
+  private List<String> notExistMeasurements; // for group by device sql
+  private List<Integer> positionOfNotExistMeasurements; // for group by device 
sql
+  //the measurements that have quotation mark. e.g., "abc",
+  // '11', the data type is considered as String and the value  is considered 
is the same with measurement name
+  private List<String> constMeasurements; // for group by device sql
+  private List<Integer> positionOfConstMeasurements; // for group by device sql
+
   // group-by-time parameters
   private long unit;
   private long slidingStep;
@@ -85,6 +94,11 @@ public class DeviceIterateDataSet extends QueryDataSet {
     this.context = context;
     this.measurementColumnsGroupByDevice = 
queryPlan.getMeasurementsGroupByDevice();
     this.deviceToFilterMap = queryPlan.getDeviceToFilterMap();
+    this.notExistMeasurements = queryPlan.getNotExistMeasurements();
+    this.constMeasurements = queryPlan.getConstMeasurements();
+    this.positionOfNotExistMeasurements = 
queryPlan.getPositionOfNotExistMeasurements();
+    this.positionOfConstMeasurements = 
queryPlan.getPositionOfConstMeasurements();
+    //BuildOutDataTypes();
 
     if (queryPlan instanceof GroupByPlan) {
       this.dataSetType = DataSetType.GROUPBY;
@@ -162,7 +176,7 @@ public class DeviceIterateDataSet extends QueryDataSet {
       }
 
       // get filter to execute for the current device
-      if(deviceToFilterMap != null){
+      if (deviceToFilterMap != null) {
         this.expression = deviceToFilterMap.get(currentDevice);
       }
 
@@ -234,7 +248,36 @@ public class DeviceIterateDataSet extends QueryDataSet {
         rowRecord.addField(measurementFields.get(mapPos));
       }
     }
-    return rowRecord;
+
+    // build record with constant and non exist measurement
+    RowRecord outRecord = new RowRecord(originRowRecord.getTimestamp());
+    int loc = 0;
+    int totalSize = notExistMeasurements.size() + constMeasurements.size()
+        + rowRecord.getFields().size();
+    int notExistMeasurementsLoc = 0;
+    int constMeasurementsLoc = 0;
+    int resLoc = 0;
+    // don't forget device column, so loc - 1 is for looking up constant and 
non exist column
+    while (loc < totalSize) {
+      if (notExistMeasurementsLoc < notExistMeasurements.size()
+          && loc - 1 == 
positionOfNotExistMeasurements.get(notExistMeasurementsLoc)) {
+        outRecord.addField(new Field(null));
+        notExistMeasurementsLoc++;
+      } else if (constMeasurementsLoc < constMeasurements.size()
+          && loc - 1 == positionOfConstMeasurements.get(constMeasurementsLoc)) 
{
+        Field res = new Field(TSDataType.TEXT);
+        
res.setBinaryV(Binary.valueOf(constMeasurements.get(constMeasurementsLoc)));
+        outRecord.addField(res);
+        constMeasurementsLoc++;
+      } else {
+        outRecord.addField(rowRecord.getFields().get(resLoc));
+        resLoc++;
+      }
+
+      loc++;
+    }
+
+    return outRecord;
   }
 
   private enum DataSetType {
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 4517400..e9f943a 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
@@ -18,6 +18,28 @@
  */
 package org.apache.iotdb.db.service;
 
+import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_PRIVILEGE;
+import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_ROLE;
+import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_STORAGE_GROUP;
+import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_TTL;
+import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_USER;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
 import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.apache.iotdb.db.auth.AuthException;
 import org.apache.iotdb.db.auth.AuthorityChecker;
@@ -46,7 +68,12 @@ import org.apache.iotdb.db.qp.physical.crud.BatchInsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.DeletePlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.QueryPlan;
-import org.apache.iotdb.db.qp.physical.sys.*;
+import org.apache.iotdb.db.qp.physical.sys.AuthorPlan;
+import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.control.QueryResourceManager;
 import org.apache.iotdb.db.query.dataset.NewEngineDataSetWithoutValueFilter;
@@ -55,7 +82,34 @@ import 
org.apache.iotdb.db.tools.watermark.GroupedLSBWatermarkEncoder;
 import org.apache.iotdb.db.tools.watermark.WatermarkEncoder;
 import org.apache.iotdb.db.utils.QueryDataSetUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
-import org.apache.iotdb.service.rpc.thrift.*;
+import org.apache.iotdb.service.rpc.thrift.ServerProperties;
+import org.apache.iotdb.service.rpc.thrift.TSBatchInsertionReq;
+import org.apache.iotdb.service.rpc.thrift.TSCancelOperationReq;
+import org.apache.iotdb.service.rpc.thrift.TSCloseOperationReq;
+import org.apache.iotdb.service.rpc.thrift.TSCloseSessionReq;
+import org.apache.iotdb.service.rpc.thrift.TSCreateTimeseriesReq;
+import org.apache.iotdb.service.rpc.thrift.TSDeleteDataReq;
+import org.apache.iotdb.service.rpc.thrift.TSExecuteBatchStatementReq;
+import org.apache.iotdb.service.rpc.thrift.TSExecuteBatchStatementResp;
+import org.apache.iotdb.service.rpc.thrift.TSExecuteInsertRowInBatchResp;
+import org.apache.iotdb.service.rpc.thrift.TSExecuteStatementReq;
+import org.apache.iotdb.service.rpc.thrift.TSExecuteStatementResp;
+import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataReq;
+import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataResp;
+import org.apache.iotdb.service.rpc.thrift.TSFetchResultsReq;
+import org.apache.iotdb.service.rpc.thrift.TSFetchResultsResp;
+import org.apache.iotdb.service.rpc.thrift.TSGetTimeZoneResp;
+import org.apache.iotdb.service.rpc.thrift.TSIService;
+import org.apache.iotdb.service.rpc.thrift.TSInsertInBatchReq;
+import org.apache.iotdb.service.rpc.thrift.TSInsertReq;
+import org.apache.iotdb.service.rpc.thrift.TSOpenSessionReq;
+import org.apache.iotdb.service.rpc.thrift.TSOpenSessionResp;
+import org.apache.iotdb.service.rpc.thrift.TSProtocolVersion;
+import org.apache.iotdb.service.rpc.thrift.TSQueryDataSet;
+import org.apache.iotdb.service.rpc.thrift.TSQueryNonAlignDataSet;
+import org.apache.iotdb.service.rpc.thrift.TSSetTimeZoneReq;
+import org.apache.iotdb.service.rpc.thrift.TSStatus;
+import org.apache.iotdb.service.rpc.thrift.TSStatusType;
 import 
org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
 import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
@@ -68,17 +122,6 @@ import org.apache.thrift.server.ServerContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.time.ZoneId;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-import static org.apache.iotdb.db.conf.IoTDBConstant.*;
-
 /**
  * Thrift RPC implementation at server side.
  */
@@ -738,9 +781,7 @@ public class TSServiceImpl implements TSIService.Iface, 
ServerContext {
   private void getGroupByDeviceQueryHeaders(QueryPlan plan, List<String> 
respColumns,
                                             List<String> columnTypes) {
     // set columns in TSExecuteStatementResp. Note this is without 
deduplication.
-    List<String> measurementColumns = plan.getMeasurements();
     respColumns.add(SQLConstant.GROUPBY_DEVICE_COLUMN_NAME);
-    respColumns.addAll(measurementColumns);
 
     // get column types and do deduplication
     columnTypes.add(TSDataType.TEXT.toString()); // the DEVICE column of 
GROUP_BY_DEVICE result
@@ -749,16 +790,81 @@ public class TSServiceImpl implements TSIService.Iface, 
ServerContext {
     List<String> deduplicatedMeasurementColumns = new ArrayList<>();
     Set<String> tmpColumnSet = new HashSet<>();
     Map<String, TSDataType> checker = plan.getDataTypeConsistencyChecker();
-    for (String column : measurementColumns) {
-      TSDataType dataType = checker.get(column);
-      columnTypes.add(dataType.toString());
+    // build column header with constant and non exist column and deduplicate
+    int loc = 0;
+    // size of total column
+    int totalSize = plan.getNotExistMeasurements().size() + 
plan.getConstMeasurements().size()
+        + plan.getMeasurements().size();
+    // not exist column loc
+    int notExistMeasurementsLoc = 0;
+    // constant column loc
+    int constMeasurementsLoc = 0;
+    // normal column loc
+    int resLoc = 0;
+    // after removing duplicate, we must shift column position
+    int shiftLoc = 0;
+    while (loc < totalSize) {
+      boolean isNonExist = false;
+      boolean isConstant = false;
+      TSDataType type = null;
+      String column = null;
+      // not exist
+      if (notExistMeasurementsLoc < plan.getNotExistMeasurements().size()
+          && loc == 
plan.getPositionOfNotExistMeasurements().get(notExistMeasurementsLoc)) {
+        // for shifting
+        plan.getPositionOfNotExistMeasurements().set(notExistMeasurementsLoc, 
loc - shiftLoc);
+
+        type = TSDataType.TEXT;
+        column = plan.getNotExistMeasurements().get(notExistMeasurementsLoc);
+        notExistMeasurementsLoc++;
+        isNonExist = true;
+      }
+      // constant
+      else if (constMeasurementsLoc < plan.getConstMeasurements().size()
+          && loc == 
plan.getPositionOfConstMeasurements().get(constMeasurementsLoc)) {
+        // for shifting
+        plan.getPositionOfConstMeasurements().set(constMeasurementsLoc, loc - 
shiftLoc);
+
+        type = TSDataType.TEXT;
+        column = plan.getConstMeasurements().get(constMeasurementsLoc);
+        constMeasurementsLoc++;
+        isConstant = true;
+      }
+      // normal series
+      else {
+        type = checker.get(plan.getMeasurements().get(resLoc));
+        column = plan.getMeasurements().get(resLoc);
+        resLoc++;
+      }
 
+      columnTypes.add(type.toString());
+      respColumns.add(column);
+      // deduplicate part
       if (!tmpColumnSet.contains(column)) {
         // Note that this deduplication strategy is consistent with that of 
client IoTDBQueryResultSet.
         tmpColumnSet.add(column);
-        deduplicatedMeasurementColumns.add(column);
-        deduplicatedColumnsType.add(dataType);
+        if(!isNonExist && ! isConstant) {
+          // only refer to those normal measurements
+          deduplicatedMeasurementColumns.add(column);
+        }
+        deduplicatedColumnsType.add(type);
+      }
+      else if(isConstant){
+        shiftLoc++;
+        constMeasurementsLoc--;
+        plan.getConstMeasurements().remove(constMeasurementsLoc);
+        plan.getPositionOfConstMeasurements().remove(constMeasurementsLoc);
+      }
+      else if(isNonExist){
+        shiftLoc++;
+        notExistMeasurementsLoc--;
+        plan.getNotExistMeasurements().remove(notExistMeasurementsLoc);
+        
plan.getPositionOfNotExistMeasurements().remove(notExistMeasurementsLoc);
+      }
+      else {
+        shiftLoc++;
       }
+      loc++;
     }
 
     // save deduplicated measurementColumn names and types in QueryPlan for 
the next stage to use.
diff --git 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupbyDeviceIT.java
 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupbyDeviceIT.java
index 52e20dd..9a3d96d 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupbyDeviceIT.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBGroupbyDeviceIT.java
@@ -18,6 +18,14 @@
  */
 package org.apache.iotdb.db.integration;
 
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Statement;
+import java.sql.Types;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.jdbc.Config;
 import org.junit.AfterClass;
@@ -25,10 +33,6 @@ import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import java.sql.*;
-
-import static org.junit.Assert.fail;
-
 public class IoTDBGroupbyDeviceIT {
 
   private static String[] sqls = new String[]{
@@ -458,12 +462,12 @@ public class IoTDBGroupbyDeviceIT {
   @Test
   public void groupByTimeTest() throws ClassNotFoundException {
     String[] retArray = new String[]{
-            "2,root.vehicle.d0,1,1,3,0,0,",
-            "22,root.vehicle.d0,0,0,0,0,0,",
-            "42,root.vehicle.d0,1,1,0,0,0,",
-            "2,root.vehicle.d1,0,null,null,null,null,",
-            "22,root.vehicle.d1,0,null,null,null,null,",
-            "42,root.vehicle.d1,0,null,null,null,null,",
+        "2,root.vehicle.d0,1,1,3,0,0,",
+        "22,root.vehicle.d0,0,0,0,0,0,",
+        "42,root.vehicle.d0,1,1,0,0,0,",
+        "2,root.vehicle.d1,0,null,null,null,null,",
+        "22,root.vehicle.d1,0,null,null,null,null,",
+        "42,root.vehicle.d1,0,null,null,null,null,",
     };
 
     Class.forName(Config.JDBC_DRIVER_NAME);
@@ -571,20 +575,6 @@ public class IoTDBGroupbyDeviceIT {
   }
 
   @Test
-  public void errorCaseTest2() throws ClassNotFoundException {
-    Class.forName(Config.JDBC_DRIVER_NAME);
-    try (Connection connection = DriverManager
-        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
-        Statement statement = connection.createStatement()) {
-      boolean hasResultSet = statement.execute(
-          "select s0 from root.nonexistent.noneixtsent group by device");
-      fail("No exception thrown.");
-    } catch (Exception e) {
-      Assert.assertTrue(e.getMessage().contains("do not select any existing 
series"));
-    }
-  }
-
-  @Test
   public void errorCaseTest3() throws ClassNotFoundException {
     Class.forName(Config.JDBC_DRIVER_NAME);
     try (Connection connection = DriverManager
@@ -710,4 +700,789 @@ public class IoTDBGroupbyDeviceIT {
     }
   }
 
+  @Test
+  public void selectConstantTest() throws ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,1101,null,null,null,11,",
+        "2,root.vehicle.d0,10000,40000,2.22,null,null,11,",
+        "3,root.vehicle.d0,null,null,3.33,null,null,11,",
+        "4,root.vehicle.d0,null,null,4.44,null,null,11,",
+        "50,root.vehicle.d0,10000,50000,null,null,null,11,",
+        "60,root.vehicle.d0,null,null,null,aaaaa,null,11,",
+        "70,root.vehicle.d0,null,null,null,bbbbb,null,11,",
+        "80,root.vehicle.d0,null,null,null,ccccc,null,11,",
+        "100,root.vehicle.d0,99,199,null,null,true,11,",
+        "101,root.vehicle.d0,99,199,null,ddddd,null,11,",
+        "102,root.vehicle.d0,80,180,10.0,fffff,null,11,",
+        "103,root.vehicle.d0,99,199,null,null,null,11,",
+        "104,root.vehicle.d0,90,190,null,null,null,11,",
+        "105,root.vehicle.d0,99,199,11.11,null,null,11,",
+        "106,root.vehicle.d0,99,null,null,null,null,11,",
+        "1000,root.vehicle.d0,22222,55555,1000.11,null,null,11,",
+        "946684800000,root.vehicle.d0,null,100,null,good,null,11,",
+        "1,root.vehicle.d1,999,null,null,null,null,11,",
+        "1000,root.vehicle.d1,888,null,null,null,null,11,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select *, \"11\" from root.vehicle group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s1,s2,s3,s4,11,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.BIGINT, resultSetMetaData.getColumnType(4));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(5));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(6));
+        Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(7));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectNonExistTest() throws ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,1101,null,null,null,null,",
+        "2,root.vehicle.d0,10000,40000,2.22,null,null,null,",
+        "3,root.vehicle.d0,null,null,3.33,null,null,null,",
+        "4,root.vehicle.d0,null,null,4.44,null,null,null,",
+        "50,root.vehicle.d0,10000,50000,null,null,null,null,",
+        "60,root.vehicle.d0,null,null,null,aaaaa,null,null,",
+        "70,root.vehicle.d0,null,null,null,bbbbb,null,null,",
+        "80,root.vehicle.d0,null,null,null,ccccc,null,null,",
+        "100,root.vehicle.d0,99,199,null,null,true,null,",
+        "101,root.vehicle.d0,99,199,null,ddddd,null,null,",
+        "102,root.vehicle.d0,80,180,10.0,fffff,null,null,",
+        "103,root.vehicle.d0,99,199,null,null,null,null,",
+        "104,root.vehicle.d0,90,190,null,null,null,null,",
+        "105,root.vehicle.d0,99,199,11.11,null,null,null,",
+        "106,root.vehicle.d0,99,null,null,null,null,null,",
+        "1000,root.vehicle.d0,22222,55555,1000.11,null,null,null,",
+        "946684800000,root.vehicle.d0,null,100,null,good,null,null,",
+        "1,root.vehicle.d1,999,null,null,null,null,null,",
+        "1000,root.vehicle.d1,888,null,null,null,null,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s0, s1, s2, s3, s4, s5 from root.vehicle.*  group by 
device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s1,s2,s3,s4,s5,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.BIGINT, resultSetMetaData.getColumnType(4));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(5));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(6));
+        Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(7));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+
+  @Test
+  public void selectConstantTestUnorder() throws ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,1101,11,null,22,null,null,",
+        "2,root.vehicle.d0,10000,40000,11,2.22,22,null,null,",
+        "3,root.vehicle.d0,null,null,11,3.33,22,null,null,",
+        "4,root.vehicle.d0,null,null,11,4.44,22,null,null,",
+        "50,root.vehicle.d0,10000,50000,11,null,22,null,null,",
+        "60,root.vehicle.d0,null,null,11,null,22,aaaaa,null,",
+        "70,root.vehicle.d0,null,null,11,null,22,bbbbb,null,",
+        "80,root.vehicle.d0,null,null,11,null,22,ccccc,null,",
+        "100,root.vehicle.d0,99,199,11,null,22,null,true,",
+        "101,root.vehicle.d0,99,199,11,null,22,ddddd,null,",
+        "102,root.vehicle.d0,80,180,11,10.0,22,fffff,null,",
+        "103,root.vehicle.d0,99,199,11,null,22,null,null,",
+        "104,root.vehicle.d0,90,190,11,null,22,null,null,",
+        "105,root.vehicle.d0,99,199,11,11.11,22,null,null,",
+        "106,root.vehicle.d0,99,null,11,null,22,null,null,",
+        "1000,root.vehicle.d0,22222,55555,11,1000.11,22,null,null,",
+        "946684800000,root.vehicle.d0,null,100,11,null,22,good,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s0, s1,\"11\", s2, \"22\", s3, s4 from root.vehicle.d0 group 
by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s1,11,s2,22,s3,s4,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.BIGINT, resultSetMetaData.getColumnType(4));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(6));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(7));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(9));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(17, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectConstantAndNonExistTestUnorder() throws 
ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,1101,11,null,22,null,null,null,",
+        "2,root.vehicle.d0,10000,40000,11,2.22,22,null,null,null,",
+        "3,root.vehicle.d0,null,null,11,3.33,22,null,null,null,",
+        "4,root.vehicle.d0,null,null,11,4.44,22,null,null,null,",
+        "50,root.vehicle.d0,10000,50000,11,null,22,null,null,null,",
+        "60,root.vehicle.d0,null,null,11,null,22,null,aaaaa,null,",
+        "70,root.vehicle.d0,null,null,11,null,22,null,bbbbb,null,",
+        "80,root.vehicle.d0,null,null,11,null,22,null,ccccc,null,",
+        "100,root.vehicle.d0,99,199,11,null,22,null,null,true,",
+        "101,root.vehicle.d0,99,199,11,null,22,null,ddddd,null,",
+        "102,root.vehicle.d0,80,180,11,10.0,22,null,fffff,null,",
+        "103,root.vehicle.d0,99,199,11,null,22,null,null,null,",
+        "104,root.vehicle.d0,90,190,11,null,22,null,null,null,",
+        "105,root.vehicle.d0,99,199,11,11.11,22,null,null,null,",
+        "106,root.vehicle.d0,99,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d0,22222,55555,11,1000.11,22,null,null,null,",
+        "946684800000,root.vehicle.d0,null,100,11,null,22,null,good,null,",
+        "1,root.vehicle.d1,999,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d1,888,null,11,null,22,null,null,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s0, s1,\"11\", s2, \"22\", s5, s3, s4 from root.vehicle.* 
group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s1,11,s2,22,s5,s3,s4,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.BIGINT, resultSetMetaData.getColumnType(4));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(6));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(7));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(9));
+        Assert.assertEquals(Types.BOOLEAN, 
resultSetMetaData.getColumnType(10));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectConstantAndNonExistTestUnorder2() throws 
ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,null,11,null,22,null,null,null,",
+        "2,root.vehicle.d0,10000,null,11,2.22,22,null,null,null,",
+        "3,root.vehicle.d0,null,null,11,3.33,22,null,null,null,",
+        "4,root.vehicle.d0,null,null,11,4.44,22,null,null,null,",
+        "50,root.vehicle.d0,10000,null,11,null,22,null,null,null,",
+        "60,root.vehicle.d0,null,aaaaa,11,null,22,null,aaaaa,null,",
+        "70,root.vehicle.d0,null,bbbbb,11,null,22,null,bbbbb,null,",
+        "80,root.vehicle.d0,null,ccccc,11,null,22,null,ccccc,null,",
+        "100,root.vehicle.d0,99,null,11,null,22,null,null,true,",
+        "101,root.vehicle.d0,99,ddddd,11,null,22,null,ddddd,null,",
+        "102,root.vehicle.d0,80,fffff,11,10.0,22,null,fffff,null,",
+        "103,root.vehicle.d0,99,null,11,null,22,null,null,null,",
+        "104,root.vehicle.d0,90,null,11,null,22,null,null,null,",
+        "105,root.vehicle.d0,99,null,11,11.11,22,null,null,null,",
+        "106,root.vehicle.d0,99,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d0,22222,null,11,1000.11,22,null,null,null,",
+        "946684800000,root.vehicle.d0,null,good,11,null,22,null,good,null,",
+        "1,root.vehicle.d1,999,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d1,888,null,11,null,22,null,null,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s0, s3,\"11\", s2, \"22\", s5, s3, s4 from root.vehicle.* 
group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s3,11,s2,22,s5,s3,s4,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(4));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(6));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(7));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(9));
+        Assert.assertEquals(Types.BOOLEAN, 
resultSetMetaData.getColumnType(10));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectConstantAndNonExistTestUnorder3() throws 
ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,null,11,null,22,null,null,null,",
+        "2,root.vehicle.d0,10000,null,11,2.22,22,null,null,null,",
+        "3,root.vehicle.d0,null,null,11,3.33,22,null,null,null,",
+        "4,root.vehicle.d0,null,null,11,4.44,22,null,null,null,",
+        "50,root.vehicle.d0,10000,null,11,null,22,null,null,null,",
+        "60,root.vehicle.d0,null,null,11,null,22,null,aaaaa,null,",
+        "70,root.vehicle.d0,null,null,11,null,22,null,bbbbb,null,",
+        "80,root.vehicle.d0,null,null,11,null,22,null,ccccc,null,",
+        "100,root.vehicle.d0,99,null,11,null,22,null,null,true,",
+        "101,root.vehicle.d0,99,null,11,null,22,null,ddddd,null,",
+        "102,root.vehicle.d0,80,null,11,10.0,22,null,fffff,null,",
+        "103,root.vehicle.d0,99,null,11,null,22,null,null,null,",
+        "104,root.vehicle.d0,90,null,11,null,22,null,null,null,",
+        "105,root.vehicle.d0,99,null,11,11.11,22,null,null,null,",
+        "106,root.vehicle.d0,99,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d0,22222,null,11,1000.11,22,null,null,null,",
+        "946684800000,root.vehicle.d0,null,null,11,null,22,null,good,null,",
+        "1,root.vehicle.d1,999,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d1,888,null,11,null,22,null,null,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s0, s5, \"11\", s2, \"22\", s5, s3, s4 from root.vehicle.* 
group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s5,11,s2,22,s5,s3,s4,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(4));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(6));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(7));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(9));
+        Assert.assertEquals(Types.BOOLEAN, 
resultSetMetaData.getColumnType(10));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectConstantAndNonExistTestShifting() throws 
ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,null,null,11,null,22,null,null,null,",
+        "2,root.vehicle.d0,10000,null,null,11,2.22,22,null,null,null,",
+        "3,root.vehicle.d0,null,null,null,11,3.33,22,null,null,null,",
+        "4,root.vehicle.d0,null,null,null,11,4.44,22,null,null,null,",
+        "50,root.vehicle.d0,10000,null,null,11,null,22,null,null,null,",
+        "60,root.vehicle.d0,null,null,null,11,null,22,null,aaaaa,null,",
+        "70,root.vehicle.d0,null,null,null,11,null,22,null,bbbbb,null,",
+        "80,root.vehicle.d0,null,null,null,11,null,22,null,ccccc,null,",
+        "100,root.vehicle.d0,99,null,null,11,null,22,null,null,true,",
+        "101,root.vehicle.d0,99,null,null,11,null,22,null,ddddd,null,",
+        "102,root.vehicle.d0,80,null,null,11,10.0,22,null,fffff,null,",
+        "103,root.vehicle.d0,99,null,null,11,null,22,null,null,null,",
+        "104,root.vehicle.d0,90,null,null,11,null,22,null,null,null,",
+        "105,root.vehicle.d0,99,null,null,11,11.11,22,null,null,null,",
+        "106,root.vehicle.d0,99,null,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d0,22222,null,null,11,1000.11,22,null,null,null,",
+        
"946684800000,root.vehicle.d0,null,null,null,11,null,22,null,good,null,",
+        "1,root.vehicle.d1,999,null,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d1,888,null,null,11,null,22,null,null,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s0, s5, s5, \"11\", s2, \"22\", s5, s3, s4 from 
root.vehicle.* group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s5,s5,11,s2,22,s5,s3,s4,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(4));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(6));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(7));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(9));
+        Assert.assertEquals(Types.VARCHAR, 
resultSetMetaData.getColumnType(10));
+        Assert.assertEquals(Types.BOOLEAN, 
resultSetMetaData.getColumnType(11));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectConstantAndNonExistTestShifting2() throws 
ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,101,null,11,null,22,null,null,null,",
+        "2,root.vehicle.d0,10000,10000,null,11,2.22,22,null,null,null,",
+        "3,root.vehicle.d0,null,null,null,11,3.33,22,null,null,null,",
+        "4,root.vehicle.d0,null,null,null,11,4.44,22,null,null,null,",
+        "50,root.vehicle.d0,10000,10000,null,11,null,22,null,null,null,",
+        "60,root.vehicle.d0,null,null,null,11,null,22,null,aaaaa,null,",
+        "70,root.vehicle.d0,null,null,null,11,null,22,null,bbbbb,null,",
+        "80,root.vehicle.d0,null,null,null,11,null,22,null,ccccc,null,",
+        "100,root.vehicle.d0,99,99,null,11,null,22,null,null,true,",
+        "101,root.vehicle.d0,99,99,null,11,null,22,null,ddddd,null,",
+        "102,root.vehicle.d0,80,80,null,11,10.0,22,null,fffff,null,",
+        "103,root.vehicle.d0,99,99,null,11,null,22,null,null,null,",
+        "104,root.vehicle.d0,90,90,null,11,null,22,null,null,null,",
+        "105,root.vehicle.d0,99,99,null,11,11.11,22,null,null,null,",
+        "106,root.vehicle.d0,99,99,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d0,22222,22222,null,11,1000.11,22,null,null,null,",
+        
"946684800000,root.vehicle.d0,null,null,null,11,null,22,null,good,null,",
+        "1,root.vehicle.d1,999,999,null,11,null,22,null,null,null,",
+        "1000,root.vehicle.d1,888,888,null,11,null,22,null,null,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s0, s0, s5, \"11\", s2, \"22\", s5, s3, s4 from 
root.vehicle.* group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s0,s5,11,s2,22,s5,s3,s4,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(4));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(6));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(7));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(9));
+        Assert.assertEquals(Types.VARCHAR, 
resultSetMetaData.getColumnType(10));
+        Assert.assertEquals(Types.BOOLEAN, 
resultSetMetaData.getColumnType(11));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectConstantAndNonExistTestShifting3() throws 
ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,101,101,null,11,null,11,22,null,null,null,",
+        "2,root.vehicle.d0,10000,10000,null,11,2.22,11,22,null,null,null,",
+        "3,root.vehicle.d0,null,null,null,11,3.33,11,22,null,null,null,",
+        "4,root.vehicle.d0,null,null,null,11,4.44,11,22,null,null,null,",
+        "50,root.vehicle.d0,10000,10000,null,11,null,11,22,null,null,null,",
+        "60,root.vehicle.d0,null,null,null,11,null,11,22,null,aaaaa,null,",
+        "70,root.vehicle.d0,null,null,null,11,null,11,22,null,bbbbb,null,",
+        "80,root.vehicle.d0,null,null,null,11,null,11,22,null,ccccc,null,",
+        "100,root.vehicle.d0,99,99,null,11,null,11,22,null,null,true,",
+        "101,root.vehicle.d0,99,99,null,11,null,11,22,null,ddddd,null,",
+        "102,root.vehicle.d0,80,80,null,11,10.0,11,22,null,fffff,null,",
+        "103,root.vehicle.d0,99,99,null,11,null,11,22,null,null,null,",
+        "104,root.vehicle.d0,90,90,null,11,null,11,22,null,null,null,",
+        "105,root.vehicle.d0,99,99,null,11,11.11,11,22,null,null,null,",
+        "106,root.vehicle.d0,99,99,null,11,null,11,22,null,null,null,",
+        
"1000,root.vehicle.d0,22222,22222,null,11,1000.11,11,22,null,null,null,",
+        
"946684800000,root.vehicle.d0,null,null,null,11,null,11,22,null,good,null,",
+        "1,root.vehicle.d1,999,999,null,11,null,11,22,null,null,null,",
+        "1000,root.vehicle.d1,888,888,null,11,null,11,22,null,null,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s0, s0, s5, \"11\", s2, \"11\", \"22\", s5, s3, s4 from 
root.vehicle.* group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s0,s0,s5,11,s2,11,22,s5,s3,s4,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(4));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(6));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(7));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(9));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, 
resultSetMetaData.getColumnType(10));
+        Assert.assertEquals(Types.VARCHAR, 
resultSetMetaData.getColumnType(11));
+        Assert.assertEquals(Types.BOOLEAN, 
resultSetMetaData.getColumnType(12));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectConstantAndNonExistTestShifting4() throws 
ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d0,null,101,null,11,null,11,22,null,null,101,",
+        "2,root.vehicle.d0,null,10000,null,11,2.22,11,22,null,null,10000,",
+        "3,root.vehicle.d0,null,null,null,11,3.33,11,22,null,null,null,",
+        "4,root.vehicle.d0,null,null,null,11,4.44,11,22,null,null,null,",
+        "50,root.vehicle.d0,null,10000,null,11,null,11,22,null,null,10000,",
+        "60,root.vehicle.d0,null,null,null,11,null,11,22,null,aaaaa,null,",
+        "70,root.vehicle.d0,null,null,null,11,null,11,22,null,bbbbb,null,",
+        "80,root.vehicle.d0,null,null,null,11,null,11,22,null,ccccc,null,",
+        "100,root.vehicle.d0,null,99,null,11,null,11,22,null,null,99,",
+        "101,root.vehicle.d0,null,99,null,11,null,11,22,null,ddddd,99,",
+        "102,root.vehicle.d0,null,80,null,11,10.0,11,22,null,fffff,80,",
+        "103,root.vehicle.d0,null,99,null,11,null,11,22,null,null,99,",
+        "104,root.vehicle.d0,null,90,null,11,null,11,22,null,null,90,",
+        "105,root.vehicle.d0,null,99,null,11,11.11,11,22,null,null,99,",
+        "106,root.vehicle.d0,null,99,null,11,null,11,22,null,null,99,",
+        
"1000,root.vehicle.d0,null,22222,null,11,1000.11,11,22,null,null,22222,",
+        
"946684800000,root.vehicle.d0,null,null,null,11,null,11,22,null,good,null,",
+        "1,root.vehicle.d1,null,999,null,11,null,11,22,null,null,999,",
+        "1000,root.vehicle.d1,null,888,null,11,null,11,22,null,null,888,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s5, s0, s5, \"11\", s2, \"11\", \"22\", s5, s3, s0 from 
root.vehicle.* group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s5,s0,s5,11,s2,11,22,s5,s3,s0,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(4));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(6));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(7));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(9));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, 
resultSetMetaData.getColumnType(10));
+        Assert.assertEquals(Types.VARCHAR, 
resultSetMetaData.getColumnType(11));
+        Assert.assertEquals(Types.INTEGER, 
resultSetMetaData.getColumnType(12));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void selectConstantAndNonExistTestWithUnorderedDevice() throws 
ClassNotFoundException {
+    String[] retArray = new String[]{
+        "1,root.vehicle.d1,null,999,null,11,null,11,22,null,null,999,",
+        "1000,root.vehicle.d1,null,888,null,11,null,11,22,null,null,888,",
+        "1,root.vehicle.d0,null,101,null,11,null,11,22,null,null,101,",
+        "2,root.vehicle.d0,null,10000,null,11,2.22,11,22,null,null,10000,",
+        "3,root.vehicle.d0,null,null,null,11,3.33,11,22,null,null,null,",
+        "4,root.vehicle.d0,null,null,null,11,4.44,11,22,null,null,null,",
+        "50,root.vehicle.d0,null,10000,null,11,null,11,22,null,null,10000,",
+        "60,root.vehicle.d0,null,null,null,11,null,11,22,null,aaaaa,null,",
+        "70,root.vehicle.d0,null,null,null,11,null,11,22,null,bbbbb,null,",
+        "80,root.vehicle.d0,null,null,null,11,null,11,22,null,ccccc,null,",
+        "100,root.vehicle.d0,null,99,null,11,null,11,22,null,null,99,",
+        "101,root.vehicle.d0,null,99,null,11,null,11,22,null,ddddd,99,",
+        "102,root.vehicle.d0,null,80,null,11,10.0,11,22,null,fffff,80,",
+        "103,root.vehicle.d0,null,99,null,11,null,11,22,null,null,99,",
+        "104,root.vehicle.d0,null,90,null,11,null,11,22,null,null,90,",
+        "105,root.vehicle.d0,null,99,null,11,11.11,11,22,null,null,99,",
+        "106,root.vehicle.d0,null,99,null,11,null,11,22,null,null,99,",
+        
"1000,root.vehicle.d0,null,22222,null,11,1000.11,11,22,null,null,22222,",
+        
"946684800000,root.vehicle.d0,null,null,null,11,null,11,22,null,good,null,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "select s5, s0, s5, \"11\", s2, \"11\", \"22\", s5, s3, s0 from 
root.vehicle.d1, root.vehicle.d0  group by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("Time,Device,s5,s0,s5,11,s2,11,22,s5,s3,s0,", 
header.toString());
+        Assert.assertEquals(Types.TIMESTAMP, 
resultSetMetaData.getColumnType(1));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(2));
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(3));
+        Assert.assertEquals(Types.INTEGER, resultSetMetaData.getColumnType(4));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(5));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(6));
+        Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(7));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(8));
+        // constant column
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(9));
+        // non exist column
+        Assert.assertEquals(Types.VARCHAR, 
resultSetMetaData.getColumnType(10));
+        Assert.assertEquals(Types.VARCHAR, 
resultSetMetaData.getColumnType(11));
+        Assert.assertEquals(Types.INTEGER, 
resultSetMetaData.getColumnType(12));
+
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(19, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
 }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBMultiSeriesIT.java 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBMultiSeriesIT.java
index 27f14e3..b46989b 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBMultiSeriesIT.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBMultiSeriesIT.java
@@ -383,12 +383,17 @@ public class IoTDBMultiSeriesIT {
     try (Connection connection = DriverManager
         .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
         Statement statement = connection.createStatement()) {
-      statement.execute("select s10 from root.vehicle.d0");
-      fail("not throw exception when select unknown time series");
+      statement.execute("select s0, s10 from root.vehicle.*");
+      try (ResultSet resultSet = statement.getResultSet()) {
+        int cnt = 0;
+        while (resultSet.next()) {
+          cnt++;
+        }
+        assertEquals(23400, cnt);
+      }
     } catch (SQLException e) {
-      assertEquals(
-          "Statement format is not right: Path: \"root.vehicle.d0.s10\" 
doesn't correspond to any known time series",
-          e.getMessage());
+      e.printStackTrace();
+      fail();
     }
   }
 
@@ -399,11 +404,11 @@ public class IoTDBMultiSeriesIT {
     try (Connection connection = DriverManager
         .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
         Statement statement = connection.createStatement()) {
-      statement.execute("select s1 from root.vehicle.d0 where s0 < 111 and s10 
< 111");
+      statement.execute("select s0 from root.vehicle.d0 where s10 < 111");
       fail("not throw exception when unknown time series in where clause");
     } catch (SQLException e) {
       assertEquals(
-          "Statement format is not right: Path: \"root.vehicle.d0.s10\" 
doesn't correspond to any known time series",
+          "Statement format is not right: Filter has some time series don't 
correspond to any known time series",
           e.getMessage());
     }
   }
@@ -419,6 +424,7 @@ public class IoTDBMultiSeriesIT {
           "select s1 from root.vehicle.d0 where root.vehicle.d0.s0 < 111 and 
root.vehicle.d0.s10 < 111");
       fail("not throw exception when unknown time series in where clause");
     } catch (SQLException e) {
+      e.printStackTrace();
       assertEquals(
           "Statement format is not right: Path: [root.vehicle.d0.s10] doesn't 
correspond to any known time series",
           e.getMessage());
diff --git a/session/src/main/java/org/apache/iotdb/session/SessionDataSet.java 
b/session/src/main/java/org/apache/iotdb/session/SessionDataSet.java
index 5a2bae2..aeee91e 100644
--- a/session/src/main/java/org/apache/iotdb/session/SessionDataSet.java
+++ b/session/src/main/java/org/apache/iotdb/session/SessionDataSet.java
@@ -18,9 +18,20 @@
  */
 package org.apache.iotdb.session;
 
+import java.nio.ByteBuffer;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import org.apache.iotdb.rpc.IoTDBRPCException;
 import org.apache.iotdb.rpc.RpcUtils;
-import org.apache.iotdb.service.rpc.thrift.*;
+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.read.common.Field;
@@ -29,13 +40,6 @@ import org.apache.iotdb.tsfile.utils.Binary;
 import org.apache.iotdb.tsfile.utils.BytesUtils;
 import org.apache.thrift.TException;
 
-import java.nio.ByteBuffer;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
 public class SessionDataSet {
 
   private boolean hasCachedRecord = false;
@@ -45,6 +49,13 @@ public class SessionDataSet {
   private TSIService.Iface client;
   private int batchSize = 1024;
   private List<String> columnTypeDeduplicatedList;
+  // duplicated column index -> origin index
+  Map<Integer, Integer> duplicateLocation;
+  // column name -> column location
+  Map<String, Integer> columnMap;
+  // column size
+  int columnSize = 0;
+
 
   private int rowsIndex = 0; // used to record the row index in current 
TSQueryDataSet
   private TSQueryDataSet tsQueryDataSet;
@@ -60,14 +71,21 @@ public class SessionDataSet {
     this.queryId = queryId;
     this.client = client;
     currentBitmap = new byte[columnNameList.size()];
+    columnSize = columnNameList.size();
 
     // deduplicate columnTypeList according to columnNameList
     this.columnTypeDeduplicatedList = new ArrayList<>();
-    Set<String> columnSet = new HashSet<>(); // for deduplication
+    // duplicated column index -> origin index
+    duplicateLocation = new HashMap<>();
+    // column name -> column location
+    columnMap = new HashMap<>();
     for (int i = 0; i < columnNameList.size(); i++) {
       String name = columnNameList.get(i);
-      if (!columnSet.contains(name)) {
-        columnSet.add(name);
+      if (columnMap.containsKey(name)) {
+        duplicateLocation.put(i, columnMap.get(name));
+      }
+      else{
+        columnMap.put(name, i);
         columnTypeDeduplicatedList.add(columnTypeList.get(i));
       }
     }
@@ -111,56 +129,65 @@ public class SessionDataSet {
   }
 
   private void constructOneRow() {
-    rowRecord = new RowRecord(tsQueryDataSet.time.getLong());
-
-    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();
-      }
+    List<Field> outFields = new ArrayList<>();
+    int loc = 0;
+    for (int i = 0; i < columnSize; i++) {
       Field field;
-      if (!isNull(i, rowsIndex)) {
-        ByteBuffer valueBuffer = tsQueryDataSet.valueList.get(i);
-        TSDataType dataType = 
TSDataType.valueOf(columnTypeDeduplicatedList.get(i));
-        field = new Field(dataType);
-        switch (dataType) {
-          case BOOLEAN:
-            boolean booleanValue = BytesUtils.byteToBool(valueBuffer.get());
-            field.setBoolV(booleanValue);
-            break;
-          case INT32:
-            int intValue = valueBuffer.getInt();
-            field.setIntV(intValue);
-            break;
-          case INT64:
-            long longValue = valueBuffer.getLong();
-            field.setLongV(longValue);
-            break;
-          case FLOAT:
-            float floatValue = valueBuffer.getFloat();
-            field.setFloatV(floatValue);
-            break;
-          case DOUBLE:
-            double doubleValue = valueBuffer.getDouble();
-            field.setDoubleV(doubleValue);
-            break;
-          case TEXT:
-            int binarySize = valueBuffer.getInt();
-            byte[] binaryValue = new byte[binarySize];
-            valueBuffer.get(binaryValue);
-            field.setBinaryV(new Binary(binaryValue));
-            break;
-          default:
-            throw new UnSupportedDataTypeException(
-                    String.format("Data type %s is not supported.", 
columnTypeDeduplicatedList.get(i)));
+
+      if(duplicateLocation.containsKey(i)){
+        field = Field.copy(outFields.get(duplicateLocation.get(i)));
+      } else {
+        ByteBuffer bitmapBuffer = tsQueryDataSet.bitmapList.get(loc);
+        // another new 8 row, should move the bitmap buffer position to next 
byte
+        if (rowsIndex % 8 == 0) {
+          currentBitmap[loc] = bitmapBuffer.get();
         }
+
+        if(!isNull(loc, rowsIndex)){
+          ByteBuffer valueBuffer = tsQueryDataSet.valueList.get(loc);
+          TSDataType dataType = 
TSDataType.valueOf(columnTypeDeduplicatedList.get(loc));
+          field = new Field(dataType);
+          switch (dataType) {
+            case BOOLEAN:
+              boolean booleanValue = BytesUtils.byteToBool(valueBuffer.get());
+              field.setBoolV(booleanValue);
+              break;
+            case INT32:
+              int intValue = valueBuffer.getInt();
+              field.setIntV(intValue);
+              break;
+            case INT64:
+              long longValue = valueBuffer.getLong();
+              field.setLongV(longValue);
+              break;
+            case FLOAT:
+              float floatValue = valueBuffer.getFloat();
+              field.setFloatV(floatValue);
+              break;
+            case DOUBLE:
+              double doubleValue = valueBuffer.getDouble();
+              field.setDoubleV(doubleValue);
+              break;
+            case TEXT:
+              int binarySize = valueBuffer.getInt();
+              byte[] binaryValue = new byte[binarySize];
+              valueBuffer.get(binaryValue);
+              field.setBinaryV(new Binary(binaryValue));
+              break;
+            default:
+              throw new UnSupportedDataTypeException(
+                  String.format("Data type %s is not supported.", 
columnTypeDeduplicatedList.get(i)));
+          }
+        }
+        else {
+          field = new Field(null);
+        }
+        loc++;
       }
-      else {
-        field = new Field(null);
-      }
-      rowRecord.addField(field);
+      outFields.add(field);
     }
+
+    rowRecord = new RowRecord(tsQueryDataSet.time.getLong(), outFields);
     rowsIndex++;
   }
 
diff --git a/session/src/test/java/org/apache/iotdb/session/IoTDBSessionIT.java 
b/session/src/test/java/org/apache/iotdb/session/IoTDBSessionIT.java
index 842af25..acc936b 100644
--- a/session/src/test/java/org/apache/iotdb/session/IoTDBSessionIT.java
+++ b/session/src/test/java/org/apache/iotdb/session/IoTDBSessionIT.java
@@ -61,6 +61,22 @@ public class IoTDBSessionIT {
     EnvironmentUtils.cleanEnv();
   }
 
+  @Test
+  public void testGroupByDevice()
+      throws IoTDBSessionException, SQLException, ClassNotFoundException, 
TException, IoTDBRPCException {
+    session = new Session("127.0.0.1", 6667, "root", "root");
+    session.open();
+
+    session.setStorageGroup("root.sg1");
+
+    createTimeseries();
+
+    insertRowBatchTest2("root.sg1.d1");
+
+    queryForGroupBy();
+    queryForGroupBy2();
+  }
+
   // it's will output too much to travis, so ignore it
   public void testTime()
       throws IoTDBSessionException, SQLException, ClassNotFoundException, 
TException, IoTDBRPCException {
@@ -395,6 +411,43 @@ public class IoTDBSessionIT {
     }
   }
 
+  private void queryForGroupBy()
+      throws  SQLException, TException, IoTDBRPCException {
+    SessionDataSet sessionDataSet = session.executeQueryStatement("select 
'11', s1, '11' from root.sg1.d1 group by device");
+    sessionDataSet.setBatchSize(1024);
+    int count = 0;
+    while (sessionDataSet.hasNext()) {
+      count++;
+      StringBuilder sb = new StringBuilder();
+      List<Field> fields = sessionDataSet.next().getFields();
+      for (Field f : fields) {
+        sb.append(f.getStringValue()).append(",");
+      }
+      Assert.assertEquals("root.sg1.d1,11,0,11,", sb.toString());
+    }
+    Assert.assertEquals(1000, count);
+    sessionDataSet.closeOperationHandle();
+  }
+
+  private void queryForGroupBy2()
+      throws  SQLException, TException, IoTDBRPCException {
+    SessionDataSet sessionDataSet = session.executeQueryStatement("select 
'11', s1, '11', s5, s1, s5 from root.sg1.d1 group by device");
+    sessionDataSet.setBatchSize(1024);
+    int count = 0;
+    while (sessionDataSet.hasNext()) {
+      count++;
+      StringBuilder sb = new StringBuilder();
+      List<Field> fields = sessionDataSet.next().getFields();
+      for (Field f : fields) {
+        sb.append(f.getStringValue()).append(",");
+      }
+      Assert.assertEquals("root.sg1.d1,11,0,11,null,0,null,", sb.toString());
+    }
+    Assert.assertEquals(1000, count);
+    sessionDataSet.closeOperationHandle();
+  }
+
+
   private void query2() throws ClassNotFoundException, SQLException {
     Class.forName(Config.JDBC_DRIVER_NAME);
     String standard =
diff --git 
a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/Field.java 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/Field.java
index f387528..7e8d98b 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/Field.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/Field.java
@@ -40,6 +40,36 @@ public class Field {
     this.dataType = dataType;
   }
 
+  public static Field copy(Field field){
+    Field out = new Field(field.dataType);
+    if(out.dataType != null) {
+      switch (out.dataType) {
+        case DOUBLE:
+          out.setDoubleV(field.getDoubleV());
+          break;
+        case FLOAT:
+          out.setFloatV(field.getFloatV());
+          break;
+        case INT64:
+          out.setLongV(field.getLongV());
+          break;
+        case INT32:
+          out.setIntV(field.getIntV());
+          break;
+        case BOOLEAN:
+          out.setBoolV(field.getBoolV());
+          break;
+        case TEXT:
+          out.setBinaryV(field.getBinaryV());
+          break;
+        default:
+          throw new UnSupportedDataTypeException("UnSupported: " + 
out.dataType);
+      }
+    }
+
+    return out;
+  }
+
   public TSDataType getDataType() {
     return dataType;
   }
diff --git 
a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/RowRecord.java 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/RowRecord.java
index af49d3f..79e05ad 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/RowRecord.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/RowRecord.java
@@ -31,6 +31,11 @@ public class RowRecord {
     this.fields = new ArrayList<>();
   }
 
+  public RowRecord(long timestamp, List<Field> fields){
+    this.timestamp = timestamp;
+    this.fields = fields;
+  }
+
   public void addField(Field f) {
     this.fields.add(f);
   }

Reply via email to