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 5cb248b  IOTDB-734 Add Support for NaN in Double / Floats in SQL 
Syntax. (#1305)
5cb248b is described below

commit 5cb248b004e1922d86f723e96a3fde456fe67b81
Author: Julian <[email protected]>
AuthorDate: Tue Jun 9 05:24:56 2020 +0200

    IOTDB-734 Add Support for NaN in Double / Floats in SQL Syntax. (#1305)
    
    * IOTDB-734 Add Support for NaN in Double / Floats in SQL Syntax.
---
 docs/UserGuide/Server/Config Manual.md             |  55 ++++++++
 docs/zh/UserGuide/Server/Config Manual.md          |  58 +++++++++
 .../resources/conf/iotdb-engine.properties         |   3 +
 .../org/apache/iotdb/db/qp/strategy/SqlBase.g4     |   4 +
 .../java/org/apache/iotdb/db/conf/IoTDBConfig.java |  18 +++
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |   2 +
 .../apache/iotdb/db/utils/TypeInferenceUtils.java  |   6 +-
 .../iotdb/db/integration/IoTDBInsertNaNIT.java     | 139 +++++++++++++++++++++
 .../java/org/apache/iotdb/db/qp/PlannerTest.java   |  13 ++
 9 files changed, 297 insertions(+), 1 deletion(-)

diff --git a/docs/UserGuide/Server/Config Manual.md 
b/docs/UserGuide/Server/Config Manual.md
index a436d35..6046275 100644
--- a/docs/UserGuide/Server/Config Manual.md    
+++ b/docs/UserGuide/Server/Config Manual.md    
@@ -582,6 +582,61 @@ The permission definitions are in 
${IOTDB\_CONF}/conf/jmx.access.
 |Default|no |
 |Effective|After restart system|
 
+## Automatic Schema Creation and Type Inference
+
+* enable\_auto\_create\_schema
+
+|Name| enable\_auto\_create\_schema |
+|:---:|:---|
+|Description| whether auto create the time series when a non-existed time 
series data comes|
+|Type| true or false |
+|Default|true |
+|Effective|After restart system|
+
+* default\_storage\_group\_level
+
+|Name| default\_storage\_group\_level |
+|:---:|:---|
+|Description| Storage group level when creating schema automatically is 
enabled. For example, if we receives a data point from root.sg0.d1.s2, we will 
set root.sg0 as the storage group if storage group level is 1. (root is level 
0)|
+|Type| integer |
+|Default|1 |
+|Effective|After restart system|
+
+* boolean\_string\_infer\_type
+
+|Name| boolean\_string\_infer\_type |
+|:---:|:---|
+|Description| To which type the values "true" and "false" should be reslved|
+|Type| BOOLEAN or TEXT |
+|Default|BOOLEAN |
+|Effective|After restart system|
+
+* integer\_string\_infer\_type
+
+|Name| integer\_string\_infer\_type |
+|:---:|:---|
+|Description| To which type an integer string like "67" in a query should be 
resolved|
+|Type| INT32, INT64, DOUBLE, FLOAT or TEXT |
+|Default|DOUBLE |
+|Effective|After restart system|
+
+* nan\_string\_infer\_type
+
+|Name| nan\_string\_infer\_type |
+|:---:|:---|
+|Description| To which type the value NaN in a query should be resolved|
+|Type| DOUBLE, FLOAT or TEXT |
+|Default|FLOAT |
+|Effective|After restart system|
+
+* floating\_string\_infer\_type
+
+|Name| floating\_string\_infer\_type |
+|:---:|:---|
+|Description| To which type a floating number string like "6.7" in a query 
should be resolved|
+|Type| DOUBLE, FLOAT or TEXT |
+|Default|FLOAT |
+|Effective|After restart system|
 
 ## Enable GC log
 GC log is off by default.
diff --git a/docs/zh/UserGuide/Server/Config Manual.md 
b/docs/zh/UserGuide/Server/Config Manual.md
index 227df61..6c53b6c 100644
--- a/docs/zh/UserGuide/Server/Config Manual.md 
+++ b/docs/zh/UserGuide/Server/Config Manual.md 
@@ -528,6 +528,64 @@
 |改后生效方式|重启服务器生效|
 
 
+## 数据类型自动推断
+
+
+* enable\_auto\_create\_schema
+
+|名字| enable\_auto\_create\_schema |
+|:---:|:---|
+|描述| 当写入的序列不存在时,是否自动创建序列到Schema|
+|取值| true or false |
+|默认值|true |
+|改后生效方式|重启服务器生效|
+
+* default\_storage\_group\_level
+
+|名字| default\_storage\_group\_level |
+|:---:|:---|
+|描述| 当写入的数据不存在且自动创建序列时,若需要创建相应的存储组,将序列路径的哪一层当做存储组. 例如, 如果我们接到一个新序列 
root.sg0.d1.s2, 并且level=1, 那么root.sg0被视为存储组(因为root是level 0 层)|
+|取值| 整数 |
+|默认值|1 |
+|改后生效方式|重启服务器生效|
+
+* boolean\_string\_infer\_type
+
+|名字| boolean\_string\_infer\_type |
+|:---:|:---|
+|描述|  "true" 或者 "false" 被视为什么数据|
+|取值| BOOLEAN 或者 TEXT |
+|默认值|BOOLEAN |
+|改后生效方式|重启服务器生效|
+
+* integer\_string\_infer\_type
+
+|名字| integer\_string\_infer\_type |
+|:---:|:---|
+|描述| 整数型数据被推断成什么 |
+|取值| INT32, INT64, FLOAT, DOUBLE, TEXT |
+|默认值|FLOAT |
+|改后生效方式|重启服务器生效|
+
+* nan\_string\_infer\_type
+
+|名字| nan\_string\_infer\_type |
+|:---:|:---|
+|描述| NaN 字符串被推断为什么|
+|取值| DOUBLE, FLOAT or TEXT |
+|默认值|FLOAT |
+|改后生效方式|重启服务器生效|
+
+* floating\_string\_infer\_type
+
+|名字| floating\_string\_infer\_type |
+|:---:|:---|
+|描述| "6.7"等浮点数被推断为什么|
+|取值| DOUBLE, FLOAT or TEXT |
+|默认值|FLOAT |
+|改后生效方式|重启服务器生效|
+
+
 ## 开启GC日志
 GC日志默认是关闭的。为了性能调优,用户可能会需要手机GC信息。
 若要打开GC日志,则需要在启动IoTDB Server的时候加上"printgc"参数:
diff --git a/server/src/assembly/resources/conf/iotdb-engine.properties 
b/server/src/assembly/resources/conf/iotdb-engine.properties
index ea78585..bb78b41 100644
--- a/server/src/assembly/resources/conf/iotdb-engine.properties
+++ b/server/src/assembly/resources/conf/iotdb-engine.properties
@@ -398,6 +398,9 @@ integer_string_infer_type=FLOAT
 # register time series as which type when receiving a floating number string 
"6.7"
 floating_string_infer_type=FLOAT
 
+# register time series as which type when receiving the Literal NaN. Values 
can be DOUBLE, FLOAT or TEXT
+nan_string_infer_type=DOUBLE
+
 
 # BOOLEAN encoding when creating schema automatically is enabled
 default_boolean_encoding=RLE
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 7d5b9f2..d6ef3dd 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
@@ -394,6 +394,7 @@ dateFormat
 
 constant
     : dateExpression
+    | NaN
     | MINUS? realLiteral
     | MINUS? INT
     | STRING_LITERAL
@@ -876,6 +877,7 @@ TRUE
 FALSE
     : F A L S E
     ;
+
 //============================
 // End of the keywords list
 //============================
@@ -937,6 +939,8 @@ R_BRACKET : '}';
 
 UNDERLINE : '_';
 
+NaN : 'NaN';
+
 STRING_LITERAL
    : DOUBLE_QUOTE_STRING_LITERAL
    | SINGLE_QUOTE_STRING_LITERAL
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java 
b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index 2d26c3c..23c111a 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -386,6 +386,11 @@ public class IoTDBConfig {
   private TSDataType floatingStringInferType = TSDataType.FLOAT;
 
   /**
+   * register time series as which type when receiving the Literal NaN. Values 
can be DOUBLE, FLOAT or TEXT
+   */
+  private TSDataType nanStringInferType = TSDataType.DOUBLE;
+
+  /**
    * Storage group level when creating schema automatically is enabled
    */
   private int defaultStorageGroupLevel = 1;
@@ -1323,6 +1328,19 @@ public class IoTDBConfig {
     this.floatingStringInferType = floatingNumberStringInferType;
   }
 
+  public TSDataType getNanStringInferType() {
+    return nanStringInferType;
+  }
+
+  public void setNanStringInferType(TSDataType nanStringInferType) {
+    if (nanStringInferType != TSDataType.DOUBLE &&
+        nanStringInferType != TSDataType.FLOAT &&
+        nanStringInferType != TSDataType.TEXT) {
+      throw new IllegalArgumentException("Config Property 
nan_string_infer_type can only be FLOAT, DOUBLE or TEXT but is " + 
nanStringInferType);
+    }
+    this.nanStringInferType = nanStringInferType;
+  }
+
   public int getDefaultStorageGroupLevel() {
     return defaultStorageGroupLevel;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java 
b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index fd25b14..333b2d8 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -499,6 +499,8 @@ public class IoTDBDescriptor {
         conf.getIntegerStringInferType().toString())));
     
conf.setFloatingStringInferType(TSDataType.valueOf(properties.getProperty("floating_string_infer_type",
         conf.getFloatingStringInferType().toString())));
+    
conf.setNanStringInferType(TSDataType.valueOf(properties.getProperty("nan_string_infer_type",
+        conf.getNanStringInferType().toString())));
     conf.setDefaultStorageGroupLevel(
         Integer.parseInt(properties.getProperty("default_storage_group_level",
             Integer.toString(conf.getDefaultStorageGroupLevel()))));
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java 
b/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
index 2e9981d..e328874 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
@@ -22,7 +22,6 @@ package org.apache.iotdb.db.utils;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-import org.apache.iotdb.tsfile.utils.Binary;
 
 public class TypeInferenceUtils {
 
@@ -32,6 +31,8 @@ public class TypeInferenceUtils {
 
   private static TSDataType floatingStringInferType = 
IoTDBDescriptor.getInstance().getConfig().getFloatingStringInferType();
 
+  private static TSDataType nanStringInferType = 
IoTDBDescriptor.getInstance().getConfig().getNanStringInferType();
+
   private TypeInferenceUtils() {
 
   }
@@ -65,6 +66,9 @@ public class TypeInferenceUtils {
         } else {
           return floatingStringInferType;
         }
+        // "NaN" is returned if the NaN Literal is given in Parser
+      } else if ("NaN".equals(strValue)) {
+        return nanStringInferType;
       } else {
         return TSDataType.TEXT;
       }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBInsertNaNIT.java 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBInsertNaNIT.java
new file mode 100644
index 0000000..0e6fd16
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBInsertNaNIT.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.integration;
+
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.db.utils.MathUtils;
+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.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.iotdb.db.constant.TestConstant.TIMESTAMP_STR;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Notice that, all test begins with "IoTDB" is integration test. All test 
which will start the IoTDB server should be
+ * defined as integration test.
+ *
+ * This test stores NaN Values and retrieves them via SQL Interface.
+ */
+public class IoTDBInsertNaNIT {
+
+  private static final String CREATE_TEMPLATE_SQL = "CREATE TIMESERIES 
root.vehicle.%s.%s WITH DATATYPE=%s, ENCODING=%s, MAX_POINT_NUMBER=%d";
+  private static final String INSERT_TEMPLATE_SQL = "insert into 
root.vehicle.%s(timestamp,%s) values(%d,%s)";
+  private static List<String> sqls = new ArrayList<>();
+  private static final int TIMESTAMP = 10;
+  private static final String VALUE = "NaN";
+  private static final float DELTA_FLOAT = 0.0000001f;
+  private static final double DELTA_DOUBLE = 0.0000001d;
+
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvironmentUtils.closeStatMonitor();
+    initCreateSQLStatement();
+    EnvironmentUtils.envSetUp();
+    insertData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvironmentUtils.cleanEnv();
+  }
+
+  private static void initCreateSQLStatement(){
+    sqls.add("SET STORAGE GROUP TO root.vehicle.f0");
+    sqls.add("SET STORAGE GROUP TO root.vehicle.d0");
+    for(int i = 0; i < 10; i++){
+      sqls.add(String.format(CREATE_TEMPLATE_SQL, "f0", "s"+i+"rle", "FLOAT", 
"RLE", i));
+      sqls.add(String.format(CREATE_TEMPLATE_SQL, "f0", "s"+i+"2f", "FLOAT", 
"TS_2DIFF", i));
+      sqls.add(String.format(CREATE_TEMPLATE_SQL, "d0", "s"+i+"rle", "DOUBLE", 
"RLE", i));
+      sqls.add(String.format(CREATE_TEMPLATE_SQL, "d0", "s"+i+"2f", "DOUBLE", 
"TS_2DIFF", i));
+    }
+    for(int i = 0; i < 10; i++){
+      sqls.add(String.format(INSERT_TEMPLATE_SQL, "f0", "s"+i+"rle", 
TIMESTAMP, VALUE));
+      sqls.add(String.format(INSERT_TEMPLATE_SQL, "f0", "s"+i+"2f", TIMESTAMP, 
VALUE));
+      sqls.add(String.format(INSERT_TEMPLATE_SQL, "d0", "s"+i+"rle", 
TIMESTAMP, VALUE));
+      sqls.add(String.format(INSERT_TEMPLATE_SQL, "d0", "s"+i+"2f", TIMESTAMP, 
VALUE));
+    }
+
+  }
+
+  private static void insertData() 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();
+    }
+  }
+
+  @Test
+  public void selectAllSQLTest() 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 * from root");
+      Assert.assertTrue(hasResultSet);
+      int cnt;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          assertEquals(TIMESTAMP + "", resultSet.getString(TIMESTAMP_STR));
+          for (int i = 0; i < 10; i++) {
+            
Assert.assertEquals(MathUtils.roundWithGivenPrecision(Float.parseFloat(VALUE), 
i),
+                resultSet.getFloat(String.format("root.vehicle.%s.%s", "f0", 
"s" + i + "rle")),
+                DELTA_FLOAT);
+            
Assert.assertEquals(MathUtils.roundWithGivenPrecision(Float.parseFloat(VALUE), 
i),
+                resultSet.getFloat(String.format("root.vehicle.%s.%s", "f0", 
"s" + i + "2f")),
+                DELTA_FLOAT);
+            
Assert.assertEquals(MathUtils.roundWithGivenPrecision(Double.parseDouble(VALUE),
 i),
+                resultSet.getDouble(String.format("root.vehicle.%s.%s", "d0", 
"s" + i + "rle")),
+                DELTA_DOUBLE);
+            
Assert.assertEquals(MathUtils.roundWithGivenPrecision(Double.parseDouble(VALUE),
 i),
+                resultSet.getDouble(String.format("root.vehicle.%s.%s", "d0", 
"s" + i + "2f")),
+                DELTA_DOUBLE);
+          }
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+}
diff --git a/server/src/test/java/org/apache/iotdb/db/qp/PlannerTest.java 
b/server/src/test/java/org/apache/iotdb/db/qp/PlannerTest.java
index e4396a0..ec05a13 100644
--- a/server/src/test/java/org/apache/iotdb/db/qp/PlannerTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/qp/PlannerTest.java
@@ -23,6 +23,7 @@ import 
org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.MManager;
 import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
@@ -35,6 +36,7 @@ import org.junit.Test;
 import java.util.Collections;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 public class PlannerTest {
 
@@ -151,4 +153,15 @@ public class PlannerTest {
     String createTSStatement = "create timeseriess root.vehicle.d1.s1 with 
datatype=INT32,encoding=RLE";
     processor.parseSQLToPhysicalPlan(createTSStatement);
   }
+
+  @Test
+  public void insertStatementWithNullValue() throws QueryProcessException {
+    String createTSStatement = "insert into root.vehicle.d0(time,s0) 
values(10,NaN)";
+    PhysicalPlan physicalPlan = 
processor.parseSQLToPhysicalPlan(createTSStatement);
+
+    assertTrue(physicalPlan instanceof InsertPlan);
+    assertEquals("NaN", ((InsertPlan) physicalPlan).getValues()[0]);
+    // Later we will use Double.parseDouble so we have to ensure that it is 
parsed right
+    assertEquals(Double.NaN, Double.parseDouble("NaN"), 1e-15);
+  }
 }
\ No newline at end of file

Reply via email to