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

[iotdb] branch rel/0.12 updated: [IOTDB-1540] [To rel/0.12] Bug Fix: 500 when using IN operator (#3658)

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

qiaojialin pushed a commit to branch rel/0.12
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/0.12 by this push:
     new 7cf9d76  [IOTDB-1540] [To rel/0.12] Bug Fix: 500 when using IN operator (#3658)
7cf9d76 is described below

commit 7cf9d76271fcf0b4864f53e8f72b1586d3ce9f0c
Author: liuminghui233 <36...@users.noreply.github.com>
AuthorDate: Tue Aug 10 16:21:50 2021 +0800

    [IOTDB-1540] [To rel/0.12] Bug Fix: 500 when using IN operator (#3658)
---
 .../iotdb/db/qp/logical/crud/InOperator.java       |   4 +
 .../iotdb/db/qp/strategy/PhysicalGenerator.java    |  11 +-
 .../qp/strategy/optimizer/ConcatPathOptimizer.java |  20 +-
 .../org/apache/iotdb/db/integration/IoTDBInIT.java | 255 +++++++++++++++++++++
 4 files changed, 284 insertions(+), 6 deletions(-)

diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InOperator.java
index 096f770..5d2c74b 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InOperator.java
@@ -69,6 +69,10 @@ public class InOperator extends FunctionOperator {
     return values;
   }
 
+  public boolean getNot() {
+    return not;
+  }
+
   @Override
   public void reverseFunc() {
     not = !not;
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 4ddcf85..c9c9d34 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
@@ -32,6 +32,8 @@ import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
 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.FunctionOperator;
+import org.apache.iotdb.db.qp.logical.crud.InOperator;
 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.AlterTimeSeriesOperator;
@@ -833,7 +835,14 @@ public class PhysicalGenerator {
       }
       return;
     }
-    BasicFunctionOperator basicOperator = (BasicFunctionOperator) operator;
+
+    FunctionOperator basicOperator;
+    if (operator instanceof InOperator) {
+      basicOperator = (InOperator) operator;
+    } else {
+      basicOperator = (BasicFunctionOperator) operator;
+    }
+
     PartialPath filterPath = basicOperator.getSinglePath();
 
     // do nothing in the cases of "where time > 5" or "where root.d1.s1 > 5"
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 4752eee..d07292e 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
@@ -30,6 +30,7 @@ import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
 import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
 import org.apache.iotdb.db.qp.logical.crud.FromOperator;
 import org.apache.iotdb.db.qp.logical.crud.FunctionOperator;
+import org.apache.iotdb.db.qp.logical.crud.InOperator;
 import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.SFWOperator;
 import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
@@ -292,11 +293,20 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
         currentNode = newInnerNode;
       }
       try {
-        currentNode.addChildOperator(
-            new BasicFunctionOperator(
-                operator.getTokenIntType(),
-                noStarPaths.get(i),
-                ((BasicFunctionOperator) operator).getValue()));
+        if (operator instanceof InOperator) {
+          currentNode.addChildOperator(
+              new InOperator(
+                  operator.getTokenIntType(),
+                  noStarPaths.get(i),
+                  ((InOperator) operator).getNot(),
+                  ((InOperator) operator).getValues()));
+        } else {
+          currentNode.addChildOperator(
+              new BasicFunctionOperator(
+                  operator.getTokenIntType(),
+                  noStarPaths.get(i),
+                  ((BasicFunctionOperator) operator).getValue()));
+        }
       } catch (SQLParserException e) {
         throw new LogicalOptimizeException(e.getMessage());
       }
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBInIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBInIT.java
new file mode 100644
index 0000000..8add24f
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBInIT.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.integration;
+
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.jdbc.Config;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+
+public class IoTDBInIT {
+
+  private static String[] sqls =
+      new String[] {
+        "set storage group to root.ln",
+        "create timeseries root.sg.d1.s1.qrcode with datatype=TEXT,encoding=PLAIN",
+        "insert into root.sg.d1.s1(timestamp,qrcode) values(1509465600000,\"qrcode001\")",
+        "insert into root.sg.d1.s1(timestamp,qrcode) values(1509465660000,\"qrcode002\")",
+        "insert into root.sg.d1.s1(timestamp,qrcode) values(1509465720000,\"qrcode003\")",
+        "insert into root.sg.d1.s1(timestamp,qrcode) values(1509465780000,\"qrcode004\")",
+        "create timeseries root.sg.d1.s2.qrcode with datatype=TEXT,encoding=PLAIN",
+        "insert into root.sg.d1.s2(timestamp,qrcode) values(1509465720000,\"qrcode002\")",
+        "insert into root.sg.d1.s2(timestamp,qrcode) values(1509465780000,\"qrcode003\")",
+        "insert into root.sg.d1.s2(timestamp,qrcode) values(1509465840000,\"qrcode004\")",
+        "insert into root.sg.d1.s2(timestamp,qrcode) values(1509465900000,\"qrcode005\")",
+        "create timeseries root.sg.d2.s1.qrcode with datatype=TEXT,encoding=PLAIN",
+        "insert into root.sg.d2.s1(timestamp,qrcode) values(1509465780000,\"qrcode002\")",
+        "insert into root.sg.d2.s1(timestamp,qrcode) values(1509465840000,\"qrcode003\")",
+        "insert into root.sg.d2.s1(timestamp,qrcode) values(1509465900000,\"qrcode004\")",
+        "insert into root.sg.d2.s1(timestamp,qrcode) values(1509465960000,\"qrcode005\")"
+      };
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvironmentUtils.closeStatMonitor();
+    EnvironmentUtils.envSetUp();
+
+    importData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvironmentUtils.cleanEnv();
+  }
+
+  private static void importData() 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()) {
+
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  /** Test for IOTDB-1540 */
+  @Test
+  public void selectWithStarTest1() throws ClassNotFoundException {
+    String[] retArray = new String[] {"1509465720000,qrcode003,qrcode002,"};
+
+    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 qrcode from root.sg.d1.* where qrcode in ('qrcode002', 'qrcode003')");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        List<Integer> actualIndexToExpectedIndexList =
+            checkHeader(
+                resultSetMetaData,
+                "Time,root.sg.d1.s1.qrcode,root.sg.d1.s2.qrcode,",
+                new int[] {
+                  Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR,
+                });
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          String[] expectedStrings = retArray[cnt].split(",");
+          StringBuilder expectedBuilder = new StringBuilder();
+          StringBuilder actualBuilder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            actualBuilder.append(resultSet.getString(i)).append(",");
+            expectedBuilder
+                .append(expectedStrings[actualIndexToExpectedIndexList.get(i - 1)])
+                .append(",");
+          }
+          Assert.assertEquals(expectedBuilder.toString(), actualBuilder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  /** Test for IOTDB-1540 */
+  @Test
+  public void selectWithStarTest2() throws ClassNotFoundException {
+    String[] retArray = new String[] {"1509465780000,qrcode004,qrcode003,qrcode002,"};
+
+    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 qrcode from root.sg.*.* where qrcode in ('qrcode002', 'qrcode003', 'qrcode004')");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        List<Integer> actualIndexToExpectedIndexList =
+            checkHeader(
+                resultSetMetaData,
+                "Time,root.sg.d1.s1.qrcode,root.sg.d1.s2.qrcode,root.sg.d2.s1.qrcode,",
+                new int[] {
+                  Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
+                });
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          String[] expectedStrings = retArray[cnt].split(",");
+          StringBuilder expectedBuilder = new StringBuilder();
+          StringBuilder actualBuilder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            actualBuilder.append(resultSet.getString(i)).append(",");
+            expectedBuilder
+                .append(expectedStrings[actualIndexToExpectedIndexList.get(i - 1)])
+                .append(",");
+          }
+          Assert.assertEquals(expectedBuilder.toString(), actualBuilder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  /** Test for IOTDB-1540 */
+  @Test
+  public void selectWithAlignByDeviceTest() throws ClassNotFoundException {
+    String[] retArray =
+        new String[] {
+          "1509465660000,root.sg.d1.s1,qrcode002,",
+          "1509465780000,root.sg.d1.s1,qrcode004,",
+          "1509465720000,root.sg.d1.s2,qrcode002,",
+          "1509465840000,root.sg.d1.s2,qrcode004,",
+          "1509465780000,root.sg.d2.s1,qrcode002,",
+          "1509465900000,root.sg.d2.s1,qrcode004,",
+        };
+
+    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 qrcode from root.sg.*.* where qrcode in ('qrcode002', 'qrcode004') align by device");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        List<Integer> actualIndexToExpectedIndexList =
+            checkHeader(
+                resultSetMetaData,
+                "Time,Device,qrcode,",
+                new int[] {
+                  Types.TIMESTAMP, Types.VARCHAR, Types.VARCHAR,
+                });
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          String[] expectedStrings = retArray[cnt].split(",");
+          StringBuilder expectedBuilder = new StringBuilder();
+          StringBuilder actualBuilder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            actualBuilder.append(resultSet.getString(i)).append(",");
+            expectedBuilder
+                .append(expectedStrings[actualIndexToExpectedIndexList.get(i - 1)])
+                .append(",");
+          }
+          Assert.assertEquals(expectedBuilder.toString(), actualBuilder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(6, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  private List<Integer> checkHeader(
+      ResultSetMetaData resultSetMetaData, String expectedHeaderStrings, int[] expectedTypes)
+      throws SQLException {
+    String[] expectedHeaders = expectedHeaderStrings.split(",");
+    Map<String, Integer> expectedHeaderToTypeIndexMap = new HashMap<>();
+    for (int i = 0; i < expectedHeaders.length; ++i) {
+      expectedHeaderToTypeIndexMap.put(expectedHeaders[i], i);
+    }
+
+    List<Integer> actualIndexToExpectedIndexList = new ArrayList<>();
+    for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+      Integer typeIndex = expectedHeaderToTypeIndexMap.get(resultSetMetaData.getColumnName(i));
+      Assert.assertNotNull(typeIndex);
+      Assert.assertEquals(expectedTypes[typeIndex], resultSetMetaData.getColumnType(i));
+      actualIndexToExpectedIndexList.add(typeIndex);
+    }
+    return actualIndexToExpectedIndexList;
+  }
+}