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

chaow 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 6f67a81  [IOTDB-1453]Fix result set when the server query time 
filtered is And (#3452)
6f67a81 is described below

commit 6f67a81cf418f18f87084fb869db1816ce6e92ec
Author: Hang Ji <[email protected]>
AuthorDate: Wed Jul 7 14:56:20 2021 +0800

    [IOTDB-1453]Fix result set when the server query time filtered is And 
(#3452)
---
 .../cluster/query/fill/ClusterPreviousFill.java    |   2 +-
 .../cluster/server/member/MetaGroupMember.java     |   5 +-
 .../apache/iotdb/cluster/utils/PartitionUtils.java | 237 ---------------------
 .../cluster/server/member/MetaGroupMemberTest.java |   6 +-
 .../iotdb/db/query/executor/QueryRouter.java       |  11 +
 .../apache/iotdb/db/utils/TimeValuePairUtils.java  | 232 ++++++++++++++++++++
 .../db/integration/IoTDBSequenceDataQueryIT.java   |  40 ++++
 7 files changed, 290 insertions(+), 243 deletions(-)

diff --git 
a/cluster/src/main/java/org/apache/iotdb/cluster/query/fill/ClusterPreviousFill.java
 
b/cluster/src/main/java/org/apache/iotdb/cluster/query/fill/ClusterPreviousFill.java
index 08689e7..e0f6053 100644
--- 
a/cluster/src/main/java/org/apache/iotdb/cluster/query/fill/ClusterPreviousFill.java
+++ 
b/cluster/src/main/java/org/apache/iotdb/cluster/query/fill/ClusterPreviousFill.java
@@ -32,12 +32,12 @@ import org.apache.iotdb.cluster.server.RaftServer;
 import org.apache.iotdb.cluster.server.handlers.caller.PreviousFillHandler;
 import org.apache.iotdb.cluster.server.member.DataGroupMember;
 import org.apache.iotdb.cluster.server.member.MetaGroupMember;
-import org.apache.iotdb.cluster.utils.PartitionUtils.Intervals;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.PartialPath;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.executor.fill.PreviousFill;
+import org.apache.iotdb.db.utils.TimeValuePairUtils.Intervals;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
 
diff --git 
a/cluster/src/main/java/org/apache/iotdb/cluster/server/member/MetaGroupMember.java
 
b/cluster/src/main/java/org/apache/iotdb/cluster/server/member/MetaGroupMember.java
index be1fc7d..b78d388 100644
--- 
a/cluster/src/main/java/org/apache/iotdb/cluster/server/member/MetaGroupMember.java
+++ 
b/cluster/src/main/java/org/apache/iotdb/cluster/server/member/MetaGroupMember.java
@@ -83,7 +83,6 @@ import org.apache.iotdb.cluster.server.monitor.Timer;
 import org.apache.iotdb.cluster.utils.ClientUtils;
 import org.apache.iotdb.cluster.utils.ClusterUtils;
 import org.apache.iotdb.cluster.utils.PartitionUtils;
-import org.apache.iotdb.cluster.utils.PartitionUtils.Intervals;
 import org.apache.iotdb.cluster.utils.StatusUtils;
 import org.apache.iotdb.cluster.utils.nodetool.function.Status;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
@@ -96,6 +95,8 @@ import org.apache.iotdb.db.metadata.PartialPath;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.service.IoTDB;
 import org.apache.iotdb.db.utils.TestOnly;
+import org.apache.iotdb.db.utils.TimeValuePairUtils;
+import org.apache.iotdb.db.utils.TimeValuePairUtils.Intervals;
 import org.apache.iotdb.service.rpc.thrift.EndPoint;
 import org.apache.iotdb.service.rpc.thrift.TSStatus;
 import org.apache.iotdb.tsfile.read.filter.basic.Filter;
@@ -1474,7 +1475,7 @@ public class MetaGroupMember extends RaftMember {
    */
   public List<PartitionGroup> routeFilter(Filter filter, PartialPath path)
       throws StorageEngineException, EmptyIntervalException {
-    Intervals intervals = PartitionUtils.extractTimeInterval(filter);
+    Intervals intervals = TimeValuePairUtils.extractTimeInterval(filter);
     if (intervals.isEmpty()) {
       throw new EmptyIntervalException(filter);
     }
diff --git 
a/cluster/src/main/java/org/apache/iotdb/cluster/utils/PartitionUtils.java 
b/cluster/src/main/java/org/apache/iotdb/cluster/utils/PartitionUtils.java
index 85cf424..6c4cf9d 100644
--- a/cluster/src/main/java/org/apache/iotdb/cluster/utils/PartitionUtils.java
+++ b/cluster/src/main/java/org/apache/iotdb/cluster/utils/PartitionUtils.java
@@ -41,21 +41,8 @@ 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.ShowTTLPlan;
 import org.apache.iotdb.service.rpc.thrift.TSStatus;
-import org.apache.iotdb.tsfile.read.filter.GroupByFilter;
-import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeEq;
-import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeGt;
-import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeGtEq;
-import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeIn;
-import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeLt;
-import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeLtEq;
-import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeNotEq;
-import org.apache.iotdb.tsfile.read.filter.basic.Filter;
-import org.apache.iotdb.tsfile.read.filter.operator.AndFilter;
-import org.apache.iotdb.tsfile.read.filter.operator.NotFilter;
-import org.apache.iotdb.tsfile.read.filter.operator.OrFilter;
 import org.apache.iotdb.tsfile.utils.Murmur128Hash;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -154,230 +141,6 @@ public class PartitionUtils {
     }
   }
 
-  public static Intervals extractTimeInterval(Filter filter) {
-    if (filter == null) {
-      return Intervals.ALL_INTERVAL;
-    }
-    // and, or, not, value, time, group by
-    // eq, neq, gt, gteq, lt, lteq, in
-    if (filter instanceof AndFilter) {
-      AndFilter andFilter = ((AndFilter) filter);
-      Intervals leftIntervals = extractTimeInterval(andFilter.getLeft());
-      Intervals rightIntervals = extractTimeInterval(andFilter.getRight());
-      return leftIntervals.intersection(rightIntervals);
-    } else if (filter instanceof OrFilter) {
-      OrFilter orFilter = ((OrFilter) filter);
-      Intervals leftIntervals = extractTimeInterval(orFilter.getLeft());
-      Intervals rightIntervals = extractTimeInterval(orFilter.getRight());
-      return leftIntervals.union(rightIntervals);
-    } else if (filter instanceof NotFilter) {
-      NotFilter notFilter = ((NotFilter) filter);
-      return extractTimeInterval(notFilter.getFilter()).not();
-    } else if (filter instanceof TimeGt) {
-      TimeGt timeGt = ((TimeGt) filter);
-      return new Intervals(((long) timeGt.getValue()) + 1, Long.MAX_VALUE);
-    } else if (filter instanceof TimeGtEq) {
-      TimeGtEq timeGtEq = ((TimeGtEq) filter);
-      return new Intervals(((long) timeGtEq.getValue()), Long.MAX_VALUE);
-    } else if (filter instanceof TimeEq) {
-      TimeEq timeEq = ((TimeEq) filter);
-      return new Intervals(((long) timeEq.getValue()), ((long) 
timeEq.getValue()));
-    } else if (filter instanceof TimeNotEq) {
-      TimeNotEq timeNotEq = ((TimeNotEq) filter);
-      Intervals intervals = new Intervals();
-      intervals.addInterval(Long.MIN_VALUE, (long) timeNotEq.getValue() - 1);
-      intervals.addInterval((long) timeNotEq.getValue() + 1, Long.MAX_VALUE);
-      return intervals;
-    } else if (filter instanceof TimeLt) {
-      TimeLt timeLt = ((TimeLt) filter);
-      return new Intervals(Long.MIN_VALUE, (long) timeLt.getValue() - 1);
-    } else if (filter instanceof TimeLtEq) {
-      TimeLtEq timeLtEq = ((TimeLtEq) filter);
-      return new Intervals(Long.MIN_VALUE, (long) timeLtEq.getValue());
-    } else if (filter instanceof TimeIn) {
-      TimeIn timeIn = ((TimeIn) filter);
-      Intervals intervals = new Intervals();
-      for (Object value : timeIn.getValues()) {
-        long time = ((long) value);
-        intervals.addInterval(time, time);
-      }
-      return intervals;
-    } else if (filter instanceof GroupByFilter) {
-      GroupByFilter groupByFilter = ((GroupByFilter) filter);
-      return new Intervals(groupByFilter.getStartTime(), 
groupByFilter.getEndTime() + 1);
-    }
-    // value filter
-    return Intervals.ALL_INTERVAL;
-  }
-
-  /** All intervals are closed. */
-  public static class Intervals extends ArrayList<Long> {
-
-    static final Intervals ALL_INTERVAL = new Intervals(Long.MIN_VALUE, 
Long.MAX_VALUE);
-
-    public Intervals() {
-      super();
-    }
-
-    Intervals(long lowerBound, long upperBound) {
-      super();
-      addInterval(lowerBound, upperBound);
-    }
-
-    public int getIntervalSize() {
-      return size() / 2;
-    }
-
-    public long getLowerBound(int index) {
-      return get(index * 2);
-    }
-
-    public long getUpperBound(int index) {
-      return get(index * 2 + 1);
-    }
-
-    void setLowerBound(int index, long lb) {
-      set(index * 2, lb);
-    }
-
-    void setUpperBound(int index, long ub) {
-      set(index * 2 + 1, ub);
-    }
-
-    public void addInterval(long lowerBound, long upperBound) {
-      add(lowerBound);
-      add(upperBound);
-    }
-
-    Intervals intersection(Intervals that) {
-      Intervals result = new Intervals();
-      int thisSize = this.getIntervalSize();
-      int thatSize = that.getIntervalSize();
-      for (int i = 0; i < thisSize; i++) {
-        for (int j = 0; j < thatSize; j++) {
-          long thisLB = this.getLowerBound(i);
-          long thisUB = this.getUpperBound(i);
-          long thatLB = that.getLowerBound(i);
-          long thatUB = that.getUpperBound(i);
-          if (thisUB >= thatLB) {
-            if (thisUB <= thatUB) {
-              result.addInterval(Math.max(thisLB, thatLB), thisUB);
-            } else if (thisLB <= thatUB) {
-              result.addInterval(Math.max(thisLB, thatLB), thatUB);
-            }
-          }
-        }
-      }
-      return result;
-    }
-
-    /**
-     * The union is implemented by merge, so the two intervals must be ordered.
-     *
-     * @param that
-     * @return
-     */
-    Intervals union(Intervals that) {
-      if (this.isEmpty()) {
-        return that;
-      } else if (that.isEmpty()) {
-        return this;
-      }
-      Intervals result = new Intervals();
-
-      int thisSize = this.getIntervalSize();
-      int thatSize = that.getIntervalSize();
-      int thisIndex = 0;
-      int thatIndex = 0;
-      // merge the heads of the two intervals
-      while (thisIndex < thisSize && thatIndex < thatSize) {
-        long thisLB = this.getLowerBound(thisIndex);
-        long thisUB = this.getUpperBound(thisIndex);
-        long thatLB = that.getLowerBound(thatIndex);
-        long thatUB = that.getUpperBound(thatIndex);
-        if (thisLB <= thatLB) {
-          result.mergeLast(thisLB, thisUB);
-          thisIndex++;
-        } else {
-          result.mergeLast(thatLB, thatUB);
-          thatIndex++;
-        }
-      }
-      // merge the remaining intervals
-      Intervals remainingIntervals = thisIndex < thisSize ? this : that;
-      int remainingIndex = thisIndex < thisSize ? thisIndex : thatIndex;
-      mergeRemainingIntervals(remainingIndex, remainingIntervals, result);
-
-      return result;
-    }
-
-    private void mergeRemainingIntervals(
-        int remainingIndex, Intervals remainingIntervals, Intervals result) {
-      for (int i = remainingIndex; i < remainingIntervals.getIntervalSize(); 
i++) {
-        long lb = remainingIntervals.getLowerBound(i);
-        long ub = remainingIntervals.getUpperBound(i);
-        result.mergeLast(lb, ub);
-      }
-    }
-
-    /**
-     * Merge an interval of [lowerBound, upperBound] with the last interval if 
they can be merged,
-     * or just add it as the last interval if its lowerBound is larger than 
the upperBound of the
-     * last interval. If the upperBound of the new interval is less than the 
lowerBound of the last
-     * interval, nothing will be done.
-     *
-     * @param lowerBound
-     * @param upperBound
-     */
-    private void mergeLast(long lowerBound, long upperBound) {
-      if (getIntervalSize() == 0) {
-        addInterval(lowerBound, upperBound);
-        return;
-      }
-      int lastIndex = getIntervalSize() - 1;
-      long lastLB = getLowerBound(lastIndex);
-      long lastUB = getUpperBound(lastIndex);
-      if (lowerBound > lastUB + 1) {
-        // e.g., last [3, 5], new [7, 10], just add the new interval
-        addInterval(lowerBound, upperBound);
-        return;
-      }
-      if (upperBound < lastLB - 1) {
-        // e.g., last [7, 10], new [3, 5], do nothing
-        return;
-      }
-      // merge the new interval into the last one
-      setLowerBound(lastIndex, Math.min(lastLB, lowerBound));
-      setUpperBound(lastIndex, Math.max(lastUB, upperBound));
-    }
-
-    public Intervals not() {
-      if (isEmpty()) {
-        return ALL_INTERVAL;
-      }
-      Intervals result = new Intervals();
-      long firstLB = getLowerBound(0);
-      if (firstLB != Long.MIN_VALUE) {
-        result.addInterval(Long.MIN_VALUE, firstLB - 1);
-      }
-
-      int intervalSize = getIntervalSize();
-      for (int i = 0; i < intervalSize - 1; i++) {
-        long currentUB = getUpperBound(i);
-        long nextLB = getLowerBound(i + 1);
-        if (currentUB + 1 <= nextLB - 1) {
-          result.addInterval(currentUB + 1, nextLB - 1);
-        }
-      }
-
-      long lastUB = getUpperBound(result.getIntervalSize() - 1);
-      if (lastUB != Long.MAX_VALUE) {
-        result.addInterval(lastUB + 1, Long.MAX_VALUE);
-      }
-      return result;
-    }
-  }
-
   /**
    * Calculate the headers of the groups that possibly store the data of a 
timeseries over the given
    * time range.
diff --git 
a/cluster/src/test/java/org/apache/iotdb/cluster/server/member/MetaGroupMemberTest.java
 
b/cluster/src/test/java/org/apache/iotdb/cluster/server/member/MetaGroupMemberTest.java
index e0a28fe..88ada81 100644
--- 
a/cluster/src/test/java/org/apache/iotdb/cluster/server/member/MetaGroupMemberTest.java
+++ 
b/cluster/src/test/java/org/apache/iotdb/cluster/server/member/MetaGroupMemberTest.java
@@ -74,7 +74,6 @@ import 
org.apache.iotdb.cluster.server.monitor.NodeStatusManager;
 import org.apache.iotdb.cluster.server.service.MetaAsyncService;
 import org.apache.iotdb.cluster.utils.ClusterUtils;
 import org.apache.iotdb.cluster.utils.Constants;
-import org.apache.iotdb.cluster.utils.PartitionUtils;
 import org.apache.iotdb.cluster.utils.StatusUtils;
 import org.apache.iotdb.db.auth.AuthException;
 import org.apache.iotdb.db.auth.authorizer.IAuthorizer;
@@ -100,6 +99,7 @@ import 
org.apache.iotdb.db.query.control.QueryResourceManager;
 import org.apache.iotdb.db.query.reader.series.IReaderByTimestamp;
 import org.apache.iotdb.db.query.reader.series.ManagedSeriesReader;
 import org.apache.iotdb.db.service.IoTDB;
+import org.apache.iotdb.db.utils.TimeValuePairUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 import org.apache.iotdb.service.rpc.thrift.TSStatus;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -1379,7 +1379,7 @@ public class MetaGroupMemberTest extends BaseMember {
     StorageEngine.setEnablePartition(false);
     testMetaMember.setCharacter(LEADER);
     testMetaMember.setLeader(testMetaMember.getThisNode());
-    PartitionUtils.Intervals intervals = new PartitionUtils.Intervals();
+    TimeValuePairUtils.Intervals intervals = new 
TimeValuePairUtils.Intervals();
     intervals.addInterval(Long.MIN_VALUE, Long.MAX_VALUE);
 
     List<PartitionGroup> partitionGroups =
@@ -1395,7 +1395,7 @@ public class MetaGroupMemberTest extends BaseMember {
     StorageEngine.setEnablePartition(true);
     testMetaMember.setCharacter(LEADER);
     testMetaMember.setLeader(testMetaMember.getThisNode());
-    PartitionUtils.Intervals intervals = new PartitionUtils.Intervals();
+    TimeValuePairUtils.Intervals intervals = new 
TimeValuePairUtils.Intervals();
     intervals.addInterval(Long.MIN_VALUE, Long.MAX_VALUE);
 
     List<PartitionGroup> partitionGroups =
diff --git 
a/server/src/main/java/org/apache/iotdb/db/query/executor/QueryRouter.java 
b/server/src/main/java/org/apache/iotdb/db/query/executor/QueryRouter.java
index 29254e7..6c53102 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/executor/QueryRouter.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/executor/QueryRouter.java
@@ -38,6 +38,7 @@ import 
org.apache.iotdb.db.query.dataset.groupby.GroupByWithValueFilterDataSet;
 import 
org.apache.iotdb.db.query.dataset.groupby.GroupByWithoutValueFilterDataSet;
 import org.apache.iotdb.db.query.executor.fill.IFill;
 import org.apache.iotdb.db.service.IoTDB;
+import org.apache.iotdb.db.utils.TimeValuePairUtils;
 import 
org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.read.expression.ExpressionType;
@@ -47,6 +48,8 @@ import 
org.apache.iotdb.tsfile.read.expression.impl.GlobalTimeExpression;
 import org.apache.iotdb.tsfile.read.expression.util.ExpressionOptimizer;
 import org.apache.iotdb.tsfile.read.filter.GroupByFilter;
 import org.apache.iotdb.tsfile.read.filter.GroupByMonthFilter;
+import org.apache.iotdb.tsfile.read.filter.basic.Filter;
+import org.apache.iotdb.tsfile.read.query.dataset.EmptyDataSet;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 
 import org.slf4j.Logger;
@@ -97,6 +100,14 @@ public class QueryRouter implements IQueryRouter {
         throw new QueryProcessException(e);
       }
       return rawDataQueryExecutor.executeWithValueFilter(context);
+    } else if (optimizedExpression != null
+        && optimizedExpression.getType() == ExpressionType.GLOBAL_TIME) {
+      Filter timeFilter = ((GlobalTimeExpression) 
queryPlan.getExpression()).getFilter();
+      TimeValuePairUtils.Intervals intervals = 
TimeValuePairUtils.extractTimeInterval(timeFilter);
+      if (intervals.isEmpty()) {
+        logger.warn("The interval of the filter {} is empty.", timeFilter);
+        return new EmptyDataSet();
+      }
     }
 
     // Currently, we only group the vector partial paths for raw query without 
value filter
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/TimeValuePairUtils.java 
b/server/src/main/java/org/apache/iotdb/db/utils/TimeValuePairUtils.java
index ba560a6..1df6be0 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/TimeValuePairUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/TimeValuePairUtils.java
@@ -22,6 +22,12 @@ import 
org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
 import org.apache.iotdb.tsfile.read.common.BatchData;
+import org.apache.iotdb.tsfile.read.filter.GroupByFilter;
+import org.apache.iotdb.tsfile.read.filter.TimeFilter;
+import org.apache.iotdb.tsfile.read.filter.basic.Filter;
+import org.apache.iotdb.tsfile.read.filter.operator.AndFilter;
+import org.apache.iotdb.tsfile.read.filter.operator.NotFilter;
+import org.apache.iotdb.tsfile.read.filter.operator.OrFilter;
 import org.apache.iotdb.tsfile.utils.Binary;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType.TsBinary;
@@ -31,6 +37,8 @@ import org.apache.iotdb.tsfile.utils.TsPrimitiveType.TsFloat;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType.TsInt;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType.TsLong;
 
+import java.util.ArrayList;
+
 public class TimeValuePairUtils {
 
   private TimeValuePairUtils() {}
@@ -107,4 +115,228 @@ public class TimeValuePairUtils {
         throw new UnsupportedOperationException("Unrecognized datatype: " + 
dataType);
     }
   }
+
+  public static Intervals extractTimeInterval(Filter filter) {
+    if (filter == null) {
+      return Intervals.ALL_INTERVAL;
+    }
+    // and, or, not, value, time, group by
+    // eq, neq, gt, gteq, lt, lteq, in
+    if (filter instanceof AndFilter) {
+      AndFilter andFilter = ((AndFilter) filter);
+      Intervals leftIntervals = extractTimeInterval(andFilter.getLeft());
+      Intervals rightIntervals = extractTimeInterval(andFilter.getRight());
+      return leftIntervals.intersection(rightIntervals);
+    } else if (filter instanceof OrFilter) {
+      OrFilter orFilter = ((OrFilter) filter);
+      Intervals leftIntervals = extractTimeInterval(orFilter.getLeft());
+      Intervals rightIntervals = extractTimeInterval(orFilter.getRight());
+      return leftIntervals.union(rightIntervals);
+    } else if (filter instanceof NotFilter) {
+      NotFilter notFilter = ((NotFilter) filter);
+      return extractTimeInterval(notFilter.getFilter()).not();
+    } else if (filter instanceof TimeFilter.TimeGt) {
+      TimeFilter.TimeGt timeGt = ((TimeFilter.TimeGt) filter);
+      return new Intervals(((long) timeGt.getValue()) + 1, Long.MAX_VALUE);
+    } else if (filter instanceof TimeFilter.TimeGtEq) {
+      TimeFilter.TimeGtEq timeGtEq = ((TimeFilter.TimeGtEq) filter);
+      return new Intervals(((long) timeGtEq.getValue()), Long.MAX_VALUE);
+    } else if (filter instanceof TimeFilter.TimeEq) {
+      TimeFilter.TimeEq timeEq = ((TimeFilter.TimeEq) filter);
+      return new Intervals(((long) timeEq.getValue()), ((long) 
timeEq.getValue()));
+    } else if (filter instanceof TimeFilter.TimeNotEq) {
+      TimeFilter.TimeNotEq timeNotEq = ((TimeFilter.TimeNotEq) filter);
+      Intervals intervals = new Intervals();
+      intervals.addInterval(Long.MIN_VALUE, (long) timeNotEq.getValue() - 1);
+      intervals.addInterval((long) timeNotEq.getValue() + 1, Long.MAX_VALUE);
+      return intervals;
+    } else if (filter instanceof TimeFilter.TimeLt) {
+      TimeFilter.TimeLt timeLt = ((TimeFilter.TimeLt) filter);
+      return new Intervals(Long.MIN_VALUE, (long) timeLt.getValue() - 1);
+    } else if (filter instanceof TimeFilter.TimeLtEq) {
+      TimeFilter.TimeLtEq timeLtEq = ((TimeFilter.TimeLtEq) filter);
+      return new Intervals(Long.MIN_VALUE, (long) timeLtEq.getValue());
+    } else if (filter instanceof TimeFilter.TimeIn) {
+      TimeFilter.TimeIn timeIn = ((TimeFilter.TimeIn) filter);
+      Intervals intervals = new Intervals();
+      for (Object value : timeIn.getValues()) {
+        long time = ((long) value);
+        intervals.addInterval(time, time);
+      }
+      return intervals;
+    } else if (filter instanceof GroupByFilter) {
+      GroupByFilter groupByFilter = ((GroupByFilter) filter);
+      return new Intervals(groupByFilter.getStartTime(), 
groupByFilter.getEndTime() + 1);
+    }
+    // value filter
+    return Intervals.ALL_INTERVAL;
+  }
+
+  /** All intervals are closed. */
+  public static class Intervals extends ArrayList<Long> {
+
+    static final Intervals ALL_INTERVAL = new Intervals(Long.MIN_VALUE, 
Long.MAX_VALUE);
+
+    public Intervals() {
+      super();
+    }
+
+    Intervals(long lowerBound, long upperBound) {
+      super();
+      addInterval(lowerBound, upperBound);
+    }
+
+    public int getIntervalSize() {
+      return size() / 2;
+    }
+
+    public long getLowerBound(int index) {
+      return get(index * 2);
+    }
+
+    public long getUpperBound(int index) {
+      return get(index * 2 + 1);
+    }
+
+    void setLowerBound(int index, long lb) {
+      set(index * 2, lb);
+    }
+
+    void setUpperBound(int index, long ub) {
+      set(index * 2 + 1, ub);
+    }
+
+    public void addInterval(long lowerBound, long upperBound) {
+      add(lowerBound);
+      add(upperBound);
+    }
+
+    Intervals intersection(Intervals that) {
+      Intervals result = new Intervals();
+      int thisSize = this.getIntervalSize();
+      int thatSize = that.getIntervalSize();
+      for (int i = 0; i < thisSize; i++) {
+        for (int j = 0; j < thatSize; j++) {
+          long thisLB = this.getLowerBound(i);
+          long thisUB = this.getUpperBound(i);
+          long thatLB = that.getLowerBound(i);
+          long thatUB = that.getUpperBound(i);
+          if (thisUB >= thatLB) {
+            if (thisUB <= thatUB) {
+              result.addInterval(Math.max(thisLB, thatLB), thisUB);
+            } else if (thisLB <= thatUB) {
+              result.addInterval(Math.max(thisLB, thatLB), thatUB);
+            }
+          }
+        }
+      }
+      return result;
+    }
+
+    /**
+     * The union is implemented by merge, so the two intervals must be ordered.
+     *
+     * @param that
+     * @return
+     */
+    Intervals union(Intervals that) {
+      if (this.isEmpty()) {
+        return that;
+      } else if (that.isEmpty()) {
+        return this;
+      }
+      Intervals result = new Intervals();
+
+      int thisSize = this.getIntervalSize();
+      int thatSize = that.getIntervalSize();
+      int thisIndex = 0;
+      int thatIndex = 0;
+      // merge the heads of the two intervals
+      while (thisIndex < thisSize && thatIndex < thatSize) {
+        long thisLB = this.getLowerBound(thisIndex);
+        long thisUB = this.getUpperBound(thisIndex);
+        long thatLB = that.getLowerBound(thatIndex);
+        long thatUB = that.getUpperBound(thatIndex);
+        if (thisLB <= thatLB) {
+          result.mergeLast(thisLB, thisUB);
+          thisIndex++;
+        } else {
+          result.mergeLast(thatLB, thatUB);
+          thatIndex++;
+        }
+      }
+      // merge the remaining intervals
+      Intervals remainingIntervals = thisIndex < thisSize ? this : that;
+      int remainingIndex = thisIndex < thisSize ? thisIndex : thatIndex;
+      mergeRemainingIntervals(remainingIndex, remainingIntervals, result);
+
+      return result;
+    }
+
+    private void mergeRemainingIntervals(
+        int remainingIndex, Intervals remainingIntervals, Intervals result) {
+      for (int i = remainingIndex; i < remainingIntervals.getIntervalSize(); 
i++) {
+        long lb = remainingIntervals.getLowerBound(i);
+        long ub = remainingIntervals.getUpperBound(i);
+        result.mergeLast(lb, ub);
+      }
+    }
+
+    /**
+     * Merge an interval of [lowerBound, upperBound] with the last interval if 
they can be merged,
+     * or just add it as the last interval if its lowerBound is larger than 
the upperBound of the
+     * last interval. If the upperBound of the new interval is less than the 
lowerBound of the last
+     * interval, nothing will be done.
+     *
+     * @param lowerBound
+     * @param upperBound
+     */
+    private void mergeLast(long lowerBound, long upperBound) {
+      if (getIntervalSize() == 0) {
+        addInterval(lowerBound, upperBound);
+        return;
+      }
+      int lastIndex = getIntervalSize() - 1;
+      long lastLB = getLowerBound(lastIndex);
+      long lastUB = getUpperBound(lastIndex);
+      if (lowerBound > lastUB + 1) {
+        // e.g., last [3, 5], new [7, 10], just add the new interval
+        addInterval(lowerBound, upperBound);
+        return;
+      }
+      if (upperBound < lastLB - 1) {
+        // e.g., last [7, 10], new [3, 5], do nothing
+        return;
+      }
+      // merge the new interval into the last one
+      setLowerBound(lastIndex, Math.min(lastLB, lowerBound));
+      setUpperBound(lastIndex, Math.max(lastUB, upperBound));
+    }
+
+    public Intervals not() {
+      if (isEmpty()) {
+        return ALL_INTERVAL;
+      }
+      Intervals result = new Intervals();
+      long firstLB = getLowerBound(0);
+      if (firstLB != Long.MIN_VALUE) {
+        result.addInterval(Long.MIN_VALUE, firstLB - 1);
+      }
+
+      int intervalSize = getIntervalSize();
+      for (int i = 0; i < intervalSize - 1; i++) {
+        long currentUB = getUpperBound(i);
+        long nextLB = getLowerBound(i + 1);
+        if (currentUB + 1 <= nextLB - 1) {
+          result.addInterval(currentUB + 1, nextLB - 1);
+        }
+      }
+
+      long lastUB = getUpperBound(result.getIntervalSize() - 1);
+      if (lastUB != Long.MAX_VALUE) {
+        result.addInterval(lastUB + 1, Long.MAX_VALUE);
+      }
+      return result;
+    }
+  }
 }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSequenceDataQueryIT.java
 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSequenceDataQueryIT.java
index 2c69a52..2fc4977 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSequenceDataQueryIT.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSequenceDataQueryIT.java
@@ -40,6 +40,7 @@ import 
org.apache.iotdb.tsfile.read.expression.impl.GlobalTimeExpression;
 import org.apache.iotdb.tsfile.read.expression.impl.SingleSeriesExpression;
 import org.apache.iotdb.tsfile.read.filter.TimeFilter;
 import org.apache.iotdb.tsfile.read.filter.ValueFilter;
+import org.apache.iotdb.tsfile.read.filter.operator.AndFilter;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 
 import org.junit.AfterClass;
@@ -316,4 +317,43 @@ public class IoTDBSequenceDataQueryIT {
 
     QueryResourceManager.getInstance().endQuery(TEST_QUERY_JOB_ID);
   }
+
+  @Test
+  public void readIncorrectTimeFilterTest()
+      throws IllegalPathException, QueryProcessException, 
StorageEngineException, IOException {
+
+    QueryRouter queryRouter = new QueryRouter();
+    List<PartialPath> pathList = new ArrayList<>();
+    List<TSDataType> dataTypes = new ArrayList<>();
+    pathList.add(
+        new PartialPath(TestConstant.d0 + TsFileConstant.PATH_SEPARATOR + 
TestConstant.s0));
+    dataTypes.add(TSDataType.INT32);
+    pathList.add(
+        new PartialPath(TestConstant.d1 + TsFileConstant.PATH_SEPARATOR + 
TestConstant.s0));
+    dataTypes.add(TSDataType.INT32);
+
+    TimeFilter.TimeGt gtRight = TimeFilter.gt(10L);
+    TimeFilter.TimeLt ltLeft = TimeFilter.lt(5L);
+    AndFilter andFilter = new AndFilter(ltLeft, gtRight);
+
+    GlobalTimeExpression globalTimeExpression = new 
GlobalTimeExpression(andFilter);
+    TEST_QUERY_JOB_ID =
+        QueryResourceManager.getInstance().assignQueryId(true, 1024, 
pathList.size());
+    TEST_QUERY_CONTEXT = new QueryContext(TEST_QUERY_JOB_ID);
+
+    RawDataQueryPlan queryPlan = new RawDataQueryPlan();
+    queryPlan.setDeduplicatedDataTypes(dataTypes);
+    queryPlan.setDeduplicatedPathsAndUpdate(pathList);
+    queryPlan.setExpression(globalTimeExpression);
+    QueryDataSet queryDataSet = queryRouter.rawDataQuery(queryPlan, 
TEST_QUERY_CONTEXT);
+
+    int cnt = 0;
+    while (queryDataSet.hasNext()) {
+      queryDataSet.next();
+      cnt++;
+    }
+    assertEquals(0, cnt);
+
+    QueryResourceManager.getInstance().endQuery(TEST_QUERY_JOB_ID);
+  }
 }

Reply via email to