diff --git a/documentation20/cn/12.taos-sql/docs.md b/documentation20/cn/12.taos-sql/docs.md index 9edfe172c26fa5b0a4cb84f950ef7a6697dbf417..c22b20914a26c5e9503dbd6fcd4abf6b6fb67e54 100755 --- a/documentation20/cn/12.taos-sql/docs.md +++ b/documentation20/cn/12.taos-sql/docs.md @@ -1083,7 +1083,71 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数 {slop:1.000000, intercept:9.733334} | Query OK, 1 row(s) in set (0.000921s) ``` + +- **MODE** + ```mysql + SELECT MODE(field_name) FROM tb_name [WHERE clause]; + ``` + 功能说明:返回出现频率最高的值,若存在多个频率相同的最高值,输出空。不能匹配标签、时间戳输出。 + + 返回结果数据类型:同应用的字段。 + + 应用字段:适合于除时间主列外的任何类型字段。 + 适用于:**表**。 + + 示例: + ```mysql + taos> select voltage from d002; + voltage | + ======================== + 1 | + 1 | + 2 | + 19 | + Query OK, 4 row(s) in set (0.003545s) + + taos> select mode(voltage) from d002; + mode(voltage) | + ======================== + 1 | + Query OK, 1 row(s) in set (0.019393s) + ``` + +- **HYPERLOGLOG** + ```mysql + SELECT HYPERLOGLOG(field_name) FROM { tb_name | stb_name } [WHERE clause]; + ``` + 功能说明:采用hyperloglog算法,返回某列的基数。该算法在数据量很大的情况下,可以明显降低内存的占用,但是求出来的基数是个估算值,标准误差为0.81%。 + + 返回结果类型:整形。 + + 适用数据类型:适合于任何类型字段。 + + 支持的版本:2.6.0.x 之后的版本。 + + 示例: + ```mysql + taos> select dbig from shll; + dbig | + ======================== + 1 | + 1 | + 1 | + NULL | + 2 | + 19 | + NULL | + 9 | + Query OK, 8 row(s) in set (0.003755s) + + taos> select hyperloglog(dbig) from shll; + hyperloglog(dbig)| + ======================== + 4 | + Query OK, 1 row(s) in set (0.008388s) + ``` + ### 选择函数 在使用所有的选择函数的时候,可以同时指定输出 ts 列或标签列(包括 tbname),这样就可以方便地知道被选出的值是源于哪个数据行的。 @@ -1482,6 +1546,84 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数 Query OK, 2 row(s) in set (0.003487s) ``` +- **TAIL** + ```mysql + SELECT TAIL(field_name, k, offset_val) FROM {tb_name | stb_name} [WHERE clause]; + ``` + 功能说明:返回跳过最后 offset_value个,然后取连续 k 个记录,不忽略 NULL 值。offset_val 可以不输入。此时返回最后的 k 个记录。当有 offset_val 输入的情况下,该函数功能等效于order by ts desc LIMIT k OFFSET offset_val。 + + 参数范围:k: [1,100] offset_val: [0,100]。 + + 返回结果数据类型:同应用的字段。 + + 应用字段:适合于除时间主列外的任何类型字段。 + + 适用于:**表、超级表**。 + + 支持版本:2.6.0.x 之后的版本。 + + 示例: + ```mysql + taos> select ts,dbig from tail2; + ts | dbig | + ================================================== + 2021-10-15 00:31:33.000 | 1 | + 2021-10-17 00:31:31.000 | NULL | + 2021-12-24 00:31:34.000 | 2 | + 2022-01-01 08:00:05.000 | 19 | + 2022-01-01 08:00:06.000 | NULL | + 2022-01-01 08:00:07.000 | 9 | + Query OK, 6 row(s) in set (0.001952s) + + taos> select tail(dbig,2,2) from tail2; + ts | tail(dbig,2,2) | + ================================================== + 2021-12-24 00:31:34.000 | 2 | + 2022-01-01 08:00:05.000 | 19 | + Query OK, 2 row(s) in set (0.002307s) + +- **UNIQUE** + ```mysql + SELECT UNIQUE(field_name) FROM {tb_name | stb_name} [WHERE clause]; + ``` + 功能说明:返回该列的数值首次出现的值。该函数功能与 distinct 相似,但是可以匹配标签和时间戳信息。可以针对除时间列以外的字段进行查询,可以匹配标签和时间戳,其中的标签和时间戳是第一次出现时刻的标签和时间戳。 + + 返回结果数据类型:同应用的字段。 + + 应用字段:适合于除时间类型以外的字段。 + + 适用于:**表、超级表**。 + + 支持版本:2.6.0.x 之后的版本。 + + 说明:该函数可以应用在普通表和超级表上。不能和窗口操作一起使用,例如 interval/state_window/session_window 。 + + 示例: + ```mysql + taos> select ts,voltage from unique1; + ts | voltage | + ================================================== + 2021-10-17 00:31:31.000 | 1 | + 2022-01-24 00:31:31.000 | 1 | + 2021-10-17 00:31:31.000 | 1 | + 2021-12-24 00:31:31.000 | 2 | + 2022-01-01 08:00:01.000 | 19 | + 2021-10-17 00:31:31.000 | NULL | + 2022-01-01 08:00:02.000 | NULL | + 2022-01-01 08:00:03.000 | 9 | + Query OK, 8 row(s) in set (0.003018s) + + taos> select unique(voltage) from unique1; + ts | unique(voltage) | + ================================================== + 2021-10-17 00:31:31.000 | 1 | + 2021-10-17 00:31:31.000 | NULL | + 2021-12-24 00:31:31.000 | 2 | + 2022-01-01 08:00:01.000 | 19 | + 2022-01-01 08:00:03.000 | 9 | + Query OK, 5 row(s) in set (0.108458s) + + ### 计算函数 - **DIFF** @@ -1623,6 +1765,106 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数 80.810000718 | Query OK, 3 row(s) in set (0.001046s) ``` + +- **STATECOUNT** + ```mysql + SELECT STATECOUNT(field_name, oper, val) FROM { tb_name | stb_name } [WHERE clause]; + ``` + 功能说明:返回满足某个条件的连续记录的个数,结果作为新的一列追加在每行后面。条件根据参数计算,如果条件为true则加1,条件为false则重置为-1,如果数据为NULL,跳过该条数据。 + + 参数范围: + - oper : LT (小于)、GT(大于)、LE(小于等于)、GE(大于等于)、NE(不等于)、EQ(等于),不区分大小写。 + - val : 数值型 + + 返回结果类型:整形。 + + 适用数据类型:不能应用在 timestamp、binary、nchar、bool 类型字段上。 + + 嵌套子查询支持:不支持应用在子查询上。 + + 支持的版本:2.6.0.x 之后的版本。 + + 说明: + + - 该函数可以应用在普通表上,在由 GROUP BY 划分出单独时间线的情况下用于超级表(也即 GROUP BY tbname) + + - 不能和窗口操作一起使用,例如interval/state_window/session_window。 + + 示例: + ```mysql + taos> select ts,dbig from statef2; + ts | dbig | + ======================================================== + 2021-10-15 00:31:33.000000000 | 1 | + 2021-10-17 00:31:31.000000000 | NULL | + 2021-12-24 00:31:34.000000000 | 2 | + 2022-01-01 08:00:05.000000000 | 19 | + 2022-01-01 08:00:06.000000000 | NULL | + 2022-01-01 08:00:07.000000000 | 9 | + Query OK, 6 row(s) in set (0.002977s) + + taos> select stateCount(dbig,GT,2) from statef2; + ts | dbig | statecount(dbig,gt,2) | + ================================================================================ + 2021-10-15 00:31:33.000000000 | 1 | -1 | + 2021-10-17 00:31:31.000000000 | NULL | NULL | + 2021-12-24 00:31:34.000000000 | 2 | -1 | + 2022-01-01 08:00:05.000000000 | 19 | 1 | + 2022-01-01 08:00:06.000000000 | NULL | NULL | + 2022-01-01 08:00:07.000000000 | 9 | 2 | + Query OK, 6 row(s) in set (0.002791s) + ``` + +- **STATEDURATION** + ```mysql + SELECT stateDuration(field_name, oper, val, unit) FROM { tb_name | stb_name } [WHERE clause]; + ``` + 功能说明:返回满足某个条件的连续记录的时间长度,结果作为新的一列追加在每行后面。条件根据参数计算,如果条件为true则加上两个记录之间的时间长度(第一个满足条件的记录时间长度记为0),条件为false则重置为-1,如果数据为NULL,跳过该条数据。 + + 参数范围: + - oper : LT (小于)、GT(大于)、LE(小于等于)、GE(大于等于)、NE(不等于)、EQ(等于),不区分大小写。 + - val : 数值型 + - unit : 时间长度的单位,范围[1s、1m、1h ],不足一个单位舍去。默认为1s。 + + 返回结果类型:整形。 + + 适用数据类型:不能应用在 timestamp、binary、nchar、bool 类型字段上。 + + 嵌套子查询支持:不支持应用在子查询上。 + + 支持的版本:2.6.0.x 之后的版本。 + + 说明: + + - 该函数可以应用在普通表上,在由 GROUP BY 划分出单独时间线的情况下用于超级表(也即 GROUP BY tbname) + + - 不能和窗口操作一起使用,例如interval/state_window/session_window。 + + 示例: + ```mysql + taos> select ts,dbig from statef2; + ts | dbig | + ======================================================== + 2021-10-15 00:31:33.000000000 | 1 | + 2021-10-17 00:31:31.000000000 | NULL | + 2021-12-24 00:31:34.000000000 | 2 | + 2022-01-01 08:00:05.000000000 | 19 | + 2022-01-01 08:00:06.000000000 | NULL | + 2022-01-01 08:00:07.000000000 | 9 | + Query OK, 6 row(s) in set (0.002407s) + + taos> select stateDuration(dbig,GT,2) from statef2; + ts | dbig | stateduration(dbig,gt,2) | + =================================================================================== + 2021-10-15 00:31:33.000000000 | 1 | -1 | + 2021-10-17 00:31:31.000000000 | NULL | NULL | + 2021-12-24 00:31:34.000000000 | 2 | -1 | + 2022-01-01 08:00:05.000000000 | 19 | 0 | + 2022-01-01 08:00:06.000000000 | NULL | NULL | + 2022-01-01 08:00:07.000000000 | 9 | 2 | + Query OK, 6 row(s) in set (0.002613s) + ``` + ### 时间函数 - **NOW** diff --git a/documentation20/en/12.taos-sql/docs.md b/documentation20/en/12.taos-sql/docs.md index cbd2d77a507e0d55f1d870423d517cd1b79aac10..9a68e071782bce8ac17768c01a4d7d0823538598 100755 --- a/documentation20/en/12.taos-sql/docs.md +++ b/documentation20/en/12.taos-sql/docs.md @@ -852,6 +852,69 @@ TDengine supports aggregations over data, they are listed below: Query OK, 1 row(s) in set (0.000921s) ``` +- **MODE** + ```mysql + SELECT MODE(field_name) FROM tb_name [WHERE clause]; + ``` + Function: Returns the value with the highest frequency. If there are multiple highest values with the same frequency, the output is NULL. + + Return Data Type: Same as applicable fields. + + Applicable Fields: All types except timestamp. + + Supported version: Version after 2.6.0 . + + Example: + ```mysql + taos> select voltage from d002; + voltage | + ======================== + 1 | + 1 | + 2 | + 19 | + Query OK, 4 row(s) in set (0.003545s) + + taos> select mode(voltage) from d002; + mode(voltage) | + ======================== + 1 | + Query OK, 1 row(s) in set (0.019393s) + ``` + +- **HYPERLOGLOG** + ```mysql + SELECT HYPERLOGLOG(field_name) FROM { tb_name | stb_name } [WHERE clause]; + ``` + Function: The hyperloglog algorithm is used to return the cardinality of a column. In the case of large amount of data, the algorithm can significantly reduce the occupation of memory, but the cardinality is an estimated value, and the standard error is 0.81%. + + Return Data Type:Integer. + + Applicable Fields: All types. + + Supported version: Version after 2.6.0 . + + Example: + ```mysql + taos> select dbig from shll; + dbig | + ======================== + 1 | + 1 | + 1 | + NULL | + 2 | + 19 | + NULL | + 9 | + Query OK, 8 row(s) in set (0.003755s) + + taos> select hyperloglog(dbig) from shll; + hyperloglog(dbig)| + ======================== + 4 | + Query OK, 1 row(s) in set (0.008388s) + ### Selector Functions - **MIN** @@ -1102,6 +1165,83 @@ TDengine supports aggregations over data, they are listed below: Query OK, 1 row(s) in set (0.001042s) ``` +- **TAIL** + ```mysql + SELECT TAIL(field_name, k, offset_val) FROM {tb_name | stb_name} [WHERE clause]; + ``` + Function: Skip the last num of offset_value, return the k consecutive records without ignoring NULL value. offset_val can be empty, then the last K records are returned.The function is equivalent to:order by ts desc LIMIT k OFFSET offset_val. + + Range:k: [1,100] offset_val: [0,100]。 + + Return Data Type: Same as applicable fields. + + Applicable Fields: All types except timestamp. + + Applied to: **table stable**. + + Supported version: Version after 2.6.0 . + + Example: + ```mysql + taos> select ts,dbig from tail2; + ts | dbig | + ================================================== + 2021-10-15 00:31:33.000 | 1 | + 2021-10-17 00:31:31.000 | NULL | + 2021-12-24 00:31:34.000 | 2 | + 2022-01-01 08:00:05.000 | 19 | + 2022-01-01 08:00:06.000 | NULL | + 2022-01-01 08:00:07.000 | 9 | + Query OK, 6 row(s) in set (0.001952s) + + taos> select tail(dbig,2,2) from tail2; + ts | tail(dbig,2,2) | + ================================================== + 2021-12-24 00:31:34.000 | 2 | + 2022-01-01 08:00:05.000 | 19 | + Query OK, 2 row(s) in set (0.002307s) + +- **UNIQUE** + ```mysql + SELECT UNIQUE(field_name) FROM {tb_name | stb_name} [WHERE clause]; + ``` + Function: Returns the first occurrence of a value in this column. + + Return Data Type: Same as applicable fields. + + Applicable Fields: All types except timestamp. + + Applied to: **table stable**. + + Supported version: Version after 2.6.0 . + + Note: This function can be applied to ordinary tables and super tables. Cannot be used with window operations,such as interval/state_window/session_window. + + Example: + ```mysql + taos> select ts,voltage from unique1; + ts | voltage | + ================================================== + 2021-10-17 00:31:31.000 | 1 | + 2022-01-24 00:31:31.000 | 1 | + 2021-10-17 00:31:31.000 | 1 | + 2021-12-24 00:31:31.000 | 2 | + 2022-01-01 08:00:01.000 | 19 | + 2021-10-17 00:31:31.000 | NULL | + 2022-01-01 08:00:02.000 | NULL | + 2022-01-01 08:00:03.000 | 9 | + Query OK, 8 row(s) in set (0.003018s) + + taos> select unique(voltage) from unique1; + ts | unique(voltage) | + ================================================== + 2021-10-17 00:31:31.000 | 1 | + 2021-10-17 00:31:31.000 | NULL | + 2021-12-24 00:31:31.000 | 2 | + 2022-01-01 08:00:01.000 | 19 | + 2022-01-01 08:00:03.000 | 9 | + Query OK, 5 row(s) in set (0.108458s) + ### Computing Functions - **DIFF** @@ -1172,6 +1312,97 @@ TDengine supports aggregations over data, they are listed below: 1. Calculation between two or more columns is supported, and the calculation priorities can be controlled by parentheses(); 2. The NULL field does not participate in the calculation. If a row involved in calculation contains NULL, the calculation result of the row is NULL. +- **STATECOUNT** + ```mysql + SELECT STATECOUNT(field_name, oper, val) FROM { tb_name | stb_name } [WHERE clause]; + ``` + Function: Returns the number of consecutive records that meet a certain condition, and the result is appended to each row as a new column. The condition is calculated according to the parameters. If the condition is true, it will be increased by 1. If the condition is false, it will be reset to -1. If the data is NULL, the data will be skipped. + + Range: + - oper : LT(<),GT(>),LE(<=),GE(>=),NE(!=),EQ(=),case insensitive. + - val : Number. + + Returned Data Type: Integer。 + + Applicable Fields: All types except timestamp, binary, nchar, bool. + + Supported version: Version after 2.6.0 . + + Note: + - This function can be applied to ordinary tables. When a separate timeline is divided by group by, it is used for super tables (i.e. group by TBNAME). + - Cannot be used with window operations,such as interval/state_window/session_window. + + Example: + ```mysql + taos> select ts,dbig from statef2; + ts | dbig | + ======================================================== + 2021-10-15 00:31:33.000000000 | 1 | + 2021-10-17 00:31:31.000000000 | NULL | + 2021-12-24 00:31:34.000000000 | 2 | + 2022-01-01 08:00:05.000000000 | 19 | + 2022-01-01 08:00:06.000000000 | NULL | + 2022-01-01 08:00:07.000000000 | 9 | + Query OK, 6 row(s) in set (0.002977s) + + taos> select stateCount(dbig,GT,2) from statef2; + ts | dbig | statecount(dbig,gt,2) | + ================================================================================ + 2021-10-15 00:31:33.000000000 | 1 | -1 | + 2021-10-17 00:31:31.000000000 | NULL | NULL | + 2021-12-24 00:31:34.000000000 | 2 | -1 | + 2022-01-01 08:00:05.000000000 | 19 | 1 | + 2022-01-01 08:00:06.000000000 | NULL | NULL | + 2022-01-01 08:00:07.000000000 | 9 | 2 | + Query OK, 6 row(s) in set (0.002791s) + ``` + +- **STATEDURATION** + ```mysql + SELECT stateDuration(field_name, oper, val, unit) FROM { tb_name | stb_name } [WHERE clause]; + ``` + Function: Returns the length of time of continuous records that meet a certain condition, and the result is appended to each row as a new column. The condition is calculated according to the parameters. If the condition is true, the length of time between two records will be added (the length of time of the first record that meets the condition is recorded as 0). If the condition is false, it will be reset to -1. If the data is NULL, the data will be skipped. + + Range: + - oper : LT(<),GT(>),LE(<=),GE(>=),NE(!=),EQ(=),case insensitive. + - val : Number. + - unit : Unit of time length, range [1s, 1M, 1H], less than one unit is rounded off. The default is 1s. + + Returned Data Type: Integer。 + + Applicable Fields: All types except timestamp, binary, nchar, bool. + + Supported version: Version after 2.6.0 . + + Note: + - This function can be applied to ordinary tables. When a separate timeline is divided by group by, it is used for super tables (i.e. group by TBNAME). + - Cannot be used with window operations,such as interval/state_window/session_window. + + Example: + ```mysql + taos> select ts,dbig from statef2; + ts | dbig | + ======================================================== + 2021-10-15 00:31:33.000000000 | 1 | + 2021-10-17 00:31:31.000000000 | NULL | + 2021-12-24 00:31:34.000000000 | 2 | + 2022-01-01 08:00:05.000000000 | 19 | + 2022-01-01 08:00:06.000000000 | NULL | + 2022-01-01 08:00:07.000000000 | 9 | + Query OK, 6 row(s) in set (0.002407s) + + taos> select stateDuration(dbig,GT,2) from statef2; + ts | dbig | stateduration(dbig,gt,2) | + =================================================================================== + 2021-10-15 00:31:33.000000000 | 1 | -1 | + 2021-10-17 00:31:31.000000000 | NULL | NULL | + 2021-12-24 00:31:34.000000000 | 2 | -1 | + 2022-01-01 08:00:05.000000000 | 19 | 0 | + 2022-01-01 08:00:06.000000000 | NULL | NULL | + 2022-01-01 08:00:07.000000000 | 9 | 2 | + Query OK, 6 row(s) in set (0.002613s) + ``` + ## Time-dimension Aggregation TDengine supports aggregating by intervals (time range). Data in a table can partitioned by intervals and aggregated to generate results. For example, a temperature sensor collects data once per second, but the average temperature needs to be queried every 10 minutes. This aggregation is suitable for down sample operation, and the syntax is as follows: diff --git a/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h b/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h index 4c999b710a62d1e620064af4d5647ee46d9a570e..6b987141996d3c9a0bf78e162f1c11b758008536 100644 --- a/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h +++ b/src/client/jni/com_taosdata_jdbc_TSDBJNIConnector.h @@ -11,257 +11,254 @@ extern "C" { #define com_taosdata_jdbc_TSDBJNIConnector_INVALID_CONNECTION_POINTER_VALUE 0LL /* * Class: com_taosdata_jdbc_TSDBJNIConnector - * Method: + * Method: * Signature: (Ljava/lang/String;)V */ -JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setAllocModeImp - (JNIEnv *, jclass, jint, jstring, jboolean); +JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setAllocModeImp(JNIEnv *, jclass, jint, jstring, + jboolean); /* * Class: com_taosdata_jdbc_TSDBJNIConnector - * Method: + * Method: * Signature: ()Ljava/lang/String; */ -JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_dumpMemoryLeakImp - (JNIEnv *, jclass); +JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_dumpMemoryLeakImp(JNIEnv *, jclass); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: initImp * Signature: (Ljava/lang/String;)V */ -JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_initImp - (JNIEnv *, jclass, jstring); +JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_initImp(JNIEnv *, jclass, jstring); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: setOptions * Signature: (ILjava/lang/String;)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setOptions - (JNIEnv *, jclass, jint, jstring); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setOptions(JNIEnv *, jclass, jint, jstring); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: setConfigImp * Signature: (Ljava/lang/String;)Lcom/taosdata/jdbc/TSDBException; */ -JNIEXPORT jobject JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setConfigImp - (JNIEnv *, jclass, jstring); +JNIEXPORT jobject JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setConfigImp(JNIEnv *, jclass, jstring); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: getTsCharset * Signature: ()Ljava/lang/String; */ -JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset - (JNIEnv *, jclass); +JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset(JNIEnv *, jclass); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: getResultTimePrecisionImp * Signature: (JJ)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecisionImp - (JNIEnv *, jobject, jlong, jlong); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecisionImp(JNIEnv *, jobject, jlong, + jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: connectImp * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)J */ -JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_connectImp - (JNIEnv *, jobject, jstring, jint, jstring, jstring, jstring); +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_connectImp(JNIEnv *, jobject, jstring, jint, jstring, + jstring, jstring); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: executeQueryImp * Signature: ([BJ)I */ -JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_executeQueryImp - (JNIEnv *, jobject, jbyteArray, jlong); +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_executeQueryImp(JNIEnv *, jobject, jbyteArray, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: getErrCodeImp * Signature: (J)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getErrCodeImp - (JNIEnv *, jobject, jlong, jlong); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getErrCodeImp(JNIEnv *, jobject, jlong, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: getErrMsgImp * Signature: (J)Ljava/lang/String; */ -JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getErrMsgImp - (JNIEnv *, jobject, jlong); +JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getErrMsgImp(JNIEnv *, jobject, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: getResultSetImp * Signature: (J)J */ -JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getResultSetImp - (JNIEnv *env, jobject jobj, jlong con, jlong tres); +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getResultSetImp(JNIEnv *env, jobject jobj, jlong con, + jlong tres); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: isUpdateQueryImp * Signature: (JJ)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_isUpdateQueryImp - (JNIEnv *env, jobject jobj, jlong con, jlong tres); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_isUpdateQueryImp(JNIEnv *env, jobject jobj, jlong con, + jlong tres); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: freeResultSetImp * Signature: (JJ)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_freeResultSetImp - (JNIEnv *, jobject, jlong, jlong); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_freeResultSetImp(JNIEnv *, jobject, jlong, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: getAffectedRowsImp * Signature: (J)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getAffectedRowsImp - (JNIEnv *env, jobject jobj, jlong con, jlong res); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getAffectedRowsImp(JNIEnv *env, jobject jobj, jlong con, + jlong res); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: getSchemaMetaDataImp * Signature: (JJLjava/util/List;)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getSchemaMetaDataImp - (JNIEnv *, jobject, jlong, jlong, jobject); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getSchemaMetaDataImp(JNIEnv *, jobject, jlong, jlong, + jobject); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: fetchRowImp * Signature: (JJLcom/taosdata/jdbc/TSDBResultSetRowData;)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchRowImp - (JNIEnv *, jobject, jlong, jlong, jobject); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchRowImp(JNIEnv *, jobject, jlong, jlong, jobject); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: fetchBlockImp * Signature: (JJLcom/taosdata/jdbc/TSDBResultSetBlockData;)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchBlockImp - (JNIEnv *, jobject, jlong, jlong, jobject); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchBlockImp(JNIEnv *, jobject, jlong, jlong, jobject); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: closeConnectionImp * Signature: (J)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeConnectionImp - (JNIEnv *, jobject, jlong); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeConnectionImp(JNIEnv *, jobject, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: subscribeImp * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JI)J */ -JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_subscribeImp - (JNIEnv *, jobject, jlong, jboolean, jstring, jstring, jint); +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_subscribeImp(JNIEnv *, jobject, jlong, jboolean, + jstring, jstring, jint); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: consumeImp * Signature: (J)Lcom/taosdata/jdbc/TSDBResultSetRowData; */ -JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_consumeImp - (JNIEnv *, jobject, jlong); +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_consumeImp(JNIEnv *, jobject, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: unsubscribeImp * Signature: (J)V */ -JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_unsubscribeImp - (JNIEnv *, jobject, jlong, jboolean); +JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_unsubscribeImp(JNIEnv *, jobject, jlong, jboolean); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: validateCreateTableSqlImp * Signature: (J[B)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_validateCreateTableSqlImp - (JNIEnv *, jobject, jlong, jbyteArray); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_validateCreateTableSqlImp(JNIEnv *, jobject, jlong, + jbyteArray); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: prepareStmtImp * Signature: ([BJ)I */ -JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_prepareStmtImp - (JNIEnv *, jobject, jbyteArray, jlong); +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_prepareStmtImp(JNIEnv *, jobject, jbyteArray, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: setBindTableNameImp * Signature: (JLjava/lang/String;J)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setBindTableNameImp - (JNIEnv *, jobject, jlong, jstring, jlong); - +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setBindTableNameImp(JNIEnv *, jobject, jlong, jstring, + jlong); /** * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: setTableNameTagsImp * Signature: (JLjava/lang/String;I[B[B[B[BJ)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setTableNameTagsImp - (JNIEnv *, jobject, jlong, jstring, jint, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jlong); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setTableNameTagsImp(JNIEnv *, jobject, jlong, jstring, + jint, jbyteArray, jbyteArray, + jbyteArray, jbyteArray, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: bindColDataImp * Signature: (J[B[B[BIIIIJ)J */ -JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_bindColDataImp -(JNIEnv *, jobject, jlong, jbyteArray, jbyteArray, jbyteArray, jint, jint, jint, jint, jlong); +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_bindColDataImp(JNIEnv *, jobject, jlong, jbyteArray, + jbyteArray, jbyteArray, jint, jint, jint, + jint, jlong); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: stmt_add_batch * Signature: (JJ)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_addBatchImp(JNIEnv *env, jobject jobj, jlong stmt, jlong con); - +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_addBatchImp(JNIEnv *env, jobject jobj, jlong stmt, + jlong con); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: executeBatchImp * Signature: (JJ)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_executeBatchImp(JNIEnv *env, jobject jobj, jlong stmt, jlong con); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_executeBatchImp(JNIEnv *env, jobject jobj, jlong stmt, + jlong con); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: closeStmt * Signature: (JJ)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeStmt(JNIEnv *env, jobject jobj, jlong stmt, jlong con); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeStmt(JNIEnv *env, jobject jobj, jlong stmt, + jlong con); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: stmt_errstr * Signature: (JJ)I */ -JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_stmtErrorMsgImp(JNIEnv *env, jobject jobj, jlong stmt, jlong con); +JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_stmtErrorMsgImp(JNIEnv *env, jobject jobj, jlong stmt, + jlong con); /* * Class: com_taosdata_jdbc_TSDBJNIConnector * Method: insertLinesImp * Signature: ([Ljava/lang/String;JII)I */ -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp - (JNIEnv *, jobject, jobjectArray, jlong, jint, jint); +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JNIEnv *, jobject, jobjectArray, jlong, + jint, jint); + +/* + * Class: com_taosdata_jdbc_TSDBJNIConnector + * Method: schemalessInsertImp + * Signature: (J[B[B[BIIIIJ)J + */ +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_schemalessInsertImp(JNIEnv *, jobject, jobjectArray, + jlong, jint, jint); #ifdef __cplusplus } diff --git a/src/client/src/TSDBJNIConnector.c b/src/client/src/TSDBJNIConnector.c index 67a08fa4fac39e2497a3cc0447b73f2a93d0c4ee..49c7008947894eb3506893ae272512f73e7fb295 100644 --- a/src/client/src/TSDBJNIConnector.c +++ b/src/client/src/TSDBJNIConnector.c @@ -945,7 +945,7 @@ JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_bindColDataImp( } JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_addBatchImp(JNIEnv *env, jobject jobj, jlong stmt, - jlong con) { + jlong con) { TAOS *tscon = (TAOS *)con; if (tscon == NULL) { jniError("jobj:%p, connection already closed", jobj); @@ -1017,7 +1017,7 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeStmt(JNIEnv } JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_stmtErrorMsgImp(JNIEnv *env, jobject jobj, jlong stmt, - jlong con) { + jlong con) { char errMsg[128]; TAOS *tscon = (TAOS *)con; if (tscon == NULL) { @@ -1036,20 +1036,12 @@ JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_stmtErrorMsgIm return (*env)->NewStringUTF(env, taos_stmt_errstr((TAOS_STMT *)stmt)); } -JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JNIEnv *env, jobject jobj, - jobjectArray lines, jlong conn, - jint protocol, jint precision) { - TAOS *taos = (TAOS *)conn; - if (taos == NULL) { - jniError("jobj:%p, connection already closed", jobj); - return JNI_CONNECTION_NULL; - } - +SSqlObj *schemalessInsert(JNIEnv *env, jobject jobj, jobjectArray lines, TAOS *taos, jint protocol, jint precision) { int numLines = (*env)->GetArrayLength(env, lines); char **c_lines = calloc(numLines, sizeof(char *)); if (c_lines == NULL) { jniError("c_lines:%p, alloc memory failed", c_lines); - return JNI_OUT_OF_MEMORY; + return NULL; } for (int i = 0; i < numLines; ++i) { jstring line = (jstring)((*env)->GetObjectArrayElement(env, lines, i)); @@ -1057,7 +1049,6 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JN } SSqlObj *result = (SSqlObj *)taos_schemaless_insert(taos, c_lines, numLines, protocol, precision); - int code = taos_errno(result); for (int i = 0; i < numLines; ++i) { jstring line = (jstring)((*env)->GetObjectArrayElement(env, lines, i)); @@ -1065,6 +1056,24 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JN } tfree(c_lines); + return result; +} + +JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JNIEnv *env, jobject jobj, + jobjectArray lines, jlong conn, + jint protocol, jint precision) { + TAOS *taos = (TAOS *)conn; + if (taos == NULL) { + jniError("jobj:%p, connection already closed", jobj); + return JNI_CONNECTION_NULL; + } + + SSqlObj *result = (SSqlObj *)schemalessInsert(env, jobj, lines, taos, protocol, precision); + + if (result == NULL) { + return JNI_OUT_OF_MEMORY; + } + int code = taos_errno(result); if (code != TSDB_CODE_SUCCESS) { jniError("jobj:%p, conn:%p, code:%s, msg:%s", jobj, taos, tstrerror(code), taos_errstr(result)); taos_free_result((void *)result); @@ -1074,3 +1083,19 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JN return JNI_SUCCESS; } + +JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_schemalessInsertImp(JNIEnv *env, jobject jobj, + jobjectArray lines, jlong conn, + jint protocol, jint precision) { + TAOS *taos = (TAOS *)conn; + if (taos == NULL) { + jniError("jobj:%p, connection already closed", jobj); + return JNI_CONNECTION_NULL; + } + + SSqlObj *result = schemalessInsert(env, jobj, lines, taos, protocol, precision); + if (result == NULL) { + return JNI_OUT_OF_MEMORY; + } + return (jlong)result; +} \ No newline at end of file diff --git a/src/client/src/tscParseLineProtocol.c b/src/client/src/tscParseLineProtocol.c index 5d1173e8cf3859403c765a514c07120cb0f18ba7..e45c1bc956a9c55c316141423c81c726df696b39 100644 --- a/src/client/src/tscParseLineProtocol.c +++ b/src/client/src/tscParseLineProtocol.c @@ -2140,64 +2140,331 @@ static int32_t parseSmlKey(TAOS_SML_KV *pKV, const char **index, SHashObj *pHash static int32_t parseSmlValue(TAOS_SML_KV *pKV, const char **index, bool *is_last_kv, SSmlLinesInfo* info, bool isTag) { - const char *start, *cur, *tmp; - int32_t ret = TSDB_CODE_SUCCESS; - char *value = NULL; - int16_t len = 0; - bool searchQuote = false; - start = cur = *index; + const char *start, *cur; + int32_t ret = TSDB_CODE_SUCCESS; + char *value = NULL; + int16_t len = 0; + + bool kv_done = false; + bool back_slash = false; + bool double_quote = false; + size_t line_len = 0; + + enum { + tag_common, + tag_lqoute, + tag_rqoute + } tag_state; + + enum { + val_common, + val_lqoute, + val_rqoute + } val_state; - //if field value is string - if (!isTag) { - if (*cur == '"') { - searchQuote = true; - cur += 1; - len += 1; - } else if (*cur == 'L' && *(cur + 1) == '"') { - searchQuote = true; - cur += 2; - len += 2; - } - } + start = cur = *index; + tag_state = tag_common; + val_state = val_common; while (1) { - // unescaped ',' or ' ' or '\0' identifies a value - if (((*cur == ',' || *cur == ' ' ) && *(cur - 1) != '\\') || *cur == '\0') { - if (searchQuote == true) { - //first quote ignored while searching - if (*(cur - 1) == '"' && len != 1 && len != 2) { - *is_last_kv = (*cur == ' ' || *cur == '\0') ? true : false; + if (isTag) { + /* ',', '=' and spaces MUST be escaped */ + switch (tag_state) { + case tag_common: + if (back_slash == true) { + if (*cur != ',' && *cur != '=' && *cur != ' ') { + tscError("SML:0x%"PRIx64" tag value: state(%d), incorrect character(%c) escaped", info->id, tag_state, *cur); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + goto error; + } + + back_slash = false; + cur++; + len++; + break; + } + + if (*cur == '"') { + if (cur == *index) { + tag_state = tag_lqoute; + } + cur += 1; + len += 1; + break; + } else if (*cur == 'L') { + line_len = strlen(*index); + + /* common character at the end */ + if (cur + 1 >= *index + line_len) { + *is_last_kv = true; + kv_done = true; + break; + } + + if (*(cur + 1) == '"') { + /* string starts here */ + if (cur + 1 == *index + 1) { + tag_state = tag_lqoute; + } + cur += 2; + len += 2; + break; + } + } + + switch (*cur) { + case '\\': + back_slash = true; + cur++; + len++; + break; + case ',': + kv_done = true; + break; + + case ' ': + /* fall through */ + case '\0': + *is_last_kv = true; + kv_done = true; break; - } else if (*cur == '\0') { + + default: + cur++; + len++; + } + + break; + case tag_lqoute: + if (back_slash == true) { + if (*cur != ',' && *cur != '=' && *cur != ' ') { + tscError("SML:0x%"PRIx64" tag value: state(%d), incorrect character(%c) escaped", info->id, tag_state, *cur); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + goto error; + } + + back_slash = false; + cur++; + len++; + break; + } else if (double_quote == true) { + if (*cur != ' ' && *cur != ',' && *cur != '\0') { + tscError("SML:0x%"PRIx64" tag value: state(%d), incorrect character(%c) behind closing \"", info->id, tag_state, *cur); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + goto error; + } + + if (*cur == ' ' || *cur == '\0') { + *is_last_kv = true; + } + + double_quote = false; + tag_state = tag_rqoute; + break; + } + + switch (*cur) { + case '\\': + back_slash = true; + cur++; + len++; + break; + + case '"': + double_quote = true; + cur++; + len++; + break; + + case ',': + /* fall through */ + case '=': + /* fall through */ + case ' ': + if (*(cur - 1) != '\\') { + tscError("SML:0x%"PRIx64" tag value: state(%d), character(%c) not escaped", info->id, tag_state, *cur); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + kv_done = true; + } + break; + + case '\0': + tscError("SML:0x%"PRIx64" tag value: state(%d), closing \" not found", info->id, tag_state); ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; - goto error; - } else { + kv_done = true; + break; + + default: cur++; len++; - continue; } + + break; + + default: + kv_done = true; } - //unescaped ' ' or '\0' indicates end of value - *is_last_kv = (*cur == ' ' || *cur == '\0') ? true : false; - if (*cur == ' ' && *(cur + 1) == ' ') { - cur++; - continue; - } else { + } else { + switch (val_state) { + case val_common: + if (back_slash == true) { + if (*cur != '\\' && *cur != '"') { + tscError("SML:0x%"PRIx64" field value: state(%d), incorrect character(%c) escaped", info->id, val_state, *cur); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + goto error; + } + + back_slash = false; + cur++; + len++; + break; + } + + if (*cur == '"') { + if (cur == *index) { + val_state = val_lqoute; + } else { + if (*(cur - 1) != '\\') { + tscError("SML:0x%"PRIx64" field value: state(%d), \" not escaped", info->id, val_state); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + goto error; + } + } + + cur += 1; + len += 1; + break; + } else if (*cur == 'L') { + line_len = strlen(*index); + + /* common character at the end */ + if (cur + 1 >= *index + line_len) { + *is_last_kv = true; + kv_done = true; + break; + } + + if (*(cur + 1) == '"') { + /* string starts here */ + if (cur + 1 == *index + 1) { + val_state = val_lqoute; + cur += 2; + len += 2; + } else { + /* MUST at the end of string */ + if (cur + 2 >= *index + line_len) { + cur += 2; + len += 2; + *is_last_kv = true; + kv_done = true; + } else { + if (*(cur + 2) != ' ' && *(cur + 2) != ',') { + tscError("SML:0x%"PRIx64" field value: state(%d), not closing character(L\")", info->id, val_state); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + goto error; + } else { + if (*(cur + 2) == ' ') { + *is_last_kv = true; + } + + cur += 2; + len += 2; + kv_done = true; + } + } + } + break; + } + } + + switch (*cur) { + case '\\': + back_slash = true; + cur++; + len++; + break; + + case ',': + kv_done = true; + break; + + case ' ': + /* fall through */ + case '\0': + *is_last_kv = true; + kv_done = true; + break; + + default: + cur++; + len++; + } + break; + case val_lqoute: + if (back_slash == true) { + if (*cur != '\\' && *cur != '"') { + tscError("SML:0x%"PRIx64" field value: state(%d), incorrect character(%c) escaped", info->id, val_state, *cur); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + goto error; + } + + back_slash = false; + cur++; + len++; + break; + } else if (double_quote == true) { + if (*cur != ' ' && *cur != ',' && *cur != '\0') { + tscError("SML:0x%"PRIx64" field value: state(%d), incorrect character(%c) behind closing \"", info->id, val_state, *cur); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + goto error; + } + + if (*cur == ' ' || *cur == '\0') { + *is_last_kv = true; + } + + double_quote = false; + val_state = val_rqoute; + break; + } + + switch (*cur) { + case '\\': + back_slash = true; + cur++; + len++; + break; + + case '"': + double_quote = true; + cur++; + len++; + break; + + case '\0': + tscError("SML:0x%"PRIx64" field value: state(%d), closing \" not found", info->id, val_state); + ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR; + kv_done = true; + break; + + default: + cur++; + len++; + } + + break; + default: + kv_done = true; } } - //Escape special character - if (*cur == '\\') { - tmp = cur; - escapeSpecialCharacter(isTag ? 2 : 3, &cur); - if (tmp != cur) { - continue; - } + + if (kv_done == true) { + break; } - cur++; - len++; } - if (len == 0) { + + if (len == 0 || ret != TSDB_CODE_SUCCESS) { free(pKV->key); pKV->key = NULL; return TSDB_CODE_TSC_LINE_SYNTAX_ERROR; diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index 91e2d0c388d0b6dd50ca999d35be7712f8bb18dd..653df4baa1db9e2d13ebbcae5b11b9af93a2d1c5 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -4946,7 +4946,7 @@ static int32_t createGlobalAggregateExpr(SQueryAttr* pQueryAttr, SQueryInfo* pQu pse->colType = pExpr->base.resType; if(pExpr->base.resBytes > INT16_MAX && (pExpr->base.functionId == TSDB_FUNC_UNIQUE || pExpr->base.functionId == TSDB_FUNC_MODE - || pExpr->base.functionId == TSDB_FUNC_TAIL)){ + || pExpr->base.functionId == TSDB_FUNC_TAIL || pExpr->base.functionId == TSDB_FUNC_SAMPLE)){ pQueryAttr->interBytesForGlobal = pExpr->base.resBytes; }else{ pse->colBytes = pExpr->base.resBytes; diff --git a/src/common/inc/tname.h b/src/common/inc/tname.h index 9c8e31a9131d0d9ffa3d4cb71e813e3d2a34f2b7..6c4b54ec3cfb2f46acf5341ecda7015035866e59 100644 --- a/src/common/inc/tname.h +++ b/src/common/inc/tname.h @@ -54,8 +54,8 @@ typedef struct SSqlExpr { int32_t resBytes; // length of return value int32_t interBytes; // inter result buffer size - int16_t colType; // table column type, this should be int32_t, because it is too small for globale merge stage, pQueryAttr->interBytesForGlobal - int16_t colBytes; // table column bytes + int16_t colType; // table column type + int16_t colBytes; // table column bytes,it should be int32_t, because it is too small for globale merge stage, pQueryAttr->interBytesForGlobal int16_t numOfParams; // argument value of each function tVariant param[3]; // parameters are not more than 3 diff --git a/src/common/src/tdataformat.c b/src/common/src/tdataformat.c index d8999a0b6fece9cda4d5c8e2af82e65afa4ed580..55afd4c62096974e379e78d448086f10e9860764 100644 --- a/src/common/src/tdataformat.c +++ b/src/common/src/tdataformat.c @@ -624,8 +624,9 @@ static void tdMergeTwoDataCols(SDataCols *target, SDataCols *src1, int *iter1, i if ((key1 > key2) || (key1 == key2 && !TKEY_IS_DELETED(tkey2))) { for (int i = 0; i < src2->numOfCols; i++) { ASSERT(target->cols[i].type == src2->cols[i].type); - if (src2->cols[i].len > 0 && !isNull(src2->cols[i].pData, src2->cols[i].type)) { - dataColAppendVal(&(target->cols[i]), tdGetColDataOfRow(src2->cols + i, *iter2), target->numOfRows, + const void *src2Val = tdGetColDataOfRow(src2->cols + i, *iter2); + if (src2->cols[i].len > 0 && !isNull(src2Val, src2->cols[i].type)) { + dataColAppendVal(&(target->cols[i]), src2Val, target->numOfRows, target->maxPoints, 0); } else if(!forceSetNull && key1 == key2 && src1->cols[i].len > 0) { dataColAppendVal(&(target->cols[i]), tdGetColDataOfRow(src1->cols + i, *iter1), target->numOfRows, diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java index 093baef3cac5b33e6be74248a289addbc1e18e9d..3cc28b4de68cae7bcf337b12ba924454d5653706 100755 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBJNIConnector.java @@ -338,7 +338,7 @@ public class TSDBJNIConnector { public void addBatch(long stmt) throws SQLException { int code = addBatchImp(stmt, this.taos); - if (code != TSDBConstants.JNI_SUCCESS){ + if (code != TSDBConstants.JNI_SUCCESS) { throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, stmtErrorMsgImp(stmt, this.taos)); } } @@ -361,13 +361,24 @@ public class TSDBJNIConnector { /*************************************************************************************************/ // NOTE: schemaless-lines public void insertLines(String[] lines, SchemalessProtocolType protocolType, SchemalessTimestampType timestampType) throws SQLException { - int code = insertLinesImp(lines, this.taos, protocolType.ordinal(), timestampType.ordinal()); - if (code != TSDBConstants.JNI_SUCCESS) { - throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "failed to insertLines"); + long pSql = schemalessInsertImp(lines, this.taos, protocolType.ordinal(), timestampType.ordinal()); + try { + if (pSql == TSDBConstants.JNI_CONNECTION_NULL) { + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL); + } + if (pSql == TSDBConstants.JNI_OUT_OF_MEMORY) { + throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_OUT_OF_MEMORY); + } + + int code = this.getErrCode(pSql); + if (code != TSDBConstants.JNI_SUCCESS) { + String msg = this.getErrMsg(pSql); + throw TSDBError.createSQLException(code, msg); + } + } finally { + this.freeResultSetImp(this.taos, pSql); } } - private native int insertLinesImp(String[] lines, long conn, int type, int precision); - - + private native long schemalessInsertImp(String[] lines, long conn, int type, int precision); } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSet.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSet.java index 003324d27a57c3557f0bb3205fcee208aa776ed5..e1e15d0332ca465c31c2ef2726b181716298378e 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSet.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSet.java @@ -19,7 +19,6 @@ import com.google.common.primitives.Longs; import com.google.common.primitives.Shorts; import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; import java.sql.*; import java.util.ArrayList; import java.util.Calendar; @@ -53,7 +52,7 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet { return rowData; } - public TSDBResultSet(TSDBStatement statement, TSDBJNIConnector connector, long resultSetPointer) throws SQLException { + public TSDBResultSet(TSDBStatement statement, TSDBJNIConnector connector, long resultSetPointer, int timestampPrecision) throws SQLException { this.statement = statement; this.jniConnector = connector; this.resultSetPointer = resultSetPointer; @@ -69,7 +68,8 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet { throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0); } this.rowData = new TSDBResultSetRowData(this.columnMetaDataList.size()); - this.blockData = new TSDBResultSetBlockData(this.columnMetaDataList, this.columnMetaDataList.size()); + this.blockData = new TSDBResultSetBlockData(this.columnMetaDataList, this.columnMetaDataList.size(), timestampPrecision); + this.timestampPrecision = timestampPrecision; } public boolean next() throws SQLException { @@ -268,7 +268,7 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet { checkAvailability(columnIndex, this.columnMetaDataList.size()); if (this.getBatchFetch()) - return this.blockData.getString(columnIndex).getBytes(); + return this.blockData.getBytes(columnIndex -1); Object value = this.rowData.getObject(columnIndex); this.lastWasNull = value == null; @@ -343,7 +343,7 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet { @Override public BigDecimal getBigDecimal(int columnIndex) throws SQLException { if (this.getBatchFetch()) - return new BigDecimal(this.blockData.getLong(columnIndex - 1)); + return BigDecimal.valueOf(this.blockData.getDouble(columnIndex - 1)); this.lastWasNull = this.rowData.wasNull(columnIndex); if (lastWasNull) diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetBlockData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetBlockData.java index a74c9cbb8831c5b1142b5ddd3b6b17f95249b873..cdf30dd6974f01677186e432c53fd4649234b2bd 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetBlockData.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetBlockData.java @@ -25,10 +25,15 @@ import java.nio.ShortBuffer; import java.sql.SQLDataException; import java.sql.SQLException; import java.sql.Timestamp; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import com.google.common.primitives.Shorts; +import com.taosdata.jdbc.enums.TimestampPrecision; import com.taosdata.jdbc.utils.NullType; public class TSDBResultSetBlockData { @@ -39,9 +44,12 @@ public class TSDBResultSetBlockData { private List columnMetaDataList; private ArrayList colData; - public TSDBResultSetBlockData(List colMeta, int numOfCols) { + private int timestampPrecision; + + public TSDBResultSetBlockData(List colMeta, int numOfCols, int timestampPrecision) { this.columnMetaDataList = colMeta; this.colData = new ArrayList<>(numOfCols); + this.timestampPrecision = timestampPrecision; } public TSDBResultSetBlockData() { @@ -169,12 +177,46 @@ public class TSDBResultSetBlockData { public String getString(int col) throws SQLException { Object obj = get(col); if (obj == null) { - return new NullType().toString(); +// return new NullType().toString(); + return null; } + if (obj instanceof String) + return (String) obj; + + if (obj instanceof byte[]) { + String charset = TaosGlobalConfig.getCharset(); + try { + return new String((byte[]) obj, charset); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.getMessage()); + } + } return obj.toString(); } + public byte[] getBytes(int col) throws SQLException { + + Object obj = get(col); + if (obj == null) { + return null; + } + if (obj instanceof byte[]) + return (byte[]) obj; + if (obj instanceof String) + return ((String) obj).getBytes(); + if (obj instanceof Long) + return Longs.toByteArray((long) obj); + if (obj instanceof Integer) + return Ints.toByteArray((int) obj); + if (obj instanceof Short) + return Shorts.toByteArray((short) obj); + if (obj instanceof Byte) + return new byte[]{(byte) obj}; + + return obj.toString().getBytes(); + } + public int getInt(int col) { Object obj = get(col); if (obj == null) { @@ -184,14 +226,18 @@ public class TSDBResultSetBlockData { int type = this.columnMetaDataList.get(col).getColType(); switch (type) { case TSDBConstants.TSDB_DATA_TYPE_BOOL: + return (boolean) obj ? 1 : 0; case TSDBConstants.TSDB_DATA_TYPE_TINYINT: + return (byte) obj; case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: + return (short) obj; case TSDBConstants.TSDB_DATA_TYPE_INT: { return (int) obj; } case TSDBConstants.TSDB_DATA_TYPE_BIGINT: - case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { return ((Long) obj).intValue(); + case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { + return ((Long) ((Timestamp) obj).getTime()).intValue(); } case TSDBConstants.TSDB_DATA_TYPE_FLOAT: @@ -218,19 +264,25 @@ public class TSDBResultSetBlockData { int type = this.columnMetaDataList.get(col).getColType(); switch (type) { case TSDBConstants.TSDB_DATA_TYPE_BOOL: + return (boolean) obj; case TSDBConstants.TSDB_DATA_TYPE_TINYINT: + return ((byte) obj == 0) ? Boolean.FALSE : Boolean.TRUE; case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: + return ((short) obj == 0) ? Boolean.FALSE : Boolean.TRUE; case TSDBConstants.TSDB_DATA_TYPE_INT: { - return ((int) obj == 0L) ? Boolean.FALSE : Boolean.TRUE; + return ((int) obj == 0) ? Boolean.FALSE : Boolean.TRUE; } case TSDBConstants.TSDB_DATA_TYPE_BIGINT: + return (((long) obj) == 0L) ? Boolean.FALSE : Boolean.TRUE; + case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { - return (((Long) obj) == 0L) ? Boolean.FALSE : Boolean.TRUE; + return ((Timestamp) obj).getTime() == 0L ? Boolean.FALSE : Boolean.TRUE; } case TSDBConstants.TSDB_DATA_TYPE_FLOAT: + return (((float) obj) == 0f) ? Boolean.FALSE : Boolean.TRUE; case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: { - return (((Double) obj) == 0) ? Boolean.FALSE : Boolean.TRUE; + return (((double) obj) == 0) ? Boolean.FALSE : Boolean.TRUE; } case TSDBConstants.TSDB_DATA_TYPE_NCHAR: @@ -258,17 +310,31 @@ public class TSDBResultSetBlockData { int type = this.columnMetaDataList.get(col).getColType(); switch (type) { case TSDBConstants.TSDB_DATA_TYPE_BOOL: + return (boolean) obj ? 1 : 0; case TSDBConstants.TSDB_DATA_TYPE_TINYINT: + return (byte) obj; case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: + return (short) obj; case TSDBConstants.TSDB_DATA_TYPE_INT: { return (int) obj; } case TSDBConstants.TSDB_DATA_TYPE_BIGINT: - case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { return (long) obj; + case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { + Timestamp ts = (Timestamp) obj; + switch (this.timestampPrecision) { + case TimestampPrecision.MS: + default: + return ts.getTime(); + case TimestampPrecision.US: + return ts.getTime() * 1000 + ts.getNanos() / 1000 % 1000; + case TimestampPrecision.NS: + return ts.getTime() * 1000_000 + ts.getNanos() % 1000_000; + } } case TSDBConstants.TSDB_DATA_TYPE_FLOAT: + return ((Float) obj).longValue(); case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: { return ((Double) obj).longValue(); } @@ -284,6 +350,17 @@ public class TSDBResultSetBlockData { } public Timestamp getTimestamp(int col) throws SQLException { + Object obj = get(col); + if (obj == null) { + return null; + } + + int type = this.columnMetaDataList.get(col).getColType(); + if (type == TSDBConstants.TSDB_DATA_TYPE_BIGINT) + return parseTimestampColumnData((long) obj); + if (type == TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP) + return (Timestamp) obj; + return new Timestamp(getLong(col)); } @@ -296,17 +373,31 @@ public class TSDBResultSetBlockData { int type = this.columnMetaDataList.get(col).getColType(); switch (type) { case TSDBConstants.TSDB_DATA_TYPE_BOOL: + return (boolean) obj ? 1 : 0; case TSDBConstants.TSDB_DATA_TYPE_TINYINT: + return (byte) obj; case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: + return (short) obj; case TSDBConstants.TSDB_DATA_TYPE_INT: { return (int) obj; } case TSDBConstants.TSDB_DATA_TYPE_BIGINT: - case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { return (long) obj; + case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { + Timestamp ts = (Timestamp) obj; + switch (this.timestampPrecision) { + case TimestampPrecision.MS: + default: + return ts.getTime(); + case TimestampPrecision.US: + return ts.getTime() * 1000 + ts.getNanos() / 1000 % 1000; + case TimestampPrecision.NS: + return ts.getTime() * 1000_000 + ts.getNanos() % 1000_000; + } } case TSDBConstants.TSDB_DATA_TYPE_FLOAT: + return Double.parseDouble(String.valueOf(obj)); case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: { return (double) obj; } @@ -367,7 +458,15 @@ public class TSDBResultSetBlockData { return val; } - case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: + case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: { + LongBuffer lb = (LongBuffer) this.colData.get(col); + long val = lb.get(this.rowIndex); + if (NullType.isBigIntNull(val)) { + return null; + } + + return parseTimestampColumnData(val); + } case TSDBConstants.TSDB_DATA_TYPE_BIGINT: { LongBuffer lb = (LongBuffer) this.colData.get(col); long val = lb.get(this.rowIndex); @@ -408,7 +507,7 @@ public class TSDBResultSetBlockData { return null; } - return new String(dest); + return dest; } case TSDBConstants.TSDB_DATA_TYPE_JSON: @@ -432,4 +531,21 @@ public class TSDBResultSetBlockData { return 0; } + + private Timestamp parseTimestampColumnData(long value) { + if (TimestampPrecision.MS == timestampPrecision) + return new Timestamp(value); + + if (TimestampPrecision.US == timestampPrecision) { + long epochSec = value / 1000_000L; + long nanoAdjustment = value % 1000_000L * 1000L; + return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + } + if (TimestampPrecision.NS == timestampPrecision) { + long epochSec = value / 1000_000_000L; + long nanoAdjustment = value % 1000_000_000L; + return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment)); + } + return null; + } } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java index 5d2b98a516c0d0086628e242570b03db9b28c3ff..258a9ad6146c4376da759feb19324dfff5a7e513 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBResultSetRowData.java @@ -14,8 +14,6 @@ *****************************************************************************/ package com.taosdata.jdbc; -import com.taosdata.jdbc.utils.NullType; - import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.sql.SQLException; @@ -132,7 +130,7 @@ public class TSDBResultSetRowData { public int getInt(int col, int nativeType) throws SQLException { Object obj = data.get(col - 1); if (obj == null) - return NullType.getIntNull(); + return 0; switch (nativeType) { case TSDBConstants.TSDB_DATA_TYPE_BOOL: @@ -213,7 +211,7 @@ public class TSDBResultSetRowData { public long getLong(int col, int nativeType) throws SQLException { Object obj = data.get(col - 1); if (obj == null) { - return NullType.getBigIntNull(); + return 0; } switch (nativeType) { @@ -282,7 +280,7 @@ public class TSDBResultSetRowData { public float getFloat(int col, int nativeType) { Object obj = data.get(col - 1); if (obj == null) - return NullType.getFloatNull(); + return 0; switch (nativeType) { case TSDBConstants.TSDB_DATA_TYPE_BOOL: @@ -301,7 +299,7 @@ public class TSDBResultSetRowData { case TSDBConstants.TSDB_DATA_TYPE_BIGINT: return (Long) obj; default: - return NullType.getFloatNull(); + return 0; } } @@ -322,7 +320,7 @@ public class TSDBResultSetRowData { public double getDouble(int col, int nativeType) { Object obj = data.get(col - 1); if (obj == null) - return NullType.getDoubleNull(); + return 0; switch (nativeType) { case TSDBConstants.TSDB_DATA_TYPE_BOOL: @@ -341,7 +339,7 @@ public class TSDBResultSetRowData { case TSDBConstants.TSDB_DATA_TYPE_BIGINT: return (Long) obj; default: - return NullType.getDoubleNull(); + return 0; } } @@ -454,7 +452,7 @@ public class TSDBResultSetRowData { milliseconds = ts / 1_000; fracNanoseconds = (int) (ts * 1_000 % 1_000_000_000); if (fracNanoseconds < 0) { - if (milliseconds == 0 ){ + if (milliseconds == 0) { milliseconds = -1; } fracNanoseconds += 1_000_000_000; @@ -465,7 +463,7 @@ public class TSDBResultSetRowData { milliseconds = ts / 1_000_000; fracNanoseconds = (int) (ts % 1_000_000_000); if (fracNanoseconds < 0) { - if (milliseconds == 0 ){ + if (milliseconds == 0) { milliseconds = -1; } fracNanoseconds += 1_000_000_000; diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBStatement.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBStatement.java index ce877987e6e9073defbff62e283910ee34366c4d..8316a1d563f0517137324c4ed022a04ebc3f33f6 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBStatement.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBStatement.java @@ -46,9 +46,8 @@ public class TSDBStatement extends AbstractStatement { this.connection.getConnector().freeResultSet(pSql); throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY); } - TSDBResultSet res = new TSDBResultSet(this, this.connection.getConnector(), pSql); int timestampPrecision = this.connection.getConnector().getResultTimePrecision(pSql); - res.setTimestampPrecision(timestampPrecision); + TSDBResultSet res = new TSDBResultSet(this, this.connection.getConnector(), pSql, timestampPrecision); res.setBatchFetch(this.connection.getBatchFetch()); return res; } @@ -91,7 +90,8 @@ public class TSDBStatement extends AbstractStatement { return false; } - this.resultSet = new TSDBResultSet(this, this.connection.getConnector(), pSql); + int timestampPrecision = this.connection.getConnector().getResultTimePrecision(pSql); + this.resultSet = new TSDBResultSet(this, this.connection.getConnector(), pSql, timestampPrecision); this.resultSet.setBatchFetch(this.connection.getBatchFetch()); return true; } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBSubscribe.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBSubscribe.java index d74f7755b24f1eb59059fb5ad5ead48d420ec7f6..2a535fc8fa629a3f6d4780b8f03b397aca443824 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBSubscribe.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBSubscribe.java @@ -14,6 +14,8 @@ *****************************************************************************/ package com.taosdata.jdbc; +import com.taosdata.jdbc.enums.TimestampPrecision; + import java.sql.SQLException; public class TSDBSubscribe { @@ -41,7 +43,7 @@ public class TSDBSubscribe { } else if (resultSetPointer == TSDBConstants.JNI_NULL_POINTER) { return null; } else { - return new TSDBResultSet(null, this.connecter, resultSetPointer); + return new TSDBResultSet(null, this.connecter, resultSetPointer, TimestampPrecision.UNKNOWN); } } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java index 4558dfa84bfccacf9f0d4fa2d7991c8bd0546b30..aee575b266ed9abfce427b8f08481aac8fad00eb 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/enums/TimestampPrecision.java @@ -4,4 +4,5 @@ public class TimestampPrecision { public static final int MS = 0; public static final int US = 1; public static final int NS = 2; + public static final int UNKNOWN = 9999; } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java index 599ee85a6bbdb2a612faf1434f4921f071ea348e..2819173da852fb7f7ca3a62c21fdfab7c9e98b5d 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/rs/RestfulResultSet.java @@ -482,9 +482,6 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet { return Shorts.toByteArray((short) value); if (value instanceof Byte) return new byte[]{(byte) value}; - if (value instanceof Timestamp) { - return Utils.formatTimestamp((Timestamp) value).getBytes(); - } return value.toString().getBytes(); } diff --git a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/ws/BlockResultSet.java b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/ws/BlockResultSet.java index 709f740e486e8bcfe06a44d14f67cf3cf5b32264..6cf2d06df4ddfbc8a5530c966b13eb48a977dad3 100644 --- a/src/connector/jdbc/src/main/java/com/taosdata/jdbc/ws/BlockResultSet.java +++ b/src/connector/jdbc/src/main/java/com/taosdata/jdbc/ws/BlockResultSet.java @@ -645,8 +645,6 @@ public class BlockResultSet extends AbstractWSResultSet { } if (value instanceof Float) return (float) value; - if (value instanceof Double) - return (float) (double) value; int taosType = fields.get(columnIndex - 1).getTaosType(); switch (taosType) { @@ -670,6 +668,12 @@ public class BlockResultSet extends AbstractWSResultSet { throwRangeException(value.toString(), columnIndex, Types.FLOAT); return tmp.floatValue(); } + case TSDB_DATA_TYPE_DOUBLE:{ + Double tmp = (double) value; + if (tmp < Float.MIN_VALUE || tmp > Float.MAX_VALUE) + throwRangeException(value.toString(), columnIndex, Types.FLOAT); + return Float.parseFloat(String.valueOf(tmp)); + } case TSDB_DATA_TYPE_NCHAR: case TSDB_DATA_TYPE_JSON: @@ -700,7 +704,7 @@ public class BlockResultSet extends AbstractWSResultSet { if (value instanceof Double) return (double) value; if (value instanceof Float) - return (float) value; + return Double.parseDouble(String.valueOf(value)); int taosType = fields.get(columnIndex - 1).getTaosType(); switch (taosType) { @@ -763,9 +767,6 @@ public class BlockResultSet extends AbstractWSResultSet { return Shorts.toByteArray((short) value); if (value instanceof Byte) return new byte[]{(byte) value}; - if (value instanceof Timestamp) { - return Utils.formatTimestamp((Timestamp) value).getBytes(); - } return value.toString().getBytes(); } diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/JsonTagTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/JsonTagTest.java index fe55cd6df76c425b8a38e7e7726e74808f12dcd1..75480356e02c260ac3ad3e7c678f8fd881bf1b0a 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/JsonTagTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/JsonTagTest.java @@ -9,7 +9,9 @@ import org.junit.runners.MethodSorters; import java.sql.*; import java.util.ArrayList; +import java.util.HashSet; import java.util.Random; +import java.util.Set; @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RunWith(CatalogRunner.class) @@ -1129,14 +1131,14 @@ public class JsonTagTest { ResultSet resultSet = statement.executeQuery("select stddev(dataint) from jsons1 group by jtag->'tag1'"); String s = ""; int count = 0; + Set set = new HashSet<>(); while (resultSet.next()) { count++; - s = resultSet.getString(2); - + set.add(resultSet.getString(2)); } Assert.assertEquals(8, count); - Assert.assertEquals("\"收到货\"", s); - close(resultSet); + Assert.assertTrue(set.contains("\"femail\"")); + Assert.assertTrue(set.contains("\"收到货\"")); } @Test diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBDatabaseMetaDataTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBDatabaseMetaDataTest.java index cb6133015c0256de99ea4db02bedeb982ce7491d..d620168c80b86e073d0a6fee1d43e1d9cb942b70 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBDatabaseMetaDataTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/TSDBDatabaseMetaDataTest.java @@ -727,8 +727,8 @@ public class TSDBDatabaseMetaDataTest { Assert.assertEquals(26, columns.getInt("COLUMN_SIZE")); // DECIMAL_DIGITS Assert.assertEquals("DECIMAL_DIGITS", meta.getColumnLabel(9)); - Assert.assertEquals(Integer.MIN_VALUE, columns.getInt(9)); - Assert.assertEquals(Integer.MIN_VALUE, columns.getInt("DECIMAL_DIGITS")); + Assert.assertEquals(0, columns.getInt(9)); + Assert.assertEquals(0, columns.getInt("DECIMAL_DIGITS")); Assert.assertEquals(null, columns.getString(9)); Assert.assertEquals(null, columns.getString("DECIMAL_DIGITS")); // NUM_PREC_RADIX @@ -773,8 +773,8 @@ public class TSDBDatabaseMetaDataTest { Assert.assertEquals(12, columns.getInt("COLUMN_SIZE")); // DECIMAL_DIGITS Assert.assertEquals("DECIMAL_DIGITS", meta.getColumnLabel(9)); - Assert.assertEquals(Integer.MIN_VALUE, columns.getInt(9)); - Assert.assertEquals(Integer.MIN_VALUE, columns.getInt("DECIMAL_DIGITS")); + Assert.assertEquals(0, columns.getInt(9)); + Assert.assertEquals(0, columns.getInt("DECIMAL_DIGITS")); Assert.assertEquals(null, columns.getString(9)); Assert.assertEquals(null, columns.getString("DECIMAL_DIGITS")); // NUM_PREC_RADIX diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulDatabaseMetaDataTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulDatabaseMetaDataTest.java index 8bdc269843d3c817f3790671715d0aa0567b7053..4ac43033d67b471cb58d83aff711dda48db4f9a3 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulDatabaseMetaDataTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulDatabaseMetaDataTest.java @@ -732,8 +732,8 @@ public class RestfulDatabaseMetaDataTest { Assert.assertEquals(26, columns.getInt("COLUMN_SIZE")); // DECIMAL_DIGITS Assert.assertEquals("DECIMAL_DIGITS", meta.getColumnLabel(9)); - Assert.assertEquals(Integer.MIN_VALUE, columns.getInt(9)); - Assert.assertEquals(Integer.MIN_VALUE, columns.getInt("DECIMAL_DIGITS")); + Assert.assertEquals(0, columns.getInt(9)); + Assert.assertEquals(0, columns.getInt("DECIMAL_DIGITS")); Assert.assertEquals(null, columns.getString(9)); Assert.assertEquals(null, columns.getString("DECIMAL_DIGITS")); // NUM_PREC_RADIX @@ -778,8 +778,8 @@ public class RestfulDatabaseMetaDataTest { Assert.assertEquals(12, columns.getInt("COLUMN_SIZE")); // DECIMAL_DIGITS Assert.assertEquals("DECIMAL_DIGITS", meta.getColumnLabel(9)); - Assert.assertEquals(Integer.MIN_VALUE, columns.getInt(9)); - Assert.assertEquals(Integer.MIN_VALUE, columns.getInt("DECIMAL_DIGITS")); + Assert.assertEquals(0, columns.getInt(9)); + Assert.assertEquals(0, columns.getInt("DECIMAL_DIGITS")); Assert.assertEquals(null, columns.getString(9)); Assert.assertEquals(null, columns.getString("DECIMAL_DIGITS")); // NUM_PREC_RADIX diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulJsonTagTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulJsonTagTest.java index d96aff32bf19019a4fb2743b7d4ad03f9d878fe2..df04711eb4400e5028fc1f20e8e1c9e06cb23a57 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulJsonTagTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulJsonTagTest.java @@ -8,6 +8,8 @@ import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import java.sql.*; +import java.util.HashSet; +import java.util.Set; /** * Most of the functionality is consistent with {@link com.taosdata.jdbc.JsonTagTest}, @@ -1143,13 +1145,14 @@ public class RestfulJsonTagTest { ResultSet resultSet = statement.executeQuery("select stddev(dataint) from jsons1 group by jtag->'tag1'"); String s = ""; int count = 0; + Set set = new HashSet<>(); while (resultSet.next()) { count++; - s = resultSet.getString(2); - + set.add(resultSet.getString(2)); } Assert.assertEquals(8, count); - Assert.assertEquals("\"收到货\"", s); + Assert.assertTrue(set.contains("\"femail\"")); + Assert.assertTrue(set.contains("\"收到货\"")); close(resultSet); } diff --git a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetTest.java b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetTest.java index c1ca31ae388f577a33cc6f3a6bc943ce52112507..b1ca634a21a811561a8da1d2475b1f63ff15fb00 100644 --- a/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetTest.java +++ b/src/connector/jdbc/src/test/java/com/taosdata/jdbc/rs/RestfulResultSetTest.java @@ -133,7 +133,7 @@ public class RestfulResultSetTest { @Test public void getBytes() throws SQLException { byte[] f1 = rs.getBytes("f1"); - Assert.assertEquals("2021-01-01 00:00:00.000", new String(f1)); + Assert.assertEquals("2021-01-01 00:00:00.0", new String(f1)); byte[] f2 = rs.getBytes("f2"); Assert.assertEquals(1, Ints.fromByteArray(f2)); diff --git a/src/os/src/detail/osTime.c b/src/os/src/detail/osTime.c index fb8c2a5ae6e469545e3f1439fb1cc02fdb234e51..1575b3100f78a17b9bbe9dcb29b971054c55b294 100644 --- a/src/os/src/detail/osTime.c +++ b/src/os/src/detail/osTime.c @@ -83,16 +83,10 @@ void deltaToUtcInitOnce() { static int64_t parseFraction(char* str, char** end, int32_t timePrec); static int32_t parseTimeWithTz(char* timestr, int64_t* time, int32_t timePrec, char delim); -static int32_t parseLocaltime(char* timestr, int64_t* time, int32_t timePrec, char delim); -static int32_t parseLocaltimeWithDst(char* timestr, int64_t* time, int32_t timePrec, char delim); +static int32_t parseLocaltime(char* timestr, int64_t* time, int32_t timePrec, char delim, bool withDST); static char* forwardToTimeStringEnd(char* str); static bool checkTzPresent(char *str, int32_t len); -static int32_t (*parseLocaltimeFp[]) (char* timestr, int64_t* time, int32_t timePrec, char delim) = { - parseLocaltime, - parseLocaltimeWithDst -}; - int32_t taosGetTimestampSec() { return (int32_t)time(NULL); } int32_t taosParseTime(char* timestr, int64_t* time, int32_t len, int32_t timePrec, int8_t day_light) { @@ -101,13 +95,13 @@ int32_t taosParseTime(char* timestr, int64_t* time, int32_t len, int32_t timePre if (checkTzPresent(timestr, len)) { return parseTimeWithTz(timestr, time, timePrec, 'T'); } else { - return (*parseLocaltimeFp[day_light])(timestr, time, timePrec, 'T'); + return parseLocaltime(timestr, time, timePrec, 'T', day_light); } } else { if (checkTzPresent(timestr, len)) { return parseTimeWithTz(timestr, time, timePrec, 0); } else { - return (*parseLocaltimeFp[day_light])(timestr, time, timePrec, 0); + return parseLocaltime(timestr, time, timePrec, 0, day_light); } } } @@ -322,9 +316,12 @@ int32_t parseTimeWithTz(char* timestr, int64_t* time, int32_t timePrec, char del return 0; } -int32_t parseLocaltime(char* timestr, int64_t* time, int32_t timePrec, char delim) { +int32_t parseLocaltime(char* timestr, int64_t* time, int32_t timePrec, char delim, bool withDST) { *time = 0; struct tm tm = {0}; + if (withDST) { + tm.tm_isdst = -1; + } char* str; if (delim == 'T') { @@ -336,7 +333,11 @@ int32_t parseLocaltime(char* timestr, int64_t* time, int32_t timePrec, char deli } if (str == NULL) { - return -1; + //if parse failed, try "%Y-%m-%d" format + str = strptime(timestr, "%Y-%m-%d", &tm); + if (str == NULL) { + return -1; + } } #ifdef _MSC_VER @@ -345,45 +346,14 @@ int32_t parseLocaltime(char* timestr, int64_t* time, int32_t timePrec, char deli #endif #endif - int64_t seconds = user_mktime64(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, timezone); - - int64_t fraction = 0; - - if (*str == '.') { - /* parse the second fraction part */ - if ((fraction = parseFraction(str + 1, &str, timePrec)) < 0) { - return -1; - } - } - - int64_t factor = (timePrec == TSDB_TIME_PRECISION_MILLI) ? 1000 : - (timePrec == TSDB_TIME_PRECISION_MICRO ? 1000000 : 1000000000); - *time = factor * seconds + fraction; - - return 0; -} - -int32_t parseLocaltimeWithDst(char* timestr, int64_t* time, int32_t timePrec, char delim) { - *time = 0; - struct tm tm = {0}; - tm.tm_isdst = -1; - - char* str; - if (delim == 'T') { - str = strptime(timestr, "%Y-%m-%dT%H:%M:%S", &tm); - } else if (delim == 0) { - str = strptime(timestr, "%Y-%m-%d %H:%M:%S", &tm); + int64_t seconds; + if (!withDST) { + seconds = user_mktime64(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, timezone); } else { - str = NULL; + /* mktime will be affected by TZ, set by using taos_options */ + seconds = mktime(&tm); } - if (str == NULL) { - return -1; - } - - /* mktime will be affected by TZ, set by using taos_options */ - int64_t seconds = mktime(&tm); - int64_t fraction = 0; if (*str == '.') { @@ -396,6 +366,7 @@ int32_t parseLocaltimeWithDst(char* timestr, int64_t* time, int32_t timePrec, ch int64_t factor = (timePrec == TSDB_TIME_PRECISION_MILLI) ? 1000 : (timePrec == TSDB_TIME_PRECISION_MICRO ? 1000000 : 1000000000); *time = factor * seconds + fraction; + return 0; } diff --git a/src/query/src/qExecutor.c b/src/query/src/qExecutor.c index aabb0cd2388f1961c5141ca6a0e56379dd11162e..88dffd8fdd6f4a91f719c8de4d2ab836bd30eb10 100644 --- a/src/query/src/qExecutor.c +++ b/src/query/src/qExecutor.c @@ -1935,7 +1935,7 @@ static SQLFunctionCtx* createSQLFunctionCtx(SQueryRuntimeEnv* pRuntimeEnv, SExpr pCtx->inputType = pSqlExpr->colType; if (pRuntimeEnv->pQueryAttr->interBytesForGlobal > INT16_MAX && (pSqlExpr->functionId == TSDB_FUNC_UNIQUE || pSqlExpr->functionId == TSDB_FUNC_MODE - || pSqlExpr->functionId == TSDB_FUNC_TAIL)){ + || pSqlExpr->functionId == TSDB_FUNC_TAIL || pSqlExpr->functionId == TSDB_FUNC_SAMPLE)) { pCtx->inputBytes = pRuntimeEnv->pQueryAttr->interBytesForGlobal; }else{ pCtx->inputBytes = pSqlExpr->colBytes; diff --git a/tests/develop-test/2-query/TD-13946.py b/tests/develop-test/2-query/TD-13946.py new file mode 100644 index 0000000000000000000000000000000000000000..d08ac0989dc4edda01946f826e690cc41fc62ca1 --- /dev/null +++ b/tests/develop-test/2-query/TD-13946.py @@ -0,0 +1,44 @@ +import sys +from util.log import * +from util.cases import * +from util.sql import * +from util.dnodes import tdDnodes +from math import inf + +class TDTestCase: + def caseDescription(self): + ''' + case1: [TD-13946]core dump of sampling binary column so that when result from vnode exceeds INT16_MAX bytes + ''' + return + + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + self._conn = conn + + def run(self): + print("running {}".format(__file__)) + tdSql.execute("drop database if exists td13946") + tdSql.execute("create database td13946") + tdSql.execute("use td13946") + + tdSql.execute("create table st ( ts timestamp, bin binary(100)) tags (t1 int)") + tdSql.execute("create table ct1 using st tags(1)") + tdSql.execute("create table ct2 using st tags(2)") + + for i in range(0, 4000, 2): + tdSql.execute("insert into ct1 values(now + {}a, '{}')".format(i, i)) + tdSql.execute("insert into ct2 values(now + {}a, '{}')".format(i+1, i+1)) + + tdSql.query("select sample(bin, 1000) from td13946.st group by tbname") + + tdSql.execute('drop database td13946') + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) + diff --git a/tests/develop-test/2-query/ts_shortcut.py b/tests/develop-test/2-query/ts_shortcut.py new file mode 100644 index 0000000000000000000000000000000000000000..fa1af037ff169733f6c90f853822568ca4f233f0 --- /dev/null +++ b/tests/develop-test/2-query/ts_shortcut.py @@ -0,0 +1,107 @@ +################################################################### +# Copyright (c) 2021 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import sys +from util.log import * +from util.cases import * +from util.sql import * + + +class TDTestCase: + def caseDescription(self): + ''' + case1: [TD-13970] timestamp format shortcut + ''' + return + + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + self._conn = conn + + def run(self): + print("running {}".format(__file__)) + tdSql.execute("drop database if exists db") + tdSql.execute("create database if not exists db") + tdSql.execute('use db') + + tdSql.execute('create table tb(ts timestamp, c0 int)') + tdSql.execute('create stable stb(ts timestamp , c0 int) tags (t0 timestamp)') + + #INSERT + tdSql.execute('insert into tb values ("2020-02-02", 1);') + tdSql.query('select ts from tb'); + tdSql.checkRows(1) + res = tdSql.getData(0, 0) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + + tdSql.execute('insert into ctb using stb tags("2020-02-02") values ("2020-02-02", 1)') + tdSql.query('select ts,t0 from ctb'); + tdSql.checkRows(1) + res = tdSql.getData(0, 0) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + res = tdSql.getData(0, 1) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + tdSql.query('select ts,t0 from stb'); + tdSql.checkRows(1) + res = tdSql.getData(0, 0) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + res = tdSql.getData(0, 1) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + + #SELECT WHERE + tdSql.query('select ts from tb where ts = "2020-02-02"') + tdSql.checkRows(1) + res = tdSql.getData(0, 0) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + + tdSql.query('select ts from ctb where ts <= "2020-02-02"') + tdSql.checkRows(1) + res = tdSql.getData(0, 0) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + + tdSql.query('select ts from stb where ts >= "2020-02-02"') + tdSql.checkRows(1) + res = tdSql.getData(0, 0) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + + #CREATE TAG + tdSql.execute('create table ctb1 using stb tags("2020-02-02")') + tdSql.query('select t0 from ctb1'); + tdSql.checkRows(1) + res = tdSql.getData(0, 0) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + + #TIME RELATED functions + tdSql.query('select to_unixtimestamp("2020-02-02") from tb') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 1580572800000) + + tdSql.query('select timetruncate("2020-02-02", 1h) from tb;') + tdSql.checkRows(1) + res = tdSql.getData(0, 0) + tdSql.checkEqual(str(res), "2020-02-02 00:00:00") + + tdSql.query('select timediff("2020-02-02", "2020-02-03", 1h) from tb;') + tdSql.checkRows(1) + tdSql.checkData(0, 0, 24) + + tdSql.execute('drop database db') + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/develop-test/fulltest-query.sh b/tests/develop-test/fulltest-query.sh index 3e39c1fc30794049ad41a4a009d130c6a1bc3d5c..deffe368288a4cd968b0ebc8ca2a2d96b1d95673 100755 --- a/tests/develop-test/fulltest-query.sh +++ b/tests/develop-test/fulltest-query.sh @@ -18,3 +18,4 @@ python3 ./test.py -f 2-query/TD-13246.py python3 ./test.py -f 2-query/TD-6347.py python3 ./test.py -f 2-query/math_funcs.py python3 ./test.py -f 2-query/function_histogram.py +python3 ./test.py -f 2-query/TD-13946.py diff --git a/tests/parallel_test/cases.task b/tests/parallel_test/cases.task index 70d88796debfded06d125aeec0f09789e4b38692..998bf4abe84a2c801dad709d0906f111beb99472 100644 --- a/tests/parallel_test/cases.task +++ b/tests/parallel_test/cases.task @@ -713,6 +713,7 @@ 5,,develop-test,python3 ./test.py -f 2-query/function_to_iso8601.py 5,,develop-test,python3 ./test.py -f 2-query/function_to_unixtimestamp.py 5,,develop-test,python3 ./test.py -f 2-query/time_window_keywords.py +5,,develop-test,python3 ./test.py -f 2-query/TD-13946.py 5,,develop-test,python3 ./test.py -f 2-query/query_window_keywords.py 4,,system-test,python3 test.py -f 4-taosAdapter/TD-12163.py 4,,system-test,python3 ./test.py -f 3-connectors/restful/restful_binddbname.py @@ -789,10 +790,12 @@ 3,,pytest,python3 test.py -f tag_lite/binary.py 3,,pytest,python3 test.py -f query/filterAllIntTypes.py 3,,develop-test,python3 ./test.py -f 2-query/ts_hidden_column.py +3,,develop-test,python3 ./test.py -f 2-query/ts_shortcut.py 3,,develop-test,python3 ./test.py -f 2-query/TD-5902.py 3,,script,eval sh -c \"if [ `uname -m` != aarch64 ]; then ./test.sh -f general/compute/scalar_triangle.sim; fi\" 3,,script,./test.sh -f general/compute/scalar_str_concat_len.sim 3,,develop-test,python3 ./test.py -f 2-query/function_tail.py 2,,develop-test,python3 ./test.py -f 2-query/function_unique.py +2,,develop-test,python3 ./test.py -f 2-query/function_hll.py 1,,develop-test,python3 ./test.py -f 2-query/function_state.py 1,,develop-test,python3 ./test.py -f 5-taos-tools/taosbenchmark/demo.py diff --git a/tests/pytest/insert/line_insert.py b/tests/pytest/insert/line_insert.py index d95df3a8491f73f7279e583afd446a7182adf823..4c873ec4a4efa6d1877a83d5b3942f5eb990a714 100644 --- a/tests/pytest/insert/line_insert.py +++ b/tests/pytest/insert/line_insert.py @@ -32,9 +32,9 @@ class TDTestCase: tdSql.execute('create stable ste(ts timestamp, f int) tags(t1 bigint)') - lines = [ "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"\"\"a pa,\"s si,t \"\"\",c2=false,c4=4f64 1626006833639000000", + lines = [ "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"\\\"\\\"a pa,\\\"s si,t \\\"\\\"\",c2=false,c4=4f64 1626006833639000000", "st,t1=4i64,t3=\"t4\",t2=5f64,t4=5f64 c1=3i64,c3=L\"passitagin\",c2=true,c4=5f64,c5=5f64 1626006833640000000", - "ste,t2=5f64,t3=L\"ste\" c1=true,c2=4i64,c3=\" i,\"a \"m,\"\"\" 1626056811823316532", + "ste,t2=5f64,t3=L\"ste\" c1=true,c2=4i64,c3=\" i,\\\"a \\\"m,\\\"\\\"\" 1626056811823316532", "stf,t1=4i64,t3=\"t4\",t2=5f64,t4=5f64 c1=3i64,c3=L\"passitagin\",c2=true,c4=5f64,c5=5f64,c6=7u64 1626006933640000000", "st,t1=4i64,t2=5f64,t3=\"t4\" c1=3i64,c3=L\"passitagain\",c2=true,c4=5f64 1626006833642000000", "ste,t2=5f64,t3=L\"ste2\" c3=\"iamszhou\",c4=false 1626056811843316532", @@ -147,7 +147,7 @@ class TDTestCase: tdSql.query('select tbname from str') tdSql.checkRows(3) - ###Special Character and keyss + ###Special Character and keys self._conn.schemaless_insert([ "1234,id=3456,abc=4i64,def=3i64 123=3i64,int=2i64,bool=false,into=5f64,column=7u64,!@#$.%^&*()=false 1626006933641", "int,id=and,123=4i64,smallint=5f64,double=5f64,of=3i64,key=L\"passitagin_stf\",!@#$.%^&*()=false abc=false 1626006933654", @@ -193,6 +193,15 @@ class TDTestCase: #tdSql.query('select * from `create`') #tdSql.checkRows(1) + + self._conn.schemaless_insert([ + "sts,t1=abc,t2=ab\"c,t3=ab\\,c,t4=ab\\=c,t5=ab\\ c c1=3i64,c3=L\"passitagin\",c2=true,c4=5f64,c5=5f64,c6=\"abc\" 1626006833640000000", + "sts,t1=abc c1=3i64,c2=false,c3=L\"{\\\"date\\\":\\\"2020-01-01 08:00:00.000\\\",\\\"temperature\\\":20}\",c6=\"ab\\\\c\" 1626006833640000000" + ], TDSmlProtocolType.LINE.value, TDSmlTimestampType.NANO_SECOND.value) + + tdSql.query('select tbname from sts') + tdSql.checkRows(2) + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__)