提交 9ef8aaea 编写于 作者: G Ganlin Zhao

Merge branch 'develop' into enhance/TD-10700

import hudson.model.Result import hudson.model.Result
import hudson.model.*; import hudson.model.*;
import jenkins.model.CauseOfInterruption import jenkins.model.CauseOfInterruption
properties([pipelineTriggers([githubPush()])])
node { node {
git url: 'https://github.com/taosdata/TDengine.git'
} }
def skipbuild=0 def skipbuild=0
...@@ -194,6 +192,7 @@ def pre_test_win(){ ...@@ -194,6 +192,7 @@ def pre_test_win(){
} }
pipeline { pipeline {
agent none agent none
options { skipDefaultCheckout() }
environment{ environment{
WK = '/var/lib/jenkins/workspace/TDinternal' WK = '/var/lib/jenkins/workspace/TDinternal'
WKC= '/var/lib/jenkins/workspace/TDinternal/community' WKC= '/var/lib/jenkins/workspace/TDinternal/community'
...@@ -201,67 +200,67 @@ pipeline { ...@@ -201,67 +200,67 @@ pipeline {
stages { stages {
stage('pre_build'){ stage('pre_build'){
agent{label 'master'} agent{label 'master'}
when { options { skipDefaultCheckout() }
changeRequest() when{
changeRequest()
} }
steps { steps {
script{ script{
abort_previous() abort_previous()
abortPreviousBuilds() abortPreviousBuilds()
} }
sh''' // sh'''
rm -rf ${WORKSPACE}.tes // rm -rf ${WORKSPACE}.tes
cp -r ${WORKSPACE} ${WORKSPACE}.tes // cp -r ${WORKSPACE} ${WORKSPACE}.tes
cd ${WORKSPACE}.tes // cd ${WORKSPACE}.tes
git fetch // git fetch
''' // '''
script { // script {
if (env.CHANGE_TARGET == 'master') { // if (env.CHANGE_TARGET == 'master') {
sh ''' // sh '''
git checkout master // git checkout master
''' // '''
} // }
else if(env.CHANGE_TARGET == '2.0'){ // else if(env.CHANGE_TARGET == '2.0'){
sh ''' // sh '''
git checkout 2.0 // git checkout 2.0
''' // '''
} // }
else{ // else{
sh ''' // sh '''
git checkout develop // git checkout develop
''' // '''
} // }
} // }
sh''' // sh'''
git fetch origin +refs/pull/${CHANGE_ID}/merge // git fetch origin +refs/pull/${CHANGE_ID}/merge
git checkout -qf FETCH_HEAD // git checkout -qf FETCH_HEAD
''' // '''
script{ // script{
skipbuild='2' // skipbuild='2'
skipbuild=sh(script: "git log -2 --pretty=%B | fgrep -ie '[skip ci]' -e '[ci skip]' && echo 1 || echo 2", returnStdout:true) // skipbuild=sh(script: "git log -2 --pretty=%B | fgrep -ie '[skip ci]' -e '[ci skip]' && echo 1 || echo 2", returnStdout:true)
println skipbuild // println skipbuild
} // }
sh''' // sh'''
rm -rf ${WORKSPACE}.tes // rm -rf ${WORKSPACE}.tes
''' // '''
// }
} }
} }
stage('Parallel test stage') { stage('Parallel test stage') {
//only build pr //only build pr
options { skipDefaultCheckout() }
when { when {
allOf{ allOf{
changeRequest() changeRequest()
expression{ not{ expression { env.CHANGE_BRANCH =~ /docs\// }}
return skipbuild.trim() == '2'
}
} }
} }
parallel { parallel {
stage('python_1_s1') { stage('python_1_s1') {
agent{label " slave1 || slave11 "} agent{label " slave1 || slave11 "}
steps { steps {
pre_test() pre_test()
timeout(time: 55, unit: 'MINUTES'){ timeout(time: 55, unit: 'MINUTES'){
sh ''' sh '''
......
...@@ -124,17 +124,25 @@ IF (TD_APLHINE) ...@@ -124,17 +124,25 @@ IF (TD_APLHINE)
MESSAGE(STATUS "aplhine is defined") MESSAGE(STATUS "aplhine is defined")
ENDIF () ENDIF ()
IF (TD_LINUX) MESSAGE("before BUILD_HTTP: " ${BUILD_HTTP})
IF (TD_ARM_32) IF ("${BUILD_HTTP}" STREQUAL "")
SET(TD_BUILD_HTTP TRUE) IF (TD_LINUX)
ADD_DEFINITIONS(-DHTTP_EMBEDDED) IF (TD_ARM_32)
ELSE () SET(BUILD_HTTP "true")
IF (TD_BUILD_HTTP) ELSE ()
ADD_DEFINITIONS(-DHTTP_EMBEDDED) SET(BUILD_HTTP "false")
ENDIF () ENDIF ()
ELSE ()
SET(BUILD_HTTP "true")
ENDIF () ENDIF ()
ELSE () ENDIF ()
MESSAGE("after BUILD_HTTP: " ${BUILD_HTTP})
IF (${BUILD_HTTP} MATCHES "true")
SET(TD_BUILD_HTTP TRUE) SET(TD_BUILD_HTTP TRUE)
ENDIF ()
IF (TD_BUILD_HTTP)
ADD_DEFINITIONS(-DHTTP_EMBEDDED) ADD_DEFINITIONS(-DHTTP_EMBEDDED)
ENDIF () ENDIF ()
......
...@@ -92,10 +92,6 @@ ENDIF () ...@@ -92,10 +92,6 @@ ENDIF ()
SET(TD_BUILD_HTTP FALSE) SET(TD_BUILD_HTTP FALSE)
IF (${BUILD_HTTP} MATCHES "true")
SET(TD_BUILD_HTTP TRUE)
ENDIF ()
SET(TD_MEMORY_SANITIZER FALSE) SET(TD_MEMORY_SANITIZER FALSE)
IF (${MEMORY_SANITIZER} MATCHES "true") IF (${MEMORY_SANITIZER} MATCHES "true")
SET(TD_MEMORY_SANITIZER TRUE) SET(TD_MEMORY_SANITIZER TRUE)
......
此差异已折叠。
此差异已折叠。
...@@ -243,7 +243,7 @@ repeater 部分添加 { host:'<TDengine server/cluster host>', port: <port for S ...@@ -243,7 +243,7 @@ repeater 部分添加 { host:'<TDengine server/cluster host>', port: <port for S
{ {
port: 8125 port: 8125
, backends: ["./backends/repeater"] , backends: ["./backends/repeater"]
, repeater: [{ host: '127.0.0.1', port: 8126}] , repeater: [{ host: '127.0.0.1', port: 6044}]
} }
``` ```
......
# UDF(用户定义函数) # UDF(用户定义函数)
在有些应用场景中,应用逻辑需要的查询无法直接使用系统内置的函数来表示。利用 UDF 功能,TDengine 可以插入用户编写的处理代码并在查询中使用它们,就能够很方便地解决特殊应用场景中的使用需求。 在有些应用场景中,应用逻辑需要的查询无法直接使用系统内置的函数来表示。利用 UDF 功能,TDengine 可以插入用户编写的处理代码并在查询中使用它们,就能够很方便地解决特殊应用场景中的使用需求。 UDF 通常以数据表中的一列数据做为输入,同时支持以嵌套子查询的结果作为输入。
从 2.2.0.0 版本开始,TDengine 支持通过 C/C++ 语言进行 UDF 定义。接下来结合示例讲解 UDF 的使用方法。 从 2.2.0.0 版本开始,TDengine 支持通过 C/C++ 语言进行 UDF 定义。接下来结合示例讲解 UDF 的使用方法。
...@@ -9,76 +9,70 @@ ...@@ -9,76 +9,70 @@
TDengine 提供 3 个 UDF 的源代码示例,分别为: TDengine 提供 3 个 UDF 的源代码示例,分别为:
* [add_one.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/add_one.c) * [add_one.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/add_one.c)
* [abs_max.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/abs_max.c) * [abs_max.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/abs_max.c)
* [sum_double.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/sum_double.c) * [demo.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/demo.c)
### 无需中间变量的标量函数 ### 标量函数
[add_one.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/add_one.c) 是结构最简单的 UDF 实现。其功能为:对传入的一个数据列(可能因 WHERE 子句进行了筛选)中的每一项,都输出 +1 之后的值,并且要求输入的列数据类型为 INT。 [add_one.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/add_one.c) 是结构最简单的 UDF 实现。其功能为:对传入的一个数据列(可能因 WHERE 子句进行了筛选)中的每一项,都输出 +1 之后的值,并且要求输入的列数据类型为 INT。
这一具体的处理逻辑在函数 `void add_one(char* data, short itype, short ibytes, int numOfRows, long long* ts, char* dataOutput, char* interBUf, char* tsOutput, int* numOfOutput, short otype, short obytes, SUdfInit* buf)` 中定义。这类用于实现 UDF 的基础计算逻辑的函数,我们称为 udfNormalFunc,也就是对行数据块的标量计算函数。需要注意的是,udfNormalFunc 的参数项是固定的,用于按照约束完成与引擎之间的数据交换。 这一具体的处理逻辑在函数 `void add_one(char* data, short itype, short ibytes, int numOfRows, long long* ts, char* dataOutput, char* interBuf, char* tsOutput, int* numOfOutput, short otype, short obytes, SUdfInit* buf)` 中定义。这类用于实现 UDF 的基础计算逻辑的函数,我们称为 udfNormalFunc,也就是对行数据块的标量计算函数。需要注意的是,udfNormalFunc 的参数项是固定的,用于按照约束完成与引擎之间的数据交换。
- udfNormalFunc 中各参数的具体含义是: - udfNormalFunc 中各参数的具体含义是:
* data:存有输入的数据。 * data:输入数据。
* itype:输入数据的类型。这里采用的是短整型表示法,与各种数据类型对应的值可以参见 [column_meta 中的列类型说明](https://www.taosdata.com/cn/documentation/connector#column_meta)。例如 4 用于表示 INT 型。 * itype:输入数据的类型。这里采用的是短整型表示法,与各种数据类型对应的值可以参见 [column_meta 中的列类型说明](https://www.taosdata.com/cn/documentation/connector#column_meta)。例如 4 用于表示 INT 型。
* iBytes:输入数据中每个值会占用的字节数。 * iBytes:输入数据中每个值会占用的字节数。
* numOfRows:输入数据的总行数。 * numOfRows:输入数据的总行数。
* ts:主键时间戳在输入中的列数据。 * ts:主键时间戳在输入中的列数据(只读)
* dataOutput:输出数据的缓冲区。 * dataOutput:输出数据的缓冲区,缓冲区大小为用户指定的输出类型大小 * numOfRows
* interBuf:系统使用的中间临时缓冲区,通常用户逻辑无需对 interBuf 进行处理 * interBuf:中间计算结果的缓冲区,大小为用户在创建 UDF 时指定的BUFSIZE大小。通常用于计算中间结果与最终结果不一致时使用,由引擎负责分配与释放
* tsOutput:主键时间戳在输出时的列数据。 * tsOutput:主键时间戳在输出时的列数据,如果非空可用于输出结果对应的时间戳
* numOfOutput:输出数据的个数 * numOfOutput:输出结果的个数(行数)
* oType:输出数据的类型。取值含义与 itype 参数一致。 * oType:输出数据的类型。取值含义与 itype 参数一致。
* oBytes:输出数据中每个值占用的字节数。 * oBytes:输出数据中每个值占用的字节数。
* buf:计算过程的中间变量缓冲区 * buf:用于在 UDF 与引擎间的状态控制信息传递块
其中 buf 参数需要用到一个自定义结构体 SUdfInit。在这个例子中,因为 add_one 的计算过程无需用到中间变量缓存,所以可以把 SUdfInit 定义成一个空结构体。
### 无需中间变量的聚合函数 ### 聚合函数
[abs_max.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/abs_max.c) 实现的是一个聚合函数,功能是对一组数据按绝对值取最大值。 [abs_max.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/abs_max.c) 实现的是一个聚合函数,功能是对一组数据按绝对值取最大值。
其计算过程为:与所在查询语句相关的数据会被分为多个行数据块,对每个行数据块调用 udfNormalFunc(在本例的实现代码中,实际函数名是 `abs_max`),再将每个数据块的计算结果调用 udfMergeFunc(本例中,其实际的函数名是 `abs_max_merge`)进行聚合,生成每个子表的聚合结果。如果查询指令涉及超级表,那么最后还会通过 udfFinalizeFunc(本例中,其实际的函数名是 `abs_max_finalize`)再把子表的计算结果聚合为超级表的计算结果 其计算过程为:与所在查询语句相关的数据会被分为多个行数据块,对每个行数据块调用 udfNormalFunc(在本例的实现代码中,实际函数名是 `abs_max`)来生成每个子表的中间结果,再将子表的中间结果调用 udfMergeFunc(本例中,其实际的函数名是 `abs_max_merge`)进行聚合,生成超级表的最终聚合结果或中间结果。聚合查询最后还会通过 udfFinalizeFunc(本例中,其实际的函数名是 `abs_max_finalize`)再把超级表的中间结果处理为最终结果,最终结果只能含0或1条结果数据
值得注意的是,udfNormalFunc、udfMergeFunc、udfFinalizeFunc 之间,函数名约定使用相同的前缀,此前缀即 udfNormalFunc 的实际函数名。udfMergeFunc 的函数名后缀 `_merge`、udfFinalizeFunc 的函数名后缀 `_finalize`,是 UDF 实现规则的一部分,系统会按照这些函数名后缀来调用相应功能。 值得注意的是,udfNormalFunc、udfMergeFunc、udfFinalizeFunc 之间,函数名约定使用相同的前缀,此前缀即 udfNormalFunc 的实际函数名。udfMergeFunc 的函数名后缀 `_merge`、udfFinalizeFunc 的函数名后缀 `_finalize`,是 UDF 实现规则的一部分,系统会按照这些函数名后缀来调用相应功能。
- udfMergeFunc 用于对计算中间结果进行聚合。本例中 udfMergeFunc 对应的实现函数为 `void abs_max_merge(char* data, int32_t numOfRows, char* dataOutput, int32_t* numOfOutput, SUdfInit* buf)`,其中各参数的具体含义是: - udfMergeFunc 用于对计算中间结果进行聚合,只有针对超级表的聚合查询才需要调用该函数。本例中 udfMergeFunc 对应的实现函数为 `void abs_max_merge(char* data, int32_t numOfRows, char* dataOutput, int32_t* numOfOutput, SUdfInit* buf)`,其中各参数的具体含义是:
* data:udfNormalFunc 的输出组合在一起的数据,也就成为了 udfMergeFunc 的输入 * data:udfNormalFunc 的输出数据数组,如果使用了 interBuf 那么 data 就是 interBuf 的数组
* numOfRows:data 中数据的行数。 * numOfRows:data 中数据的行数。
* dataOutput:输出数据的缓冲区。 * dataOutput:输出数据的缓冲区,大小等于一条最终结果的大小。如果此时输出还不是最终结果,可以选择输出到 interBuf 中即data中。
* numOfOutput:输出数据的个数。 * numOfOutput:输出结果的个数(行数)。
* buf:计算过程的中间变量缓冲区。 * buf:用于在 UDF 与引擎间的状态控制信息传递块。
- udfFinalizeFunc 用于对计算结果进行最终聚合。本例中 udfFinalizeFunc 对应的实现函数为 `void abs_max_finalize(char* dataOutput, char* interBuf, int* numOfOutput, SUdfInit* buf)`,其中各参数的具体含义是:
* dataOutput:输出数据的缓冲区。对 udfFinalizeFunc 来说,其输入数据也来自于这里。
* interBuf:系统使用的中间临时缓冲区,与 udfNormalFunc 中的同名参数含义一致。
* numOfOutput:输出数据的个数。
* buf:计算过程的中间变量缓冲区。
同样因为 abs_max 的计算过程无需用到中间变量缓存,所以同样是可以把 SUdfInit 定义成一个空结构体。 - udfFinalizeFunc 用于对计算结果进行最终计算,通常用于有 interBuf 使用的场景。本例中 udfFinalizeFunc 对应的实现函数为 `void abs_max_finalize(char* dataOutput, char* interBuf, int* numOfOutput, SUdfInit* buf)`,其中各参数的具体含义是:
* dataOutput:输出数据的缓冲区。
### 使用中间变量的聚合函数 * interBuf:中间结算结果缓冲区,可作为输入。
* numOfOutput:输出数据的个数,对聚合函数来说只能是0或者1。
* buf:用于在 UDF 与引擎间的状态控制信息传递块。
[sum_double.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/sum_double.c) 也是一个聚合函数,功能是对一组数据输出求和结果的倍数。
出于功能演示的目的,在这个用户定义函数的实现方法中,用到了中间变量缓冲区 buf。因此,在这个源代码文件中,SUdfInit 就不再是一个空的结构体,而是定义了缓冲区的具体存储内容。 ### 其他 UDF 函数
也正是因为用到了中间变量缓冲区,因此就需要对这一缓冲区进行初始化和资源释放。具体来说,也即对应 udfInitFunc(本例中,其实际的函数名是 `sum_double_init`)和 udfDestroyFunc(本例中,其实际的函数名是 `sum_double_destroy`。其函数名命名规则同样是采取以 udfNormalFunc 的实际函数名为前缀,以 `_init``_destroy` 为后缀。系统会在初始化和资源释放时调用对应名称的函数。 用户 UDF 程序除了需要实现上面几个函数外,还有两个用于初始化和释放 UDF 与引擎间的状态控制信息传递块的函数。具体来说,也即对应 udfInitFunc 和 udfDestroyFunc。其函数名命名规则同样是采取以 udfNormalFunc 的实际函数名为前缀,以 `_init``_destroy` 为后缀。系统会在初始化和资源释放时调用对应名称的函数。
- udfInitFunc 用于初始化中间变量缓冲区中的变量和内容。本例中 udfInitFunc 对应的实现函数为 `int sum_double_init(SUdfInit* buf)`,其中各参数的具体含义是: - udfInitFunc 用于初始化状态控制信息传递块。上例中 udfInitFunc 对应的实现函数为 `int abs_max_init(SUdfInit* buf)`,其中各参数的具体含义是:
* buf:计算过程的中间变量缓冲区 * buf:用于在 UDF 与引擎间的状态控制信息传递块
- udfDestroyFunc 用于释放中间变量缓冲区中的变量和内容。本例中 udfDestroyFunc 对应的实现函数为 `void sum_double_destroy(SUdfInit* buf)`,其中各参数的具体含义是: - udfDestroyFunc 用于释放状态控制信息传递块。上例中 udfDestroyFunc 对应的实现函数为 `void abs_max_destroy(SUdfInit* buf)`,其中各参数的具体含义是:
* buf:计算过程的中间变量缓冲区 * buf:用于在 UDF 与引擎间的状态控制信息传递块
注意,UDF 的实现过程中需要小心处理对中间变量缓冲区的使用,如果使用不当则有可能导致内存泄露或对资源的过度占用,甚至导致系统服务进程崩溃等 目前该功能暂时没有实际意义,待后续扩展使用
### UDF 实现方式的规则总结 ### UDF 实现方式的规则总结
根据所要实现的 UDF 类型不同,用户所要实现的功能函数内容也会有所区别 根据 UDF 函数类型的不同,用户所要实现的功能函数也不同
* 无需中间变量的标量函数:结构体 SUdfInit 可以为空,需实现 udfNormalFunc。 * 标量函数:UDF 中需实现 udfNormalFunc。
* 无需中间变量的聚合函数:结构体 SUdfInit 可以为空,需实现 udfNormalFunc、udfMergeFunc、udfFinalizeFunc。 * 聚合函数:UDF 中需实现 udfNormalFunc、udfMergeFunc(对超级表查询)、udfFinalizeFunc。
* 使用中间变量的标量函数:结构体 SUdfInit 需要具体定义,并需实现 udfNormalFunc、udfInitFunc、udfDestroyFunc。
* 使用中间变量的聚合函数:结构体 SUdfInit 需要具体定义,并需实现 udfNormalFunc、udfInitFunc、udfDestroyFunc、udfMergeFunc、udfFinalizeFunc 需要注意的是,如果对应的函数不需要具体的功能,也需要实现一个空函数
## 编译 UDF ## 编译 UDF
...@@ -97,28 +91,30 @@ gcc -g -O0 -fPIC -shared add_one.c -o add_one.so ...@@ -97,28 +91,30 @@ gcc -g -O0 -fPIC -shared add_one.c -o add_one.so
用户可以通过 SQL 指令在系统中加载客户端所在主机上的 UDF 函数库(不能通过 RESTful 接口或 HTTP 管理界面来进行这一过程)。一旦创建成功,则当前 TDengine 集群的所有用户都可以在 SQL 指令中使用这些函数。UDF 存储在系统的 MNode 节点上,因此即使重启 TDengine 系统,已经创建的 UDF 也仍然可用。 用户可以通过 SQL 指令在系统中加载客户端所在主机上的 UDF 函数库(不能通过 RESTful 接口或 HTTP 管理界面来进行这一过程)。一旦创建成功,则当前 TDengine 集群的所有用户都可以在 SQL 指令中使用这些函数。UDF 存储在系统的 MNode 节点上,因此即使重启 TDengine 系统,已经创建的 UDF 也仍然可用。
在创建 UDF 时,需要区分标量函数和聚合函数。如果创建时声明了错误的函数类别,则可能导致通过 SQL 指令调用函数时出错。 在创建 UDF 时,需要区分标量函数和聚合函数。如果创建时声明了错误的函数类别,则可能导致通过 SQL 指令调用函数时出错。此外, UDF 支持输入与输出类型不一致,用户需要保证输入数据类型与 UDF 程序匹配,UDF 输出数据类型与 OUTPUTTYPE 匹配。
- 创建标量函数:`CREATE FUNCTION ids(X) AS ids(Y) OUTPUTTYPE typename(Z) bufsize B;` - 创建标量函数:`CREATE FUNCTION ids(X) AS ids(Y) OUTPUTTYPE typename(Z) [ BUFSIZE B ];`
* ids(X):标量函数未来在 SQL 指令中被调用时的函数名,必须与函数实现中 udfNormalFunc 的实际名称一致; * ids(X):标量函数未来在 SQL 指令中被调用时的函数名,必须与函数实现中 udfNormalFunc 的实际名称一致;
* ids(Y):包含 UDF 函数实现的动态链接库的库文件路径(指的是库文件在当前客户端所在主机上的保存路径,通常是指向一个 .so 文件),这个路径需要用英文单引号或英文双引号括起来; * ids(Y):包含 UDF 函数实现的动态链接库的库文件绝对路径(指的是库文件在当前客户端所在主机上的保存路径,通常是指向一个 .so 文件),这个路径需要用英文单引号或英文双引号括起来;
* typename(Z):此函数计算结果的数据类型,与上文中 udfNormalFunc 的 itype 参数不同,这里不是使用数字表示法,而是直接写类型名称即可; * typename(Z):此函数计算结果的数据类型,与上文中 udfNormalFunc 的 itype 参数不同,这里不是使用数字表示法,而是直接写类型名称即可;
* B:系统使用的中间临时缓冲区大小,单位是字节,最小 0,最大 512,通常可以设置为 128 * B:中间计算结果的缓冲区大小,单位是字节,最小 0,最大 512,如果不使用可以不设置
例如,如下语句可以把 add_one.so 创建为系统中可用的 UDF: 例如,如下语句可以把 add_one.so 创建为系统中可用的 UDF:
```sql ```sql
CREATE FUNCTION add_one AS "/home/taos/udf_example/add_one.so" OUTPUTTYPE INT; CREATE FUNCTION add_one AS "/home/taos/udf_example/add_one.so" OUTPUTTYPE INT;
``` ```
- 创建聚合函数:`CREATE AGGREGATE FUNCTION ids(X) AS ids(Y) OUTPUTTYPE typename(Z) bufsize B;` - 创建聚合函数:`CREATE AGGREGATE FUNCTION ids(X) AS ids(Y) OUTPUTTYPE typename(Z) [ BUFSIZE B ];`
* ids(X):聚合函数未来在 SQL 指令中被调用时的函数名,必须与函数实现中 udfNormalFunc 的实际名称一致; * ids(X):聚合函数未来在 SQL 指令中被调用时的函数名,必须与函数实现中 udfNormalFunc 的实际名称一致;
* ids(Y):包含 UDF 函数实现的动态链接库的库文件路径(指的是库文件在当前客户端所在主机上的保存路径,通常是指向一个 .so 文件),这个路径需要用英文单引号或英文双引号括起来; * ids(Y):包含 UDF 函数实现的动态链接库的库文件绝对路径(指的是库文件在当前客户端所在主机上的保存路径,通常是指向一个 .so 文件),这个路径需要用英文单引号或英文双引号括起来;
* typename(Z):此函数计算结果的数据类型,与上文中 udfNormalFunc 的 itype 参数不同,这里不是使用数字表示法,而是直接写类型名称即可; * typename(Z):此函数计算结果的数据类型,与上文中 udfNormalFunc 的 itype 参数不同,这里不是使用数字表示法,而是直接写类型名称即可;
* B:系统使用的中间临时缓冲区大小,单位是字节,最小 0,最大 512,通常可以设置为 128 * B:中间计算结果的缓冲区大小,单位是字节,最小 0,最大 512,如果不使用可以不设置
例如,如下语句可以把 abs_max.so 创建为系统中可用的 UDF: 关于中间计算结果的使用,可以参考示例程序[demo.c](https://github.com/taosdata/TDengine/blob/develop/tests/script/sh/demo.c)
例如,如下语句可以把 demo.so 创建为系统中可用的 UDF:
```sql ```sql
CREATE AGGREGATE FUNCTION abs_max AS "/home/taos/udf_example/abs_max.so" OUTPUTTYPE BIGINT bufsize 128; CREATE AGGREGATE FUNCTION demo AS "/home/taos/udf_example/demo.so" OUTPUTTYPE DOUBLE bufsize 14;
``` ```
### 管理 UDF ### 管理 UDF
...@@ -140,7 +136,7 @@ SELECT X(c) FROM table/stable; ...@@ -140,7 +136,7 @@ SELECT X(c) FROM table/stable;
在当前版本下,使用 UDF 存在如下这些限制: 在当前版本下,使用 UDF 存在如下这些限制:
1. 在创建和调用 UDF 时,服务端和客户端都只支持 Linux 操作系统; 1. 在创建和调用 UDF 时,服务端和客户端都只支持 Linux 操作系统;
2. UDF 不能与系统内建的 SQL 函数混合使用; 2. UDF 不能与系统内建的 SQL 函数混合使用,暂不支持在一条 SQL 语句中使用多个不同名的 UDF
3. UDF 只支持以单个数据列作为输入; 3. UDF 只支持以单个数据列作为输入;
4. UDF 只要创建成功,就会被持久化存储到 MNode 节点中; 4. UDF 只要创建成功,就会被持久化存储到 MNode 节点中;
5. 无法通过 RESTful 接口来创建 UDF; 5. 无法通过 RESTful 接口来创建 UDF;
......
...@@ -171,6 +171,7 @@ TDengine 缺省的时间戳是毫秒精度,但通过在 CREATE DATABASE 时传 ...@@ -171,6 +171,7 @@ TDengine 缺省的时间戳是毫秒精度,但通过在 CREATE DATABASE 时传
4) 子表名只能由字母、数字和下划线组成,且不能以数字开头,不区分大小写 4) 子表名只能由字母、数字和下划线组成,且不能以数字开头,不区分大小写
5) 使用数据类型 binary 或 nchar,需指定其最长的字节数,如 binary(20),表示 20 字节; 5) 使用数据类型 binary 或 nchar,需指定其最长的字节数,如 binary(20),表示 20 字节;
6) 为了兼容支持更多形式的表名,TDengine 引入新的转义符 "\`",可以让表名与关键词不冲突,同时不受限于上述表名称合法性约束检查。但是同样具有长度限制要求。使用转义字符以后,不再对转义字符中的内容进行大小写统一。 6) 为了兼容支持更多形式的表名,TDengine 引入新的转义符 "\`",可以让表名与关键词不冲突,同时不受限于上述表名称合法性约束检查。但是同样具有长度限制要求。使用转义字符以后,不再对转义字符中的内容进行大小写统一。
例如:\`aBc\` 和 \`abc\` 是不同的表名,但是 abc 和 aBc 是相同的表名。 例如:\`aBc\` 和 \`abc\` 是不同的表名,但是 abc 和 aBc 是相同的表名。
需要注意的是转义字符中的内容必须是可打印字符。 需要注意的是转义字符中的内容必须是可打印字符。
...@@ -1601,7 +1602,7 @@ SELECT AVG(current), MAX(current), LEASTSQUARES(current, start_val, step_val), P ...@@ -1601,7 +1602,7 @@ SELECT AVG(current), MAX(current), LEASTSQUARES(current, start_val, step_val), P
**GROUP BY的限制** **GROUP BY的限制**
TAOS SQL 支持对标签、TBNAME 进行 GROUP BY 操作,也支持普通列进行 GROUP BY,前提是:仅限一列且该列的唯一值小于 10 万个。 TAOS SQL 支持对标签、TBNAME 进行 GROUP BY 操作,也支持普通列进行 GROUP BY,前提是:仅限一列且该列的唯一值小于 10 万个。注意:group by 不支持float,double 类型。
**IS NOT NULL 与不为空的表达式适用范围** **IS NOT NULL 与不为空的表达式适用范围**
......
...@@ -183,9 +183,10 @@ TDengine 中时间戳的时区总是由客户端进行处理,而与服务端 ...@@ -183,9 +183,10 @@ TDengine 中时间戳的时区总是由客户端进行处理,而与服务端
| TCP | 6035 | 多节点集群的节点间通讯。 | 随 serverPort 端口变化。 | | TCP | 6035 | 多节点集群的节点间通讯。 | 随 serverPort 端口变化。 |
| TCP | 6040 | 多节点集群的节点间数据同步。 | 随 serverPort 端口变化。 | | TCP | 6040 | 多节点集群的节点间数据同步。 | 随 serverPort 端口变化。 |
| TCP | 6041 | 客户端与服务端之间的 RESTful 通讯。 | 随 serverPort 端口变化。 | | TCP | 6041 | 客户端与服务端之间的 RESTful 通讯。 | 随 serverPort 端口变化。 |
| TCP | 6042 | Arbitrator 的服务端口。 | 随 Arbitrator 启动参数设置变化。 | | TCP | 6042 | Arbitrator 的服务端口。 | 随 Arbitrator 启动参数设置变化。 |
| TCP | 6043 | 支持 collectd 数据接入端口。 | 随 BLM3 启动参数设置变化(2.3.0.1+以上版本)。 | | TCP | 6043 | TaosKeeper 监控服务端口。 | 随 TaosKeeper 启动参数设置变化。 |
| TCP | 6044 | 支持 StatsD 的数据接入端口。 | 随 BLM3 启动参数设置变化(2.3.0.1+以上版本)。 | | TCP | 6044 | 支持 StatsD 的数据接入端口。 | 随 BLM3 启动参数设置变化(2.3.0.1+以上版本)。 |
| TCP | 6045 | 支持 collectd 数据接入端口。 | 随 BLM3 启动参数设置变化(2.3.0.1+以上版本)。 |
| TCP | 6060 | 企业版内 Monitor 服务的网络端口。 | | | TCP | 6060 | 企业版内 Monitor 服务的网络端口。 | |
| UDP | 6030-6034 | 客户端与服务端之间通讯。 | 随 serverPort 端口变化。 | | UDP | 6030-6034 | 客户端与服务端之间通讯。 | 随 serverPort 端口变化。 |
| UDP | 6035-6039 | 多节点集群的节点间通讯。 | 随 serverPort 端口变化。 | | UDP | 6035-6039 | 多节点集群的节点间通讯。 | 随 serverPort 端口变化。 |
...@@ -193,12 +194,14 @@ TDengine 中时间戳的时区总是由客户端进行处理,而与服务端 ...@@ -193,12 +194,14 @@ TDengine 中时间戳的时区总是由客户端进行处理,而与服务端
## 20. go 语言编写组件编译失败怎样解决? ## 20. go 语言编写组件编译失败怎样解决?
新版本 TDengine 2.3.0.0 包含一个使用 go 语言开发的 BLM3 组件,取代之前内置的 httpd ,提供包含原 httpd 功能以及支持多种其他软件(Prometheus、Telegraf、collectd、StatsD等)的数据接入功能。 新版本 TDengine 2.3.0.0 包含一个使用 go 语言开发的 BLM3 组件,取代之前内置的 httpd ,提供包含原 httpd 功能以及支持多种其他软件(Prometheus、Telegraf、collectd、StatsD等)的数据接入功能。
使用最新 develop 分支代码编译需要先 git submodule update --init --recursive 下载 blm3 仓库代码后再编译。 使用最新 develop 分支代码编译需要先 `git submodule update --init --recursive` 下载 blm3 仓库代码后再编译。
目前编译方式默认自动编译 blm3。go 语言版本要求 1.14 以上,如果发生 go 编译错误,往往是国内访问 go mod 问题,可以通过设置 go 环境变量来解决: 目前编译方式默认自动编译 blm3。go 语言版本要求 1.14 以上,如果发生 go 编译错误,往往是国内访问 go mod 问题,可以通过设置 go 环境变量来解决:
```sh
go env -w GO111MODULE=on go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct go env -w GOPROXY=https://goproxy.cn,direct
```
如果希望继续使用之前的内置 httpd,可以关闭 blm3 编译,使用 如果希望继续使用之前的内置 httpd,可以关闭 blm3 编译,使用
cmake .. -DBUILD_HTTP=true 使用原来内置的 httpd。 `cmake .. -DBUILD_HTTP=true` 使用原来内置的 httpd。
...@@ -57,7 +57,7 @@ repeater 部分添加 { host:'<TDengine server/cluster host>', port: <port for S ...@@ -57,7 +57,7 @@ repeater 部分添加 { host:'<TDengine server/cluster host>', port: <port for S
### 导入 Dashboard ### 导入 Dashboard
使用 Web 浏览器访问 IP:3000 登录 Grafana 界面,系统初始用户名密码为 admin/admin。 使用 Web 浏览器访问运行 Grafana 的服务器的3000端口 host:3000 登录 Grafana 界面,系统初始用户名密码为 admin/admin。
点击左侧齿轮图标并选择 Plugins,应该可以找到 TDengine data source 插件图标。 点击左侧齿轮图标并选择 Plugins,应该可以找到 TDengine data source 插件图标。
#### 导入 collectd 仪表盘 #### 导入 collectd 仪表盘
......
...@@ -301,3 +301,6 @@ keepColumnName 1 ...@@ -301,3 +301,6 @@ keepColumnName 1
# force TCP transmission # force TCP transmission
# rpcForceTcp 0 # rpcForceTcp 0
# unit MB. Flush vnode wal file if walSize > walFlushSize and walSize > cache*0.5*blocks
# walFlushSize 1024
...@@ -4,21 +4,19 @@ WORKDIR /root ...@@ -4,21 +4,19 @@ WORKDIR /root
ARG pkgFile ARG pkgFile
ARG dirName ARG dirName
RUN echo ${pkgFile} RUN echo ${pkgFile} && echo ${dirName}
RUN echo ${dirName}
COPY ${pkgFile} /root/ COPY ${pkgFile} /root/
RUN tar -zxf ${pkgFile} RUN tar -zxf ${pkgFile}
WORKDIR /root/${dirName}/ WORKDIR /root/${dirName}/
RUN /bin/bash install.sh -e no RUN /bin/bash install.sh -e no
RUN apt-get clean && apt-get update && apt-get install -y locales RUN apt-get clean && apt-get update && apt-get install -y locales && locale-gen en_US.UTF-8
RUN locale-gen en_US.UTF-8 ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib" \
ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib" LC_CTYPE=en_US.UTF-8 \
ENV LC_CTYPE=en_US.UTF-8 LANG=en_US.UTF-8 \
ENV LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
EXPOSE 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 EXPOSE 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042
CMD ["taosd"] CMD ["taosd"]
VOLUME [ "/var/lib/taos", "/var/log/taos","/etc/taos/" ] VOLUME [ "/var/lib/taos", "/var/log/taos","/etc/taos/" ]
\ No newline at end of file
...@@ -395,8 +395,9 @@ function install_connector() { ...@@ -395,8 +395,9 @@ function install_connector() {
${csudo} cp -rf ${source_dir}/src/connector/python ${install_main_dir}/connector ${csudo} cp -rf ${source_dir}/src/connector/python ${install_main_dir}/connector
${csudo} cp ${binary_dir}/build/lib/*.jar ${install_main_dir}/connector &> /dev/null && ${csudo} chmod 777 ${install_main_dir}/connector/*.jar || echo &> /dev/null ${csudo} cp ${binary_dir}/build/lib/*.jar ${install_main_dir}/connector &> /dev/null && ${csudo} chmod 777 ${install_main_dir}/connector/*.jar || echo &> /dev/null
else else
${csudo} cp -rf ${source_dir}/src/connector/python ${install_main_dir}/connector || ${csudo} cp -rf ${source_dir}/src/connector/python ${install_main_2_dir}/connector} ${csudo} cp -rf ${source_dir}/src/connector/python ${install_main_dir}/connector || ${csudo} cp -rf ${source_dir}/src/connector/python ${install_main_2_dir}/connector
${csudo} cp ${binary_dir}/build/lib/*.jar ${install_main_dir}/connector &> /dev/null || cp ${binary_dir}/build/lib/*.jar ${install_main_2_dir}/connector &> /dev/null && ${csudo} chmod 777 ${install_main_dir}/connector/*.jar || ${csudo} chmod 777 ${install_main_2_dir}/connector/*.jar || echo &> /dev/null ${csudo} cp ${binary_dir}/build/lib/*.jar ${install_main_dir}/connector &> /dev/null && ${csudo} chmod 777 ${install_main_dir}/connector/*.jar || echo &> /dev/null
${csudo} cp ${binary_dir}/build/lib/*.jar ${install_main_2_dir}/connector &> /dev/null && ${csudo} chmod 777 ${install_main_2_dir}/connector/*.jar || echo &> /dev/null
fi fi
} }
......
...@@ -23,6 +23,8 @@ extern "C" { ...@@ -23,6 +23,8 @@ extern "C" {
#define SML_TIMESTAMP_SECOND_DIGITS 10 #define SML_TIMESTAMP_SECOND_DIGITS 10
#define SML_TIMESTAMP_MILLI_SECOND_DIGITS 13 #define SML_TIMESTAMP_MILLI_SECOND_DIGITS 13
typedef TSDB_SML_PROTOCOL_TYPE SMLProtocolType;
typedef struct { typedef struct {
char* key; char* key;
uint8_t type; uint8_t type;
...@@ -46,27 +48,23 @@ typedef struct { ...@@ -46,27 +48,23 @@ typedef struct {
} TAOS_SML_DATA_POINT; } TAOS_SML_DATA_POINT;
typedef enum { typedef enum {
SML_TIME_STAMP_NOW, SML_TIME_STAMP_NOT_CONFIGURED,
SML_TIME_STAMP_HOURS, SML_TIME_STAMP_HOURS,
SML_TIME_STAMP_MINUTES, SML_TIME_STAMP_MINUTES,
SML_TIME_STAMP_SECONDS, SML_TIME_STAMP_SECONDS,
SML_TIME_STAMP_MILLI_SECONDS, SML_TIME_STAMP_MILLI_SECONDS,
SML_TIME_STAMP_MICRO_SECONDS, SML_TIME_STAMP_MICRO_SECONDS,
SML_TIME_STAMP_NANO_SECONDS, SML_TIME_STAMP_NANO_SECONDS,
SML_TIME_STAMP_NOT_CONFIGURED SML_TIME_STAMP_NOW
} SMLTimeStampType; } SMLTimeStampType;
typedef enum {
SML_LINE_PROTOCOL = 0,
SML_TELNET_PROTOCOL = 1,
SML_JSON_PROTOCOL = 2,
} SMLProtocolType;
typedef struct { typedef struct {
uint64_t id; uint64_t id;
SMLProtocolType protocol; SMLProtocolType protocol;
SMLTimeStampType tsType; SMLTimeStampType tsType;
SHashObj* smlDataToSchema; SHashObj* smlDataToSchema;
int64_t affectedRows;
} SSmlLinesInfo; } SSmlLinesInfo;
int tscSmlInsert(TAOS* taos, TAOS_SML_DATA_POINT* points, int numPoint, SSmlLinesInfo* info); int tscSmlInsert(TAOS* taos, TAOS_SML_DATA_POINT* points, int numPoint, SSmlLinesInfo* info);
...@@ -83,12 +81,12 @@ int32_t convertSmlTimeStamp(TAOS_SML_KV *pVal, char *value, ...@@ -83,12 +81,12 @@ int32_t convertSmlTimeStamp(TAOS_SML_KV *pVal, char *value,
void destroySmlDataPoint(TAOS_SML_DATA_POINT* point); void destroySmlDataPoint(TAOS_SML_DATA_POINT* point);
int taos_insert_sml_lines(TAOS* taos, char* lines[], int numLines, int taos_insert_lines(TAOS* taos, char* lines[], int numLines, SMLProtocolType protocol,
SMLProtocolType protocol, SMLTimeStampType tsType); SMLTimeStampType tsType, int* affectedRows);
int taos_insert_telnet_lines(TAOS* taos, char* lines[], int numLines, int taos_insert_telnet_lines(TAOS* taos, char* lines[], int numLines, SMLProtocolType protocol,
SMLProtocolType protocol, SMLTimeStampType tsType); SMLTimeStampType tsType, int* affectedRows);
int taos_insert_json_payload(TAOS* taos, char* payload, int taos_insert_json_payload(TAOS* taos, char* payload, SMLProtocolType protocol,
SMLProtocolType protocol, SMLTimeStampType tsType); SMLTimeStampType tsType, int* affectedRows);
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -1053,7 +1053,8 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setTableNameTagsI ...@@ -1053,7 +1053,8 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setTableNameTagsI
} }
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JNIEnv *env, jobject jobj, JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(JNIEnv *env, jobject jobj,
jobjectArray lines, jlong conn) { jobjectArray lines, jlong conn,
jint protocol, jint precision) {
TAOS *taos = (TAOS *)conn; TAOS *taos = (TAOS *)conn;
if (taos == NULL) { if (taos == NULL) {
jniError("jobj:%p, connection already closed", jobj); jniError("jobj:%p, connection already closed", jobj);
...@@ -1071,7 +1072,8 @@ JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(J ...@@ -1071,7 +1072,8 @@ JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(J
c_lines[i] = (char *)(*env)->GetStringUTFChars(env, line, 0); c_lines[i] = (char *)(*env)->GetStringUTFChars(env, line, 0);
} }
int code = taos_schemaless_insert(taos, c_lines, numLines, SML_LINE_PROTOCOL, "ms"); SSqlObj* result = (SSqlObj*)taos_schemaless_insert(taos, c_lines, numLines, protocol, precision);
int code = taos_errno(result);
for (int i = 0; i < numLines; ++i) { for (int i = 0; i < numLines; ++i) {
jstring line = (jstring)((*env)->GetObjectArrayElement(env, lines, i)); jstring line = (jstring)((*env)->GetObjectArrayElement(env, lines, i));
...@@ -1080,9 +1082,10 @@ JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(J ...@@ -1080,9 +1082,10 @@ JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_insertLinesImp(J
tfree(c_lines); tfree(c_lines);
if (code != TSDB_CODE_SUCCESS) { if (code != TSDB_CODE_SUCCESS) {
jniError("jobj:%p, conn:%p, code:%s", jobj, taos, tstrerror(code)); jniError("jobj:%p, conn:%p, code:%s, msg:%s", jobj, taos, tstrerror(code), taos_errstr(result));
return JNI_TDENGINE_ERROR; return JNI_TDENGINE_ERROR;
} }
return code;
return (jlong)result;
} }
...@@ -761,7 +761,7 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam ...@@ -761,7 +761,7 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam
code = taos_stmt_prepare(stmt, sql, (unsigned long)strlen(sql)); code = taos_stmt_prepare(stmt, sql, (unsigned long)strlen(sql));
if (code != 0) { if (code != 0) {
tscError("SML:0x%"PRIx64" taos_stmt_prepare return %d:%s", info->id, code, tstrerror(code)); tscError("SML:0x%"PRIx64" taos_stmt_prepare return %d:%s", info->id, code, taos_stmt_errstr(stmt));
taos_stmt_close(stmt); taos_stmt_close(stmt);
return code; return code;
} }
...@@ -771,7 +771,11 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam ...@@ -771,7 +771,11 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam
do { do {
code = taos_stmt_set_tbname(stmt, cTableName); code = taos_stmt_set_tbname(stmt, cTableName);
if (code != 0) { if (code != 0) {
tscError("SML:0x%"PRIx64" taos_stmt_set_tbname return %d:%s", info->id, code, tstrerror(code)); tscError("SML:0x%"PRIx64" taos_stmt_set_tbname return %d:%s", info->id, code, taos_stmt_errstr(stmt));
int affectedRows = taos_stmt_affected_rows(stmt);
info->affectedRows += affectedRows;
taos_stmt_close(stmt); taos_stmt_close(stmt);
return code; return code;
} }
...@@ -781,13 +785,21 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam ...@@ -781,13 +785,21 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam
TAOS_BIND* colsBinds = taosArrayGetP(batchBind, i); TAOS_BIND* colsBinds = taosArrayGetP(batchBind, i);
code = taos_stmt_bind_param(stmt, colsBinds); code = taos_stmt_bind_param(stmt, colsBinds);
if (code != 0) { if (code != 0) {
tscError("SML:0x%"PRIx64" taos_stmt_bind_param return %d:%s", info->id, code, tstrerror(code)); tscError("SML:0x%"PRIx64" taos_stmt_bind_param return %d:%s", info->id, code, taos_stmt_errstr(stmt));
int affectedRows = taos_stmt_affected_rows(stmt);
info->affectedRows += affectedRows;
taos_stmt_close(stmt); taos_stmt_close(stmt);
return code; return code;
} }
code = taos_stmt_add_batch(stmt); code = taos_stmt_add_batch(stmt);
if (code != 0) { if (code != 0) {
tscError("SML:0x%"PRIx64" taos_stmt_add_batch return %d:%s", info->id, code, tstrerror(code)); tscError("SML:0x%"PRIx64" taos_stmt_add_batch return %d:%s", info->id, code, taos_stmt_errstr(stmt));
int affectedRows = taos_stmt_affected_rows(stmt);
info->affectedRows += affectedRows;
taos_stmt_close(stmt); taos_stmt_close(stmt);
return code; return code;
} }
...@@ -795,9 +807,10 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam ...@@ -795,9 +807,10 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam
code = taos_stmt_execute(stmt); code = taos_stmt_execute(stmt);
if (code != 0) { if (code != 0) {
tscError("SML:0x%"PRIx64" taos_stmt_execute return %d:%s, try:%d", info->id, code, tstrerror(code), try); tscError("SML:0x%"PRIx64" taos_stmt_execute return %d:%s, try:%d", info->id, code, taos_stmt_errstr(stmt), try);
} }
tscDebug("SML:0x%"PRIx64" taos_stmt_execute inserted %d rows", info->id, taos_stmt_affected_rows(stmt));
tryAgain = false; tryAgain = false;
if ((code == TSDB_CODE_TDB_INVALID_TABLE_ID if ((code == TSDB_CODE_TDB_INVALID_TABLE_ID
|| code == TSDB_CODE_VND_INVALID_VGROUP_ID || code == TSDB_CODE_VND_INVALID_VGROUP_ID
...@@ -825,6 +838,8 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam ...@@ -825,6 +838,8 @@ static int32_t doInsertChildTableWithStmt(TAOS* taos, char* sql, char* cTableNam
} }
} while (tryAgain); } while (tryAgain);
int affectedRows = taos_stmt_affected_rows(stmt);
info->affectedRows += affectedRows;
taos_stmt_close(stmt); taos_stmt_close(stmt);
return code; return code;
...@@ -1069,6 +1084,8 @@ int tscSmlInsert(TAOS* taos, TAOS_SML_DATA_POINT* points, int numPoint, SSmlLine ...@@ -1069,6 +1084,8 @@ int tscSmlInsert(TAOS* taos, TAOS_SML_DATA_POINT* points, int numPoint, SSmlLine
int32_t code = TSDB_CODE_SUCCESS; int32_t code = TSDB_CODE_SUCCESS;
info->affectedRows = 0;
tscDebug("SML:0x%"PRIx64" build data point schemas", info->id); tscDebug("SML:0x%"PRIx64" build data point schemas", info->id);
SArray* stableSchemas = taosArrayInit(32, sizeof(SSmlSTableSchema)); // SArray<STableColumnsSchema> SArray* stableSchemas = taosArrayInit(32, sizeof(SSmlSTableSchema)); // SArray<STableColumnsSchema>
code = buildDataPointSchemas(points, numPoint, stableSchemas, info); code = buildDataPointSchemas(points, numPoint, stableSchemas, info);
...@@ -1429,13 +1446,13 @@ static bool isTimeStamp(char *pVal, uint16_t len, SMLTimeStampType *tsType, SSml ...@@ -1429,13 +1446,13 @@ static bool isTimeStamp(char *pVal, uint16_t len, SMLTimeStampType *tsType, SSml
//Default no appendix //Default no appendix
if (isdigit(pVal[len - 1]) && isdigit(pVal[len - 2])) { if (isdigit(pVal[len - 1]) && isdigit(pVal[len - 2])) {
if (info->protocol == SML_LINE_PROTOCOL) { if (info->protocol == TSDB_SML_LINE_PROTOCOL) {
if (info->tsType != SML_TIME_STAMP_NOT_CONFIGURED) { if (info->tsType != SML_TIME_STAMP_NOT_CONFIGURED) {
*tsType = info->tsType; *tsType = info->tsType;
} else { } else {
*tsType = SML_TIME_STAMP_NANO_SECONDS; *tsType = SML_TIME_STAMP_NANO_SECONDS;
} }
} else if (info->protocol == SML_TELNET_PROTOCOL) { } else if (info->protocol == TSDB_SML_TELNET_PROTOCOL) {
if (len == SML_TIMESTAMP_SECOND_DIGITS) { if (len == SML_TIMESTAMP_SECOND_DIGITS) {
*tsType = SML_TIME_STAMP_SECONDS; *tsType = SML_TIME_STAMP_SECONDS;
} else if (len == SML_TIMESTAMP_MILLI_SECOND_DIGITS) { } else if (len == SML_TIMESTAMP_MILLI_SECOND_DIGITS) {
...@@ -1871,7 +1888,7 @@ static int32_t parseSmlKey(TAOS_SML_KV *pKV, const char **index, SHashObj *pHash ...@@ -1871,7 +1888,7 @@ static int32_t parseSmlKey(TAOS_SML_KV *pKV, const char **index, SHashObj *pHash
//key field cannot start with digit //key field cannot start with digit
if (isdigit(*cur)) { if (isdigit(*cur)) {
tscError("SML:0x%"PRIx64" Tag key cannnot start with digit", info->id); tscError("SML:0x%"PRIx64" Tag key cannot start with digit", info->id);
return TSDB_CODE_TSC_LINE_SYNTAX_ERROR; return TSDB_CODE_TSC_LINE_SYNTAX_ERROR;
} }
while (*cur != '\0') { while (*cur != '\0') {
...@@ -1885,6 +1902,8 @@ static int32_t parseSmlKey(TAOS_SML_KV *pKV, const char **index, SHashObj *pHash ...@@ -1885,6 +1902,8 @@ static int32_t parseSmlKey(TAOS_SML_KV *pKV, const char **index, SHashObj *pHash
} }
//Escape special character //Escape special character
if (*cur == '\\') { if (*cur == '\\') {
//TODO: escape will work after column & tag
//support spcial characters
escapeSpecialCharacter(2, &cur); escapeSpecialCharacter(2, &cur);
} }
key[len] = *cur; key[len] = *cur;
...@@ -1911,13 +1930,42 @@ static int32_t parseSmlKey(TAOS_SML_KV *pKV, const char **index, SHashObj *pHash ...@@ -1911,13 +1930,42 @@ static int32_t parseSmlKey(TAOS_SML_KV *pKV, const char **index, SHashObj *pHash
static int32_t parseSmlValue(TAOS_SML_KV *pKV, const char **index, static int32_t parseSmlValue(TAOS_SML_KV *pKV, const char **index,
bool *is_last_kv, SSmlLinesInfo* info, bool isTag) { bool *is_last_kv, SSmlLinesInfo* info, bool isTag) {
const char *start, *cur; const char *start, *cur;
int32_t ret = TSDB_CODE_SUCCESS;
char *value = NULL; char *value = NULL;
uint16_t len = 0; uint16_t len = 0;
bool searchQuote = false;
start = cur = *index; start = cur = *index;
//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;
}
}
while (1) { while (1) {
// unescaped ',' or ' ' or '\0' identifies a value // unescaped ',' or ' ' or '\0' identifies a value
if ((*cur == ',' || *cur == ' ' || *cur == '\0') && *(cur - 1) != '\\') { 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;
break;
} else if (*cur == '\0') {
ret = TSDB_CODE_TSC_LINE_SYNTAX_ERROR;
goto error;
} else {
cur++;
len++;
continue;
}
}
//unescaped ' ' or '\0' indicates end of value //unescaped ' ' or '\0' indicates end of value
*is_last_kv = (*cur == ' ' || *cur == '\0') ? true : false; *is_last_kv = (*cur == ' ' || *cur == '\0') ? true : false;
if (*cur == ' ' && *(cur + 1) == ' ') { if (*cur == ' ' && *(cur + 1) == ' ') {
...@@ -1929,7 +1977,7 @@ static int32_t parseSmlValue(TAOS_SML_KV *pKV, const char **index, ...@@ -1929,7 +1977,7 @@ static int32_t parseSmlValue(TAOS_SML_KV *pKV, const char **index,
} }
//Escape special character //Escape special character
if (*cur == '\\') { if (*cur == '\\') {
escapeSpecialCharacter(2, &cur); escapeSpecialCharacter(isTag ? 2 : 3, &cur);
} }
cur++; cur++;
len++; len++;
...@@ -1946,16 +1994,20 @@ static int32_t parseSmlValue(TAOS_SML_KV *pKV, const char **index, ...@@ -1946,16 +1994,20 @@ static int32_t parseSmlValue(TAOS_SML_KV *pKV, const char **index,
if (!convertSmlValueType(pKV, value, len, info, isTag)) { if (!convertSmlValueType(pKV, value, len, info, isTag)) {
tscError("SML:0x%"PRIx64" Failed to convert sml value string(%s) to any type", tscError("SML:0x%"PRIx64" Failed to convert sml value string(%s) to any type",
info->id, value); info->id, value);
//free previous alocated key field
free(pKV->key);
pKV->key = NULL;
free(value); free(value);
return TSDB_CODE_TSC_INVALID_VALUE; ret = TSDB_CODE_TSC_INVALID_VALUE;
goto error;
} }
free(value); free(value);
*index = (*cur == '\0') ? cur : cur + 1; *index = (*cur == '\0') ? cur : cur + 1;
return TSDB_CODE_SUCCESS; return ret;
error:
//free previous alocated key field
free(pKV->key);
pKV->key = NULL;
return ret;
} }
static int32_t parseSmlMeasurement(TAOS_SML_DATA_POINT *pSml, const char **index, static int32_t parseSmlMeasurement(TAOS_SML_DATA_POINT *pSml, const char **index,
...@@ -2221,7 +2273,7 @@ int32_t tscParseLines(char* lines[], int numLines, SArray* points, SArray* faile ...@@ -2221,7 +2273,7 @@ int32_t tscParseLines(char* lines[], int numLines, SArray* points, SArray* faile
return TSDB_CODE_SUCCESS; return TSDB_CODE_SUCCESS;
} }
int taos_insert_lines(TAOS* taos, char* lines[], int numLines, SMLProtocolType protocol, SMLTimeStampType tsType) { int taos_insert_lines(TAOS* taos, char* lines[], int numLines, SMLProtocolType protocol, SMLTimeStampType tsType, int *affectedRows) {
int32_t code = 0; int32_t code = 0;
SSmlLinesInfo* info = tcalloc(1, sizeof(SSmlLinesInfo)); SSmlLinesInfo* info = tcalloc(1, sizeof(SSmlLinesInfo));
...@@ -2265,6 +2317,9 @@ int taos_insert_lines(TAOS* taos, char* lines[], int numLines, SMLProtocolType p ...@@ -2265,6 +2317,9 @@ int taos_insert_lines(TAOS* taos, char* lines[], int numLines, SMLProtocolType p
if (code != 0) { if (code != 0) {
tscError("SML:0x%"PRIx64" taos_sml_insert error: %s", info->id, tstrerror((code))); tscError("SML:0x%"PRIx64" taos_sml_insert error: %s", info->id, tstrerror((code)));
} }
if (affectedRows != NULL) {
*affectedRows = info->affectedRows;
}
cleanup: cleanup:
tscDebug("SML:0x%"PRIx64" taos_insert_lines finish inserting %d lines. code: %d", info->id, numLines, code); tscDebug("SML:0x%"PRIx64" taos_insert_lines finish inserting %d lines. code: %d", info->id, numLines, code);
...@@ -2280,52 +2335,56 @@ cleanup: ...@@ -2280,52 +2335,56 @@ cleanup:
return code; return code;
} }
int32_t convertPrecisionStrType(char* precision, SMLTimeStampType *tsType) { static int32_t convertPrecisionType(int precision, SMLTimeStampType *tsType) {
if (precision == NULL) { switch (precision) {
*tsType = SML_TIME_STAMP_NOT_CONFIGURED; case TSDB_SML_TIMESTAMP_NOT_CONFIGURED:
return TSDB_CODE_SUCCESS; *tsType = SML_TIME_STAMP_NOT_CONFIGURED;
} break;
if (strcmp(precision, "μ") == 0) { case TSDB_SML_TIMESTAMP_HOURS:
*tsType = SML_TIME_STAMP_MICRO_SECONDS; *tsType = SML_TIME_STAMP_HOURS;
return TSDB_CODE_SUCCESS; break;
case TSDB_SML_TIMESTAMP_MILLI_SECONDS:
*tsType = SML_TIME_STAMP_MILLI_SECONDS;
break;
case TSDB_SML_TIMESTAMP_NANO_SECONDS:
*tsType = SML_TIME_STAMP_NANO_SECONDS;
break;
case TSDB_SML_TIMESTAMP_MICRO_SECONDS:
*tsType = SML_TIME_STAMP_MICRO_SECONDS;
break;
case TSDB_SML_TIMESTAMP_SECONDS:
*tsType = SML_TIME_STAMP_SECONDS;
break;
case TSDB_SML_TIMESTAMP_MINUTES:
*tsType = SML_TIME_STAMP_MINUTES;
break;
default:
return TSDB_CODE_TSC_INVALID_PRECISION_TYPE;
} }
int32_t len = (int32_t)strlen(precision); return TSDB_CODE_SUCCESS;
if (len == 1) { }
switch (precision[0]) {
case 'u': //make a dummy SSqlObj
*tsType = SML_TIME_STAMP_MICRO_SECONDS; static SSqlObj* createSmlQueryObj(TAOS* taos, int32_t affected_rows, int32_t code) {
break; SSqlObj *pNew = (SSqlObj*)calloc(1, sizeof(SSqlObj));
case 's': if (pNew == NULL) {
*tsType = SML_TIME_STAMP_SECONDS; return NULL;
break;
case 'm':
*tsType = SML_TIME_STAMP_MINUTES;
break;
case 'h':
*tsType = SML_TIME_STAMP_HOURS;
break;
default:
return TSDB_CODE_TSC_INVALID_PRECISION_TYPE;
}
} else if (len == 2 && precision[1] == 's') {
switch (precision[0]) {
case 'm':
*tsType = SML_TIME_STAMP_MILLI_SECONDS;
break;
case 'n':
*tsType = SML_TIME_STAMP_NANO_SECONDS;
break;
default:
return TSDB_CODE_TSC_INVALID_PRECISION_TYPE;
}
} else {
return TSDB_CODE_TSC_INVALID_PRECISION_TYPE;
} }
pNew->signature = pNew;
pNew->pTscObj = taos;
return TSDB_CODE_SUCCESS; tsem_init(&pNew->rspSem, 0, 0);
registerSqlObj(pNew);
pNew->res.numOfRows = affected_rows;
pNew->res.code = code;
return pNew;
} }
/** /**
* taos_schemaless_insert() parse and insert data points into database according to * taos_schemaless_insert() parse and insert data points into database according to
* different protocol. * different protocol.
...@@ -2347,31 +2406,35 @@ int32_t convertPrecisionStrType(char* precision, SMLTimeStampType *tsType) { ...@@ -2347,31 +2406,35 @@ int32_t convertPrecisionStrType(char* precision, SMLTimeStampType *tsType) {
* *
*/ */
int taos_schemaless_insert(TAOS* taos, char* lines[], int numLines, int protocol, char* timePrecision) { TAOS_RES* taos_schemaless_insert(TAOS* taos, char* lines[], int numLines, int protocol, int precision) {
int code; int code = TSDB_CODE_SUCCESS;
int affected_rows = 0;
SMLTimeStampType tsType; SMLTimeStampType tsType;
if (protocol == SML_LINE_PROTOCOL) { if (protocol == TSDB_SML_LINE_PROTOCOL) {
code = convertPrecisionStrType(timePrecision, &tsType); code = convertPrecisionType(precision, &tsType);
if (code != TSDB_CODE_SUCCESS) { if (code != TSDB_CODE_SUCCESS) {
return code; return NULL;
} }
} }
switch (protocol) { switch (protocol) {
case SML_LINE_PROTOCOL: case TSDB_SML_LINE_PROTOCOL:
code = taos_insert_lines(taos, lines, numLines, protocol, tsType); code = taos_insert_lines(taos, lines, numLines, protocol, tsType, &affected_rows);
break; break;
case SML_TELNET_PROTOCOL: case TSDB_SML_TELNET_PROTOCOL:
code = taos_insert_telnet_lines(taos, lines, numLines, protocol, tsType); code = taos_insert_telnet_lines(taos, lines, numLines, protocol, tsType, &affected_rows);
break; break;
case SML_JSON_PROTOCOL: case TSDB_SML_JSON_PROTOCOL:
code = taos_insert_json_payload(taos, *lines, protocol, tsType); code = taos_insert_json_payload(taos, *lines, protocol, tsType, &affected_rows);
break; break;
default: default:
code = TSDB_CODE_TSC_INVALID_PROTOCOL_TYPE; code = TSDB_CODE_TSC_INVALID_PROTOCOL_TYPE;
break; break;
} }
return code;
SSqlObj *pSql = createSmlQueryObj(taos, affected_rows, code);
return (TAOS_RES*)pSql;
} }
...@@ -138,21 +138,41 @@ static int32_t parseTelnetMetricValue(TAOS_SML_KV **pKVs, int *num_kvs, const ch ...@@ -138,21 +138,41 @@ static int32_t parseTelnetMetricValue(TAOS_SML_KV **pKVs, int *num_kvs, const ch
const char *start, *cur; const char *start, *cur;
int32_t ret = TSDB_CODE_SUCCESS; int32_t ret = TSDB_CODE_SUCCESS;
int len = 0; int len = 0;
bool searchQuote = false;
char key[] = OTD_METRIC_VALUE_COLUMN_NAME; char key[] = OTD_METRIC_VALUE_COLUMN_NAME;
char *value = NULL; char *value = NULL;
start = cur = *index; start = cur = *index;
//if metric value is string
if (*cur == '"') {
searchQuote = true;
cur += 1;
len += 1;
} else if (*cur == 'L' && *(cur + 1) == '"') {
searchQuote = true;
cur += 2;
len += 2;
}
while(*cur != '\0') { while(*cur != '\0') {
if (*cur == ' ') { if (*cur == ' ') {
if (*cur == ' ') { if (searchQuote == true) {
if (*(cur + 1) != ' ') { if (*(cur - 1) == '"' && len != 1 && len != 2) {
break; searchQuote = false;
} else { } else {
cur++; cur++;
len++;
continue; continue;
} }
} }
if (*(cur + 1) != ' ') {
break;
} else {
cur++;
continue;
}
} }
cur++; cur++;
len++; len++;
...@@ -389,7 +409,7 @@ static int32_t tscParseTelnetLines(char* lines[], int numLines, SArray* points, ...@@ -389,7 +409,7 @@ static int32_t tscParseTelnetLines(char* lines[], int numLines, SArray* points,
return TSDB_CODE_SUCCESS; return TSDB_CODE_SUCCESS;
} }
int taos_insert_telnet_lines(TAOS* taos, char* lines[], int numLines, SMLProtocolType protocol, SMLTimeStampType tsType) { int taos_insert_telnet_lines(TAOS* taos, char* lines[], int numLines, SMLProtocolType protocol, SMLTimeStampType tsType, int* affectedRows) {
int32_t code = 0; int32_t code = 0;
SSmlLinesInfo* info = tcalloc(1, sizeof(SSmlLinesInfo)); SSmlLinesInfo* info = tcalloc(1, sizeof(SSmlLinesInfo));
...@@ -433,6 +453,9 @@ int taos_insert_telnet_lines(TAOS* taos, char* lines[], int numLines, SMLProtoco ...@@ -433,6 +453,9 @@ int taos_insert_telnet_lines(TAOS* taos, char* lines[], int numLines, SMLProtoco
if (code != 0) { if (code != 0) {
tscError("OTD:0x%"PRIx64" taos_insert_telnet_lines error: %s", info->id, tstrerror((code))); tscError("OTD:0x%"PRIx64" taos_insert_telnet_lines error: %s", info->id, tstrerror((code)));
} }
if (affectedRows != NULL) {
*affectedRows = info->affectedRows;
}
cleanup: cleanup:
tscDebug("OTD:0x%"PRIx64" taos_insert_telnet_lines finish inserting %d lines. code: %d", info->id, numLines, code); tscDebug("OTD:0x%"PRIx64" taos_insert_telnet_lines finish inserting %d lines. code: %d", info->id, numLines, code);
...@@ -1025,7 +1048,7 @@ PARSE_JSON_OVER: ...@@ -1025,7 +1048,7 @@ PARSE_JSON_OVER:
return ret; return ret;
} }
int taos_insert_json_payload(TAOS* taos, char* payload, SMLProtocolType protocol, SMLTimeStampType tsType) { int taos_insert_json_payload(TAOS* taos, char* payload, SMLProtocolType protocol, SMLTimeStampType tsType, int* affectedRows) {
int32_t code = 0; int32_t code = 0;
SSmlLinesInfo* info = tcalloc(1, sizeof(SSmlLinesInfo)); SSmlLinesInfo* info = tcalloc(1, sizeof(SSmlLinesInfo));
...@@ -1060,6 +1083,9 @@ int taos_insert_json_payload(TAOS* taos, char* payload, SMLProtocolType protocol ...@@ -1060,6 +1083,9 @@ int taos_insert_json_payload(TAOS* taos, char* payload, SMLProtocolType protocol
if (code != 0) { if (code != 0) {
tscError("OTD:0x%"PRIx64" taos_insert_json_payload error: %s", info->id, tstrerror((code))); tscError("OTD:0x%"PRIx64" taos_insert_json_payload error: %s", info->id, tstrerror((code)));
} }
if (affectedRows != NULL) {
*affectedRows = info->affectedRows;
}
cleanup: cleanup:
tscDebug("OTD:0x%"PRIx64" taos_insert_json_payload finish inserting 1 Point. code: %d", info->id, code); tscDebug("OTD:0x%"PRIx64" taos_insert_json_payload finish inserting 1 Point. code: %d", info->id, code);
......
...@@ -78,6 +78,8 @@ typedef struct STscStmt { ...@@ -78,6 +78,8 @@ typedef struct STscStmt {
SSqlObj* pSql; SSqlObj* pSql;
SMultiTbStmt mtb; SMultiTbStmt mtb;
SNormalStmt normal; SNormalStmt normal;
int numOfRows;
} STscStmt; } STscStmt;
#define STMT_RET(c) do { \ #define STMT_RET(c) do { \
...@@ -1212,6 +1214,8 @@ static int insertStmtExecute(STscStmt* stmt) { ...@@ -1212,6 +1214,8 @@ static int insertStmtExecute(STscStmt* stmt) {
// wait for the callback function to post the semaphore // wait for the callback function to post the semaphore
tsem_wait(&pSql->rspSem); tsem_wait(&pSql->rspSem);
stmt->numOfRows += pSql->res.numOfRows;
// data block reset // data block reset
pCmd->batchSize = 0; pCmd->batchSize = 0;
for(int32_t i = 0; i < pCmd->insertParam.numOfTables; ++i) { for(int32_t i = 0; i < pCmd->insertParam.numOfTables; ++i) {
...@@ -1284,7 +1288,9 @@ static int insertBatchStmtExecute(STscStmt* pStmt) { ...@@ -1284,7 +1288,9 @@ static int insertBatchStmtExecute(STscStmt* pStmt) {
tsem_wait(&pStmt->pSql->rspSem); tsem_wait(&pStmt->pSql->rspSem);
code = pStmt->pSql->res.code; code = pStmt->pSql->res.code;
pStmt->numOfRows += pStmt->pSql->res.numOfRows;
insertBatchClean(pStmt); insertBatchClean(pStmt);
return code; return code;
...@@ -1516,11 +1522,12 @@ TAOS_STMT* taos_stmt_init(TAOS* taos) { ...@@ -1516,11 +1522,12 @@ TAOS_STMT* taos_stmt_init(TAOS* taos) {
} }
tsem_init(&pSql->rspSem, 0, 0); tsem_init(&pSql->rspSem, 0, 0);
pSql->signature = pSql; pSql->signature = pSql;
pSql->pTscObj = pObj; pSql->pTscObj = pObj;
pSql->maxRetry = TSDB_MAX_REPLICA; pSql->maxRetry = TSDB_MAX_REPLICA;
pStmt->pSql = pSql; pStmt->pSql = pSql;
pStmt->last = STMT_INIT; pStmt->last = STMT_INIT;
pStmt->numOfRows = 0;
registerSqlObj(pSql); registerSqlObj(pSql);
return pStmt; return pStmt;
...@@ -1564,9 +1571,7 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) { ...@@ -1564,9 +1571,7 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
} }
pRes->qId = 0; pRes->qId = 0;
pRes->numOfRows = 1; pRes->numOfRows = 0;
registerSqlObj(pSql);
strtolower(pSql->sqlstr, sql); strtolower(pSql->sqlstr, sql);
tscDebugL("0x%"PRIx64" SQL: %s", pSql->self, pSql->sqlstr); tscDebugL("0x%"PRIx64" SQL: %s", pSql->self, pSql->sqlstr);
...@@ -1981,6 +1986,7 @@ int taos_stmt_execute(TAOS_STMT* stmt) { ...@@ -1981,6 +1986,7 @@ int taos_stmt_execute(TAOS_STMT* stmt) {
} else { } else {
taosReleaseRef(tscObjRef, pStmt->pSql->self); taosReleaseRef(tscObjRef, pStmt->pSql->self);
pStmt->pSql = taos_query((TAOS*)pStmt->taos, sql); pStmt->pSql = taos_query((TAOS*)pStmt->taos, sql);
pStmt->numOfRows += taos_affected_rows(pStmt->pSql);
ret = taos_errno(pStmt->pSql); ret = taos_errno(pStmt->pSql);
free(sql); free(sql);
} }
...@@ -1989,6 +1995,17 @@ int taos_stmt_execute(TAOS_STMT* stmt) { ...@@ -1989,6 +1995,17 @@ int taos_stmt_execute(TAOS_STMT* stmt) {
STMT_RET(ret); STMT_RET(ret);
} }
int taos_stmt_affected_rows(TAOS_STMT* stmt) {
STscStmt* pStmt = (STscStmt*)stmt;
if (pStmt == NULL) {
tscError("statement is invalid");
return 0;
}
return pStmt->numOfRows;
}
TAOS_RES *taos_stmt_use_result(TAOS_STMT* stmt) { TAOS_RES *taos_stmt_use_result(TAOS_STMT* stmt) {
if (stmt == NULL) { if (stmt == NULL) {
tscError("statement is invalid."); tscError("statement is invalid.");
......
此差异已折叠。
...@@ -1102,6 +1102,11 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) { ...@@ -1102,6 +1102,11 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
// support only one udf // support only one udf
if (pQueryInfo->pUdfInfo != NULL && taosArrayGetSize(pQueryInfo->pUdfInfo) > 0) { if (pQueryInfo->pUdfInfo != NULL && taosArrayGetSize(pQueryInfo->pUdfInfo) > 0) {
if (taosArrayGetSize(pQueryInfo->pUdfInfo) > 1) {
code = tscInvalidOperationMsg(pCmd->payload, "only one udf allowed", NULL);
goto _end;
}
pQueryMsg->udfContentOffset = htonl((int32_t) (pMsg - pCmd->payload)); pQueryMsg->udfContentOffset = htonl((int32_t) (pMsg - pCmd->payload));
for(int32_t i = 0; i < taosArrayGetSize(pQueryInfo->pUdfInfo); ++i) { for(int32_t i = 0; i < taosArrayGetSize(pQueryInfo->pUdfInfo); ++i) {
SUdfInfo* pUdfInfo = taosArrayGet(pQueryInfo->pUdfInfo, i); SUdfInfo* pUdfInfo = taosArrayGet(pQueryInfo->pUdfInfo, i);
......
此差异已折叠。
...@@ -108,9 +108,10 @@ extern int32_t tsQuorum; ...@@ -108,9 +108,10 @@ extern int32_t tsQuorum;
extern int8_t tsUpdate; extern int8_t tsUpdate;
extern int8_t tsCacheLastRow; extern int8_t tsCacheLastRow;
//tsdb //tsdb
extern bool tsdbForceKeepFile; extern bool tsdbForceKeepFile;
extern bool tsdbForceCompactFile; extern bool tsdbForceCompactFile;
extern int32_t tsdbWalFlushSize;
// balance // balance
extern int8_t tsEnableBalance; extern int8_t tsEnableBalance;
......
...@@ -155,8 +155,9 @@ int32_t tsTsdbMetaCompactRatio = TSDB_META_COMPACT_RATIO; ...@@ -155,8 +155,9 @@ int32_t tsTsdbMetaCompactRatio = TSDB_META_COMPACT_RATIO;
// tsdb config // tsdb config
// For backward compatibility // For backward compatibility
bool tsdbForceKeepFile = false; bool tsdbForceKeepFile = false;
bool tsdbForceCompactFile = false; // compact TSDB fileset forcibly bool tsdbForceCompactFile = false; // compact TSDB fileset forcibly
int32_t tsdbWalFlushSize = TSDB_DEFAULT_WAL_FLUSH_SIZE; // MB
// balance // balance
int8_t tsEnableBalance = 1; int8_t tsEnableBalance = 1;
...@@ -1652,6 +1653,17 @@ static void doInitGlobalConfig(void) { ...@@ -1652,6 +1653,17 @@ static void doInitGlobalConfig(void) {
cfg.unitType = TAOS_CFG_UTYPE_NONE; cfg.unitType = TAOS_CFG_UTYPE_NONE;
taosInitConfigOption(cfg); taosInitConfigOption(cfg);
// flush vnode wal file if walSize > walFlushSize and walSize > cache*0.5*blocks
cfg.option = "walFlushSize";
cfg.ptr = &tsdbWalFlushSize;
cfg.valType = TAOS_CFG_VTYPE_INT32;
cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_SHOW | TSDB_CFG_CTYPE_B_CLIENT;
cfg.minValue = TSDB_MIN_WAL_FLUSH_SIZE;
cfg.maxValue = TSDB_MAX_WAL_FLUSH_SIZE;
cfg.ptrLength = 0;
cfg.unitType = TAOS_CFG_UTYPE_MB;
taosInitConfigOption(cfg);
#ifdef TD_TSZ #ifdef TD_TSZ
// lossy compress // lossy compress
cfg.option = "lossyColumns"; cfg.option = "lossyColumns";
......
此差异已折叠。
...@@ -279,6 +279,10 @@ do { \ ...@@ -279,6 +279,10 @@ do { \
#define TSDB_MAX_TOTAL_BLOCKS 10000 #define TSDB_MAX_TOTAL_BLOCKS 10000
#define TSDB_DEFAULT_TOTAL_BLOCKS 6 #define TSDB_DEFAULT_TOTAL_BLOCKS 6
#define TSDB_MIN_WAL_FLUSH_SIZE 128 // MB
#define TSDB_MAX_WAL_FLUSH_SIZE 10000000 // MB
#define TSDB_DEFAULT_WAL_FLUSH_SIZE 1024 // MB
#define TSDB_MIN_TABLES 4 #define TSDB_MIN_TABLES 4
#define TSDB_MAX_TABLES 10000000 #define TSDB_MAX_TABLES 10000000
#define TSDB_DEFAULT_TABLES 1000000 #define TSDB_DEFAULT_TABLES 1000000
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册