未验证 提交 55d00662 编写于 作者: M Minglei Jin 提交者: GitHub

Merge branch 'develop' into fix/TS-927-d

......@@ -46,6 +46,7 @@ def pre_test(){
killall -9 gdb || echo "no gdb running"
killall -9 python3.8 || echo "no python program running"
cd ${WKC}
[ -f src/connector/grafanaplugin/README.md ] && rm -f src/connector/grafanaplugin/README.md > /dev/null || echo "failed to remove grafanaplugin README.md"
git reset --hard HEAD~10 >/dev/null
'''
script {
......@@ -121,6 +122,7 @@ def pre_test_noinstall(){
sh'hostname'
sh'''
cd ${WKC}
[ -f src/connector/grafanaplugin/README.md ] && rm -f src/connector/grafanaplugin/README.md > /dev/null || echo "failed to remove grafanaplugin README.md"
git reset --hard HEAD~10 >/dev/null
'''
script {
......@@ -193,6 +195,7 @@ def pre_test_mac(){
sh'hostname'
sh'''
cd ${WKC}
[ -f src/connector/grafanaplugin/README.md ] && rm -f src/connector/grafanaplugin/README.md > /dev/null || echo "failed to remove grafanaplugin README.md"
git reset --hard HEAD~10 >/dev/null
'''
script {
......
......@@ -53,6 +53,7 @@ TDengine 提供 3 个 UDF 的源代码示例,分别为:
* numOfOutput:输出数据的个数,对聚合函数来说只能是0或者1。
* buf:用于在 UDF 与引擎间的状态控制信息传递块。
其他典型场景,如协方差的计算,即可通过定义聚合UDF的方式实现。
### 其他 UDF 函数
......
......@@ -1350,18 +1350,18 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
```mysql
SELECT LAST_ROW(field_name) FROM { tb_name | stb_name };
```
功能说明:返回表/超级表的最后一条记录。
返回结果数据类型:同应用的字段。
应用字段:所有字段。
适用于:**表、超级表**。
限制:LAST_ROW() 不能与 INTERVAL 一起使用。
说明:在用于超级表时,时间戳完全一样且同为最大的数据行可能有多个,那么会从中随机返回一条,而并不保证多次运行所挑选的数据行必然一致。<br/>
<br/>示例:
功能说明:返回表/超级表的最后一条记录。
返回结果数据类型:同应用的字段。
应用字段:所有字段。
适用于:**表、超级表**。
限制:LAST_ROW() 不能与 INTERVAL 一起使用。
说明:在用于超级表时,时间戳完全一样且同为最大的数据行可能有多个,那么会从中随机返回一条,而并不保证多次运行所挑选的数据行必然一致。<br/>
<br/>示例:
```mysql
taos> SELECT LAST_ROW(current) FROM meters;
......@@ -1383,51 +1383,51 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
SELECT INTERP(field_name) FROM { tb_name | stb_name } [WHERE where_condition] [ RANGE(timestamp1,timestamp2) ] [EVERY(interval)] [FILL ({ VALUE | PREV | NULL | LINEAR | NEXT})];
```
功能说明:返回表/超级表的指定时间截面指定列的记录值(插值)。
功能说明:返回表/超级表的指定时间截面指定列的记录值(插值)。
返回结果数据类型:同字段类型。
返回结果数据类型:同字段类型。
应用字段:数值型字段。
应用字段:数值型字段。
适用于:**表、超级表、嵌套查询**。
适用于:**表、超级表、嵌套查询**。
说明:
1)INTERP用于在指定时间断面获取指定列的记录值,如果该时间断面不存在符合条件的行数据,那么会根据 FILL 参数的设定进行插值。
说明:
1)INTERP用于在指定时间断面获取指定列的记录值,如果该时间断面不存在符合条件的行数据,那么会根据 FILL 参数的设定进行插值。
2)INTERP的输入数据为指定列的数据,可以通过条件语句(where子句)来对原始列数据进行过滤,如果没有指定过滤条件则输入为全部数据。
2)INTERP的输入数据为指定列的数据,可以通过条件语句(where子句)来对原始列数据进行过滤,如果没有指定过滤条件则输入为全部数据。
3)INTERP的输出时间范围根据RANGE(timestamp1,timestamp2)字段来指定,需满足timestamp1<=timestamp2。其中timestamp1(必选值)为输出时间范围的起始值,即如果timestamp1时刻符合插值条件则timestamp1为输出的第一条记录,timestamp2(必选值)为输出时间范围的结束值,即输出的最后一条记录的timestamp不能大于timestamp2。如果没有指定RANGE,那么满足过滤条件的输入数据中第一条记录的timestamp即为timestamp1,最后一条记录的timestamp即为timestamp2,同样也满足timestamp1 <= timestamp2。
3)INTERP的输出时间范围根据RANGE(timestamp1,timestamp2)字段来指定,需满足timestamp1<=timestamp2。其中timestamp1(必选值)为输出时间范围的起始值,即如果timestamp1时刻符合插值条件则timestamp1为输出的第一条记录,timestamp2(必选值)为输出时间范围的结束值,即输出的最后一条记录的timestamp不能大于timestamp2。如果没有指定RANGE,那么满足过滤条件的输入数据中第一条记录的timestamp即为timestamp1,最后一条记录的timestamp即为timestamp2,同样也满足timestamp1 <= timestamp2。
4)INTERP根据EVERY字段来确定输出时间范围内的结果条数,即从timestamp1开始每隔固定长度的时间(EVERY值)进行插值。如果没有指定EVERY,则默认窗口大小为无穷大,即从timestamp1开始只有一个窗口。
4)INTERP根据EVERY字段来确定输出时间范围内的结果条数,即从timestamp1开始每隔固定长度的时间(EVERY值)进行插值。如果没有指定EVERY,则默认窗口大小为无穷大,即从timestamp1开始只有一个窗口。
5)INTERP根据FILL字段来决定在每个符合输出条件的时刻如何进行插值,如果没有FILL字段则默认不插值,即输出为原始记录值或不输出(原始记录不存在)。
5)INTERP根据FILL字段来决定在每个符合输出条件的时刻如何进行插值,如果没有FILL字段则默认不插值,即输出为原始记录值或不输出(原始记录不存在)。
6)INTERP只能在一个时间序列内进行插值,因此当作用于超级表时必须跟group by tbname一起使用,当作用嵌套查询外层时内层子查询不能含GROUP BY信息。
6)INTERP只能在一个时间序列内进行插值,因此当作用于超级表时必须跟group by tbname一起使用,当作用嵌套查询外层时内层子查询不能含GROUP BY信息。
7)INTERP的插值结果不受ORDER BY timestamp的影响,ORDER BY timestamp只影响输出结果的排序。
7)INTERP的插值结果不受ORDER BY timestamp的影响,ORDER BY timestamp只影响输出结果的排序。
SQL示例:
SQL示例:
1) 单点线性插值
```mysql
taos> SELECT INTERP(*) FROM t1 RANGE('2017-7-14 18:40:00','2017-7-14 18:40:00') FILL(LINEAR);
```
2) 在2017-07-14 18:00:00到2017-07-14 19:00:00间每隔5秒钟进行取值(不插值)
```mysql
taos> SELECT INTERP(*) FROM t1 RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s);
```
3) 在2017-07-14 18:00:00到2017-07-14 19:00:00间每隔5秒钟进行线性插值
```mysql
taos> SELECT INTERP(*) FROM t1 RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s) FILL(LINEAR);
```
4.在所有时间范围内每隔5秒钟进行向后插值
```mysql
taos> SELECT INTERP(*) FROM t1 EVERY(5s) FILL(NEXT);
```
5.根据2017-07-14 17:00:00到2017-07-14 20:00:00间的数据进行从2017-07-14 18:00:00到2017-07-14 19:00:00间每隔5秒钟进行线性插值
```mysql
taos> SELECT INTERP(*) FROM t1 where ts >= '2017-07-14 17:00:00' and ts <= '2017-07-14 20:00:00' RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s) FILL(LINEAR);
```
1) 单点线性插值
```mysql
taos> SELECT INTERP(*) FROM t1 RANGE('2017-7-14 18:40:00','2017-7-14 18:40:00') FILL(LINEAR);
```
2) 在2017-07-14 18:00:00到2017-07-14 19:00:00间每隔5秒钟进行取值(不插值)
```mysql
taos> SELECT INTERP(*) FROM t1 RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s);
```
3) 在2017-07-14 18:00:00到2017-07-14 19:00:00间每隔5秒钟进行线性插值
```mysql
taos> SELECT INTERP(*) FROM t1 RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s) FILL(LINEAR);
```
4.在所有时间范围内每隔5秒钟进行向后插值
```mysql
taos> SELECT INTERP(*) FROM t1 EVERY(5s) FILL(NEXT);
```
5.根据2017-07-14 17:00:00到2017-07-14 20:00:00间的数据进行从2017-07-14 18:00:00到2017-07-14 19:00:00间每隔5秒钟进行线性插值
```mysql
taos> SELECT INTERP(*) FROM t1 where ts >= '2017-07-14 17:00:00' and ts <= '2017-07-14 20:00:00' RANGE('2017-7-14 18:00:00','2017-7-14 19:00:00') EVERY(5s) FILL(LINEAR);
```
- **INTERP [2.3.1之前的版本]**
......@@ -1436,15 +1436,15 @@ SQL示例:
SELECT INTERP(field_name) FROM { tb_name | stb_name } WHERE ts='timestamp' [FILL ({ VALUE | PREV | NULL | LINEAR | NEXT})];
```
功能说明:返回表/超级表的指定时间截面、指定字段的记录。
功能说明:返回表/超级表的指定时间截面、指定字段的记录。
返回结果数据类型:同字段类型。
返回结果数据类型:同字段类型。
应用字段:数值型字段。
应用字段:数值型字段。
适用于:**表、超级表**。
适用于:**表、超级表**。
说明:(从 2.0.15.0 版本开始新增此函数) <br/>1)INTERP 必须指定时间断面,如果该时间断面不存在直接对应的数据,那么会根据 FILL 参数的设定进行插值。此外,条件语句里面可附带筛选条件,例如标签、tbname。<br/>2)INTERP 查询要求查询的时间区间必须位于数据集合(表)的所有记录的时间范围之内。如果给定的时间戳位于时间范围之外,即使有插值指令,仍然不返回结果。<br/>3)单个 INTERP 函数查询只能够针对一个时间点进行查询,如果需要返回等时间间隔的断面数据,可以通过 INTERP 配合 EVERY 的方式来进行查询处理(而不是使用 INTERVAL),其含义是每隔固定长度的时间进行插值。<br/>
说明:(从 2.0.15.0 版本开始新增此函数) <br/>1)INTERP 必须指定时间断面,如果该时间断面不存在直接对应的数据,那么会根据 FILL 参数的设定进行插值。此外,条件语句里面可附带筛选条件,例如标签、tbname。<br/>2)INTERP 查询要求查询的时间区间必须位于数据集合(表)的所有记录的时间范围之内。如果给定的时间戳位于时间范围之外,即使有插值指令,仍然不返回结果。<br/>3)单个 INTERP 函数查询只能够针对一个时间点进行查询,如果需要返回等时间间隔的断面数据,可以通过 INTERP 配合 EVERY 的方式来进行查询处理(而不是使用 INTERVAL),其含义是每隔固定长度的时间进行插值。<br/>
示例:
```mysql
......@@ -1455,7 +1455,7 @@ SQL示例:
Query OK, 1 row(s) in set (0.002652s)
```
如果给定的时间戳无对应的数据,在不指定插值生成策略的情况下,不会返回结果,如果指定了插值策略,会根据插值策略返回结果。
如果给定的时间戳无对应的数据,在不指定插值生成策略的情况下,不会返回结果,如果指定了插值策略,会根据插值策略返回结果。
```mysql
taos> SELECT INTERP(*) FROM meters WHERE tbname IN ('d636') AND ts='2017-7-14 18:40:00.005';
......@@ -1468,7 +1468,7 @@ SQL示例:
Query OK, 1 row(s) in set (0.003056s)
```
如下所示代码表示在时间区间 `['2017-7-14 18:40:00', '2017-7-14 18:40:00.014']` 中每隔 5 毫秒 进行一次断面计算。
如下所示代码表示在时间区间 `['2017-7-14 18:40:00', '2017-7-14 18:40:00.014']` 中每隔 5 毫秒 进行一次断面计算。
```mysql
taos> SELECT INTERP(current) FROM d636 WHERE ts>='2017-7-14 18:40:00' AND ts<='2017-7-14 18:40:00.014' EVERY(5a);
......@@ -1577,8 +1577,6 @@ SQL示例:
支持 +、-、*、/ 运算,如 ceil(col1) + ceil(col2)。
只能与普通列,选择(Selection)、投影(Projection)函数一起使用,不能与聚合(Aggregation)函数一起使用。
该函数可以应用在普通表和超级表上。
支持版本:指定计算算法的功能从 2.2.0.x 版本开始,2.2.0.0 之前的版本不支持指定使用算法的功能。
- **FLOOR**
```mysql
......
......@@ -170,6 +170,16 @@ void tscAddIntoStreamList(SSqlStream *pStream) {
STscObj * pObj = pStream->pSql->pTscObj;
pthread_mutex_lock(&pObj->mutex);
//check if newly added stream node is present
//in the streamList to prevent loop in the list
SSqlStream *iter = pObj->streamList;
while (iter) {
if (pStream == iter) {
pthread_mutex_unlock(&pObj->mutex);
return;
}
iter = iter->next;
}
pStream->next = pObj->streamList;
if (pObj->streamList) pObj->streamList->prev = pStream;
......
......@@ -1392,7 +1392,7 @@ int32_t parseSlidingClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SStrToken* pSl
const char* msg1 = "sliding value no larger than the interval value";
const char* msg2 = "sliding value can not less than 1% of interval value";
const char* msg3 = "does not support sliding when interval is natural month/year";
const char* msg4 = "sliding not support for interp query";
const char* msg4 = "sliding not support for interp query";
const static int32_t INTERVAL_SLIDING_FACTOR = 100;
......@@ -1410,7 +1410,7 @@ int32_t parseSlidingClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SStrToken* pSl
if (interpQuery) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg4);
}
if (pInterval->intervalUnit == 'n' || pInterval->intervalUnit == 'y') {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
}
......@@ -2727,7 +2727,7 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col
memset(pExpr->base.aliasName, 0, tListLen(pExpr->base.aliasName));
getColumnName(pItem, pExpr->base.aliasName, pExpr->base.token,sizeof(pExpr->base.aliasName) - 1);
SColumnList list = createColumnList(1, index.tableIndex, index.columnIndex);
if (finalResult) {
int32_t numOfOutput = tscNumOfFields(pQueryInfo);
......@@ -2852,6 +2852,13 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col
char val[8] = {0};
int64_t tickPerSec = 0;
char *exprToken = tcalloc(pParamElem[1].pNode->exprToken.n + 1, sizeof(char));
memcpy(exprToken, pParamElem[1].pNode->exprToken.z, pParamElem[1].pNode->exprToken.n);
if (pParamElem[1].pNode->exprToken.type == TK_NOW || strstr(exprToken, "now")) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
}
tfree(exprToken);
if ((TSDB_DATA_TYPE_NULL == pParamElem[1].pNode->value.nType) || tVariantDump(&pParamElem[1].pNode->value, (char*) &tickPerSec, TSDB_DATA_TYPE_BIGINT, true) < 0) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
......@@ -2866,7 +2873,7 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg10);
} else if (tickPerSec <= 0) {
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg16);
}
}
tscExprAddParams(&pExpr->base, (char*) &tickPerSec, TSDB_DATA_TYPE_BIGINT, LONG_BYTES);
if (functionId == TSDB_FUNC_DERIVATIVE) {
......@@ -4906,14 +4913,14 @@ static int32_t validateNullExpr(tSqlExpr* pExpr, STableMeta* pTableMeta, int32_t
if (IS_VAR_DATA_TYPE(pSchema[index].type) || pSchema[index].type == TSDB_DATA_TYPE_JSON) {
return TSDB_CODE_SUCCESS;
}
char *v = strndup(pRight->exprToken.z, pRight->exprToken.n);
int32_t len = strRmquote(v, pRight->exprToken.n);
if (len > 0) {
uint32_t type = 0;
tGetToken(v, &type);
if (type == TK_NULL) {
if (type == TK_NULL) {
free(v);
return invalidOperationMsg(msgBuf, msg);
}
......@@ -5229,7 +5236,7 @@ static int32_t handleExprInQueryCond(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, tSql
}
}
if (pRight != NULL && (pRight->tokenId == TK_ID || pRight->tokenId == TK_ARROW)) { // join on tag columns for stable query
if (joinQuery && pRight != NULL && (pRight->tokenId == TK_ID || pRight->tokenId == TK_ARROW)) { // join on tag columns for stable query
if (!validateJoinExprNode(pCmd, pQueryInfo, *pExpr, &index)) {
return TSDB_CODE_TSC_INVALID_OPERATION;
}
......
......@@ -1479,6 +1479,18 @@ void handleDownstreamOperator(SSqlObj** pSqlObjList, int32_t numOfUpstream, SQue
break;
}
}
// set input data order to param[1]
if(pex->base.functionId == TSDB_FUNC_FIRST || pex->base.functionId == TSDB_FUNC_FIRST_DST ||
pex->base.functionId == TSDB_FUNC_LAST || pex->base.functionId == TSDB_FUNC_LAST_DST) {
// set input order
SQueryInfo* pInputQI = pSqlObjList[0]->cmd.pQueryInfo;
if(pInputQI) {
pex->base.numOfParams = 3;
pex->base.param[2].nType = TSDB_DATA_TYPE_INT;
pex->base.param[2].i64 = pInputQI->order.order;
}
}
}
tscDebug("0x%"PRIx64" create QInfo 0x%"PRIx64" to execute the main query while all nest queries are ready", pSql->self, pSql->self);
......@@ -4303,6 +4315,11 @@ void executeQuery(SSqlObj* pSql, SQueryInfo* pQueryInfo) {
// create sub query to handle the sub query.
SQueryInfo* pq = tscGetQueryInfo(&psub->cmd);
STableMetaInfo* pSubMeta = tscGetMetaInfo(pq, 0);
if (UTIL_TABLE_IS_SUPER_TABLE(pSubMeta) &&
pq->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT) {
psub->cmd.command = TSDB_SQL_RETRIEVE_EMPTY_RESULT;
}
executeQuery(psub, pq);
}
......
src/TDengineDriver/bin/
src/TDengineDriver/obj/
src/test/Cases/bin/
src/test/Cases/obj/
src/test/FunctionTest/bin/
src/test/FunctionTest/obj/
src/test/XUnitTest/bin/
src/test/XUnitTest/obj/
src/test/doc/
......
......@@ -11,7 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CB8E6458-3
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XUnitTest", "src\test\XUnitTest\XUnitTest.csproj", "{64C0A478-2591-4459-9F8F-A70F37976A41}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cases", "src\test\Cases\Cases.csproj", "{19A69D26-66BF-4227-97BE-9B087BC76B2F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionTest", "src\test\FunctionTest\FunctionTest.csproj", "{E66B034B-4677-4BFB-8B87-84715D281E21}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
......@@ -50,23 +50,23 @@ Global
{64C0A478-2591-4459-9F8F-A70F37976A41}.Release|x64.Build.0 = Release|Any CPU
{64C0A478-2591-4459-9F8F-A70F37976A41}.Release|x86.ActiveCfg = Release|Any CPU
{64C0A478-2591-4459-9F8F-A70F37976A41}.Release|x86.Build.0 = Release|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Debug|x64.ActiveCfg = Debug|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Debug|x64.Build.0 = Debug|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Debug|x86.ActiveCfg = Debug|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Debug|x86.Build.0 = Debug|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Release|Any CPU.Build.0 = Release|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Release|x64.ActiveCfg = Release|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Release|x64.Build.0 = Release|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Release|x86.ActiveCfg = Release|Any CPU
{19A69D26-66BF-4227-97BE-9B087BC76B2F}.Release|x86.Build.0 = Release|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Debug|x64.ActiveCfg = Debug|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Debug|x64.Build.0 = Debug|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Debug|x86.ActiveCfg = Debug|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Debug|x86.Build.0 = Debug|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Release|Any CPU.Build.0 = Release|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Release|x64.ActiveCfg = Release|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Release|x64.Build.0 = Release|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Release|x86.ActiveCfg = Release|Any CPU
{E66B034B-4677-4BFB-8B87-84715D281E21}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{5BED7402-0A65-4ED9-A491-C56BFB518045} = {A1FB5B66-E32F-4789-9BE9-042E5BD21087}
{CB8E6458-31E1-4351-B704-1B918E998654} = {A1FB5B66-E32F-4789-9BE9-042E5BD21087}
{64C0A478-2591-4459-9F8F-A70F37976A41} = {CB8E6458-31E1-4351-B704-1B918E998654}
{19A69D26-66BF-4227-97BE-9B087BC76B2F} = {CB8E6458-31E1-4351-B704-1B918E998654}
{E66B034B-4677-4BFB-8B87-84715D281E21} = {CB8E6458-31E1-4351-B704-1B918E998654}
EndGlobalSection
EndGlobal
......@@ -87,7 +87,7 @@ namespace TDengineDriver
case TDengineDataType.TSDB_DATA_TYPE_DOUBLE:
return "DOUBLE";
case TDengineDataType.TSDB_DATA_TYPE_BINARY:
return "STRING";
return "BINARY";
case TDengineDataType.TSDB_DATA_TYPE_TIMESTAMP:
return "TIMESTAMP";
case TDengineDataType.TSDB_DATA_TYPE_NCHAR:
......
......@@ -4,7 +4,7 @@
<TargetFrameworks>net5;netstandard2.0;net45</TargetFrameworks>
<PackageId>TDengine.Connector</PackageId>
<PackageIcon>logo.jpg</PackageIcon>
<Version>1.0.3</Version>
<Version>1.0.4</Version>
<Authors>taosdata</Authors>
<Company>www.taosdata.com</Company>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
......@@ -14,7 +14,7 @@
This C # connector supports: Linux 64/Windows x64/Windows x86.
more information please visit: https://www.taosdata.com
</Description>
<RepositoryUrl>https://github.com/taosdata/TDengine/tree/develop/src/connector/C%23</RepositoryUrl>
<RepositoryUrl>https://github.com/taosdata/TDengine/tree/develop/src/connector/C%2523/src/TDengineDriver</RepositoryUrl>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<ItemGroup>
......
......@@ -436,49 +436,46 @@ namespace TDengineDriver
{
TAOS_MULTI_BIND multiBind = new TAOS_MULTI_BIND();
int elementCount = arr.Length;
//TypeSize represent the Max element length of the comming arr
//The size of the buffer is typeSize * elementCount
//This buffer is used to store TAOS_MULTI_BIND.buffer
int typeSize = MaxElementLength(arr);
//This intSize is used to calcuate buffer size of the struct TAOS_MULTI_BIND's
//length. The buffer is intSize * elementCount,which is used to store TAOS_MULTI_BIND.length
int intSize = sizeof(int);
//This byteSize is used to calculate the buffer size of the struct TAOS_MULTI_BIND.is_null
//This buffer size is byteSize * elementCount
int byteSize = sizeof(byte);
StringBuilder arrStrBuilder = new StringBuilder(); ;
StringBuilder arrStrBuilder = new StringBuilder(); ;
//TAOS_MULTI_BIND.length
IntPtr lengthArr = Marshal.AllocHGlobal(intSize * elementCount);
//TAOS_MULTI_BIND.is_null
IntPtr nullArr = Marshal.AllocHGlobal(byteSize * elementCount);
//TAOS_MULTI_BIND.buffer
IntPtr uNcharBuff = Marshal.AllocHGlobal(typeSize * elementCount);
for (int i = 0; i < elementCount; i++)
{
int itemLength = 0;
byte[] decodeByte = GetStringEncodeByte(arr[i]);
itemLength = decodeByte.Length;
// if element if not null and element length is less then typeSize
// fill the memory with default char.Since arr element memory need align.
if (!String.IsNullOrEmpty(arr[i]) && typeSize == itemLength)
{
arrStrBuilder.Append(arr[i]);
}
else if (!String.IsNullOrEmpty(arr[i]) && typeSize > itemLength)
{
arrStrBuilder.Append(arr[i]);
arrStrBuilder.Append(AlignCharArr(typeSize - itemLength));
}
else
if (!String.IsNullOrEmpty(arr[i]))
{
// if is null value,fill the memory with default values.
arrStrBuilder.Append(AlignCharArr(typeSize));
for (int j = 0; j < itemLength; j++)
{
//Read byte after byte
Marshal.WriteByte(uNcharBuff, i * typeSize + j, decodeByte[j]);
}
}
//set TAOS_MULTI_BIND.length
Marshal.WriteInt32(lengthArr, intSize * i, typeSize);
//set TAOS_MULTI_BIND.is_null
//Set TAOS_MULTI_BIND.length
Marshal.WriteInt32(lengthArr, intSize * i, itemLength);
//Set TAOS_MULTI_BIND.is_null
Marshal.WriteByte(nullArr, byteSize * i, Convert.ToByte(String.IsNullOrEmpty(arr[i]) ? 1 : 0));
}
//set TAOS_MULTI_BIND.buffer
IntPtr uBinaryBuff = (IntPtr)Marshal.StringToHGlobalAnsi(arrStrBuilder.ToString());
//config TAOS_MULTI_BIND
//Config TAOS_MULTI_BIND
multiBind.buffer_type = (int)TDengineDataType.TSDB_DATA_TYPE_BINARY;
multiBind.buffer = uBinaryBuff;
multiBind.buffer = uNcharBuff;
multiBind.buffer_length = (ulong)typeSize;
multiBind.length = lengthArr;
multiBind.is_null = nullArr;
......@@ -491,47 +488,43 @@ namespace TDengineDriver
{
TAOS_MULTI_BIND multiBind = new TAOS_MULTI_BIND();
int elementCount = arr.Length;
//TypeSize represent the Max element length of the comming arr
//The size of the buffer is typeSize * elementCount
//This buffer is used to store TAOS_MULTI_BIND.buffer
int typeSize = MaxElementLength(arr);
//This intSize is used to calcuate buffer size of the struct TAOS_MULTI_BIND's
//length. The buffer is intSize * elementCount,which is used to store TAOS_MULTI_BIND.length
int intSize = sizeof(int);
//This byteSize is used to calculate the buffer size of the struct TAOS_MULTI_BIND.is_null
//This buffer size is byteSize * elementCount
int byteSize = sizeof(byte);
StringBuilder arrStrBuilder = new StringBuilder(); ;
//TAOS_MULTI_BIND.length
IntPtr lengthArr = Marshal.AllocHGlobal(intSize * elementCount);
//TAOS_MULTI_BIND.is_null
IntPtr nullArr = Marshal.AllocHGlobal(byteSize * elementCount);
//TAOS_MULTI_BIND.buffer
IntPtr uNcharBuff = Marshal.AllocHGlobal(typeSize * elementCount);
for (int i = 0; i < elementCount; i++)
{
int itemLength = 0;
byte[] decodeByte = GetStringEncodeByte(arr[i]);
itemLength = decodeByte.Length;
// if element if not null and element length is less then typeSize
// fill the memory with default char.Since arr element memory need align.
if (!String.IsNullOrEmpty(arr[i]) && typeSize == itemLength)
{
arrStrBuilder.Append(arr[i]);
}
else if (!String.IsNullOrEmpty(arr[i]) && typeSize > itemLength)
if (!String.IsNullOrEmpty(arr[i]))
{
arrStrBuilder.Append(arr[i]);
arrStrBuilder.Append(AlignCharArr(typeSize - itemLength));
for (int j = 0; j < itemLength; j++)
{
//Read byte after byte
Marshal.WriteByte(uNcharBuff, i * typeSize + j, decodeByte[j]);
}
}
else
{
// if is null value,fill the memory with default values.
arrStrBuilder.Append(AlignCharArr(typeSize));
}
//set TAOS_MULTI_BIND.length
Marshal.WriteInt32(lengthArr, intSize * i, typeSize);
//set TAOS_MULTI_BIND.is_null
//Set TAOS_MULTI_BIND.length
Marshal.WriteInt32(lengthArr, intSize * i, itemLength);
//Set TAOS_MULTI_BIND.is_null
Marshal.WriteByte(nullArr, byteSize * i, Convert.ToByte(String.IsNullOrEmpty(arr[i]) ? 1 : 0));
}
//set TAOS_MULTI_BIND.buffer
IntPtr uNcharBuff = (IntPtr)Marshal.StringToHGlobalAnsi(arrStrBuilder.ToString());
//config TAOS_MULTI_BIND
//Config TAOS_MULTI_BIND
multiBind.buffer_type = (int)TDengineDataType.TSDB_DATA_TYPE_NCHAR;
multiBind.buffer = uNcharBuff;
multiBind.buffer_length = (ulong)typeSize;
......@@ -612,16 +605,16 @@ namespace TDengineDriver
}
private static Byte[] GetStringEncodeByte(string str)
{
{
Byte[] strToBytes = null;
if(String.IsNullOrEmpty(str))
if (String.IsNullOrEmpty(str))
{
strToBytes = System.Text.Encoding.Default.GetBytes(String.Empty);
}
else
{
strToBytes = System.Text.Encoding.Default.GetBytes(str);
}
}
return strToBytes;
}
}
......
using System;
using Test.UtilsTools;
using System.Collections.Generic;
namespace Cases
{
public class FetchLengthCase
{
/// <author>xiaolei</author>
/// <Name>TestRetrieveBinary</Name>
/// <describe>TD-12103 C# connector fetch_row with binary data retrieving error</describe>
/// <filename>FetchLength.cs</filename>
/// <result>pass or failed </result>
public void TestRetrieveBinary(IntPtr conn)
{
string sql1 = "create stable stb1 (ts timestamp, name binary(10)) tags(n int);";
string sql2 = "insert into tb1 using stb1 tags(1) values(now, 'log');";
string sql3 = "insert into tb2 using stb1 tags(2) values(now, 'test');";
string sql4 = "insert into tb3 using stb1 tags(3) values(now, 'db02');";
string sql5 = "insert into tb4 using stb1 tags(4) values(now, 'db3');";
string sql6 = "select distinct(name) from stb1;";//
UtilsTools.ExecuteQuery(conn, sql1);
UtilsTools.ExecuteQuery(conn, sql2);
UtilsTools.ExecuteQuery(conn, sql3);
UtilsTools.ExecuteQuery(conn, sql4);
UtilsTools.ExecuteQuery(conn, sql5);
IntPtr resPtr = IntPtr.Zero;
resPtr = UtilsTools.ExecuteQuery(conn, sql6);
List<List<string>> result = UtilsTools.GetResultSet(resPtr);
List<string> colname = result[0];
List<string> data = result[1];
UtilsTools.AssertEqual("db3", data[0]);
UtilsTools.AssertEqual("log", data[1]);
UtilsTools.AssertEqual("db02", data[2]);
UtilsTools.AssertEqual("test", data[3]);
}
}
}
using System;
using Test.UtilsTools;
using Cases;
namespace Cases.EntryPoint
{
class Program
{
static void Main(string[] args)
{
IntPtr conn = IntPtr.Zero;
IntPtr stmt = IntPtr.Zero;
IntPtr res = IntPtr.Zero;
conn = UtilsTools.TDConnection("127.0.0.1", "root", "taosdata", "", 0);
UtilsTools.ExecuteUpdate(conn, "drop database if exists csharp");
UtilsTools.ExecuteUpdate(conn, "create database if not exists csharp keep 3650");
UtilsTools.ExecuteUpdate(conn, "use csharp");
Console.WriteLine("====================StableColumnByColumn===================");
StableColumnByColumn columnByColumn = new StableColumnByColumn();
columnByColumn.Test(conn, "stablecolumnbycolumn");
Console.WriteLine("====================StmtStableQuery===================");
StmtStableQuery stmtStableQuery = new StmtStableQuery();
stmtStableQuery.Test(conn, "stablecolumnbycolumn");
Console.WriteLine("====================StableMutipleLine===================");
StableMutipleLine mutipleLine = new StableMutipleLine();
mutipleLine.Test(conn, "stablemutipleline");
//================================================================================
Console.WriteLine("====================NtableSingleLine===================");
NtableSingleLine ntableSingleLine = new NtableSingleLine();
ntableSingleLine.Test(conn, "stablesingleline");
IntPtr resPtr = UtilsTools.ExecuteQuery(conn, "select * from stablesingleline ");
UtilsTools.DisplayRes(resPtr);
Console.WriteLine("====================NtableMutipleLine===================");
NtableMutipleLine ntableMutipleLine = new NtableMutipleLine();
ntableMutipleLine.Test(conn, "ntablemutipleline");
Console.WriteLine("====================StmtNtableQuery===================");
StmtNtableQuery stmtNtableQuery = new StmtNtableQuery();
stmtNtableQuery.Test(conn, "ntablemutipleline");
Console.WriteLine("====================NtableColumnByColumn===================");
NtableColumnByColumn ntableColumnByColumn = new NtableColumnByColumn();
ntableColumnByColumn.Test(conn, "ntablecolumnbycolumn");
Console.WriteLine("====================fetchfeilds===================");
FetchFields fetchFields = new FetchFields();
fetchFields.Test(conn, "fetchfeilds");
StableStmtCases stableStmtCases = new StableStmtCases();
Console.WriteLine("====================stableStmtCases.TestBindSingleLineCn===================");
stableStmtCases.TestBindSingleLineCn(conn, "stablestmtcasestestbindsinglelinecn");
Console.WriteLine("====================stableStmtCases.TestBindColumnCn===================");
stableStmtCases.TestBindColumnCn(conn, " stablestmtcasestestbindcolumncn");
Console.WriteLine("====================stableStmtCases.TestBindMultiLineCn===================");
stableStmtCases.TestBindMultiLineCn(conn, "stablestmtcasestestbindmultilinecn");
NormalTableStmtCases normalTableStmtCases = new NormalTableStmtCases();
Console.WriteLine("====================normalTableStmtCases.TestBindSingleLineCn===================");
normalTableStmtCases.TestBindSingleLineCn(conn, "normaltablestmtcasestestbindsinglelinecn");
Console.WriteLine("====================normalTableStmtCases.TestBindColumnCn===================");
normalTableStmtCases.TestBindColumnCn(conn, "normaltablestmtcasestestbindcolumncn");
Console.WriteLine("====================normalTableStmtCases.TestBindMultiLineCn===================");
normalTableStmtCases.TestBindMultiLineCn(conn, "normaltablestmtcasestestbindmultilinecn");
Console.WriteLine("===================JsonTagTest====================");
JsonTagTest jsonTagTest = new JsonTagTest();
jsonTagTest.Test(conn);
Console.WriteLine("====================fetchLengthCase===================");
FetchLengthCase fetchLengthCase = new FetchLengthCase();
fetchLengthCase.TestRetrieveBinary(conn);
UtilsTools.ExecuteQuery(conn, "drop database if exists csharp");
UtilsTools.CloseConnection(conn);
UtilsTools.ExitProgram();
}
}
}
using System;
using Test.UtilsTools;
using TDengineDriver;
using Test.UtilsTools.DataSource;
namespace Cases
{
public class StableMutipleLine
{
TAOS_BIND[] tags = DataSource.getTags();
TAOS_MULTI_BIND[] mbind = DataSource.GetMultiBindArr();
public void Test(IntPtr conn, string tableName)
{
String createTb = "create stable " + tableName + " (ts timestamp ,b bool,v1 tinyint,v2 smallint,v4 int,v8 bigint,f4 float,f8 double,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,bin binary(200),blob nchar(200))tags(bo bool,tt tinyint,si smallint,ii int,bi bigint,tu tinyint unsigned,su smallint unsigned,iu int unsigned,bu bigint unsigned,ff float ,dd double ,bb binary(200),nc nchar(200));";
String insertSql = "insert into ? using " + tableName + " tags(?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
UtilsTools.ExecuteUpdate(conn, createTb);
IntPtr stmt = StmtUtilTools.StmtInit(conn);
StmtUtilTools.StmtPrepare(stmt, insertSql);
StmtUtilTools.SetTableNameTags(stmt, tableName + "_t1", tags);
StmtUtilTools.BindParamBatch(stmt, mbind);
StmtUtilTools.AddBatch(stmt);
StmtUtilTools.StmtExecute(stmt);
StmtUtilTools.StmtClose(stmt);
DataSource.FreeTaosBind(tags);
DataSource.FreeTaosMBind(mbind);
}
}
public class StableColumnByColumn
{
DataSource data = new DataSource();
TAOS_BIND[] tags = DataSource.getTags();
TAOS_MULTI_BIND[] mbind = DataSource.GetMultiBindArr();
public void Test(IntPtr conn, string tableName)
{
String createTb = "create stable " + tableName + " (ts timestamp ,b bool,v1 tinyint,v2 smallint,v4 int,v8 bigint,f4 float,f8 double,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,bin binary(200),blob nchar(200))tags(bo bool,tt tinyint,si smallint,ii int,bi bigint,tu tinyint unsigned,su smallint unsigned,iu int unsigned,bu bigint unsigned,ff float ,dd double ,bb binary(200),nc nchar(200));";
String insertSql = "insert into ? using " + tableName + " tags(?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
UtilsTools.ExecuteUpdate(conn, createTb);
IntPtr stmt = StmtUtilTools.StmtInit(conn);
StmtUtilTools.StmtPrepare(stmt, insertSql);
StmtUtilTools.SetTableNameTags(stmt, tableName + "_t1", tags);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[0], 0);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[1], 1);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[2], 2);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[3], 3);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[4], 4);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[5], 5);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[6], 6);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[7], 7);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[8], 8);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[9], 9);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[10], 10);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[11], 11);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[12], 12);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[13], 13);
StmtUtilTools.AddBatch(stmt);
StmtUtilTools.StmtExecute(stmt);
StmtUtilTools.StmtClose(stmt);
DataSource.FreeTaosBind(tags);
DataSource.FreeTaosMBind(mbind);
}
}
public class StableStmtCases
{
/// <author>xiaolei</author>
/// <Name>StableStmtCases.TestBindSingleLineCn</Name>
/// <describe>Test stmt insert single line of chinese character into stable by column after column </describe>
/// <filename>StmtSTable.cs</filename>
/// <result>pass or failed </result>
public void TestBindSingleLineCn(IntPtr conn, string tableName)
{
TAOS_BIND[] tags = DataSource.getCNTags();
TAOS_BIND[] binds = DataSource.getNtableCNRow();
String createTb = "create stable " + tableName + " (ts timestamp,v1 tinyint,v2 smallint,v4 int,v8 bigint,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,f4 float,f8 double,bin binary(200),blob nchar(200),b bool,nilcol int)tags(bo bool,tt tinyint,si smallint,ii int,bi bigint,tu tinyint unsigned,su smallint unsigned,iu int unsigned,bu bigint unsigned,ff float ,dd double ,bb binary(200),nc nchar(200));";
String insertSql = "insert into ? using " + tableName + " tags(?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
UtilsTools.ExecuteUpdate(conn, createTb);
IntPtr stmt = StmtUtilTools.StmtInit(conn);
StmtUtilTools.StmtPrepare(stmt, insertSql);
StmtUtilTools.SetTableNameTags(stmt, tableName + "_t1", tags);
StmtUtilTools.BindParam(stmt, binds);
StmtUtilTools.AddBatch(stmt);
StmtUtilTools.StmtExecute(stmt);
StmtUtilTools.StmtClose(stmt);
DataSource.FreeTaosBind(tags);
DataSource.FreeTaosBind(binds);
string querySql = "select * from " + tableName;
IntPtr res = UtilsTools.ExecuteQuery(conn, querySql);
UtilsTools.DisplayRes(res);
}
/// <author>xiaolei</author>
/// <Name>StableStmtCases.TestBindColumnCn</Name>
/// <describe>Test stmt insert single line of chinese character into stable by column after column </describe>
/// <filename>StmtSTable.cs</filename>
/// <result>pass or failed </result>
public void TestBindColumnCn(IntPtr conn, string tableName)
{
DataSource data = new DataSource();
TAOS_BIND[] tags = DataSource.getCNTags();
TAOS_MULTI_BIND[] mbind = DataSource.GetMultiBindCNArr();
String createTb = "create stable " + tableName + " (ts timestamp ,b bool,v1 tinyint,v2 smallint,v4 int,v8 bigint,f4 float,f8 double,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,bin binary(200),blob nchar(200))tags(bo bool,tt tinyint,si smallint,ii int,bi bigint,tu tinyint unsigned,su smallint unsigned,iu int unsigned,bu bigint unsigned,ff float ,dd double ,bb binary(200),nc nchar(200));";
String insertSql = "insert into ? using " + tableName + " tags(?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
UtilsTools.ExecuteUpdate(conn, createTb);
IntPtr stmt = StmtUtilTools.StmtInit(conn);
StmtUtilTools.StmtPrepare(stmt, insertSql);
StmtUtilTools.SetTableNameTags(stmt, tableName + "_t1", tags);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[0], 0);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[1], 1);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[2], 2);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[3], 3);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[4], 4);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[5], 5);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[6], 6);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[7], 7);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[8], 8);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[9], 9);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[10], 10);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[11], 11);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[12], 12);
StmtUtilTools.BindSingleParamBatch(stmt, mbind[13], 13);
StmtUtilTools.AddBatch(stmt);
StmtUtilTools.StmtExecute(stmt);
StmtUtilTools.StmtClose(stmt);
DataSource.FreeTaosBind(tags);
DataSource.FreeTaosMBind(mbind);
string querySql = "select * from " + tableName;
IntPtr res = UtilsTools.ExecuteQuery(conn, querySql);
UtilsTools.DisplayRes(res);
}
/// <author>xiaolei</author>
/// <Name>StableStmtCases.TestBindMultiLineCn</Name>
/// <describe>Test stmt insert single line of chinese character into stable by column after column </describe>
/// <filename>StmtSTable.cs</filename>
/// <result>pass or failed </result>
public void TestBindMultiLineCn(IntPtr conn, string tableName)
{
TAOS_BIND[] tags = DataSource.getCNTags();
TAOS_MULTI_BIND[] mbind = DataSource.GetMultiBindCNArr();
String createTb = "create stable " + tableName + " (ts timestamp ,b bool,v1 tinyint,v2 smallint,v4 int,v8 bigint,f4 float,f8 double,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,bin binary(200),blob nchar(200))tags(bo bool,tt tinyint,si smallint,ii int,bi bigint,tu tinyint unsigned,su smallint unsigned,iu int unsigned,bu bigint unsigned,ff float ,dd double ,bb binary(200),nc nchar(200));";
String insertSql = "insert into ? using " + tableName + " tags(?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
UtilsTools.ExecuteUpdate(conn, createTb);
IntPtr stmt = StmtUtilTools.StmtInit(conn);
StmtUtilTools.StmtPrepare(stmt, insertSql);
StmtUtilTools.SetTableNameTags(stmt, tableName + "_t1", tags);
StmtUtilTools.BindParamBatch(stmt, mbind);
StmtUtilTools.AddBatch(stmt);
StmtUtilTools.StmtExecute(stmt);
StmtUtilTools.StmtClose(stmt);
DataSource.FreeTaosBind(tags);
DataSource.FreeTaosMBind(mbind);
string querySql = "select * from " + tableName;
IntPtr res = UtilsTools.ExecuteQuery(conn, querySql);
UtilsTools.DisplayRes(res);
}
}
}
\ No newline at end of file
using System;
using Test.UtilsTools;
using TDengineDriver;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Cases
{
public class FetchFields
{
public void Test(IntPtr conn, string tableName)
{
IntPtr res = IntPtr.Zero;
String createTb = "create stable " + tableName + " (ts timestamp ,b bool,v1 tinyint,v2 smallint,v4 int,v8 bigint,f4 float,f8 double,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,bin binary(200),blob nchar(200))tags(jsontag json);";
String insertSql = "insert into " + tableName + "_t1 using " + tableName + " tags('{\"k1\": \"v1\"}') values(1637064040000,true,1,2,3,4,5,6,7,8,9,10,'XI','XII')";
String selectSql = "select * from " + tableName;
String dropSql = "drop table " + tableName;
UtilsTools.ExecuteQuery(conn, createTb);
UtilsTools.ExecuteQuery(conn, insertSql);
res = UtilsTools.ExecuteQuery(conn, selectSql);
UtilsTools.ExecuteQuery(conn, dropSql);
List<TDengineMeta> metas = new List<TDengineMeta>();
metas = TDengine.FetchFields(res);
if (metas.Capacity == 0)
{
Console.WriteLine("empty result");
}
else
{
foreach(TDengineMeta meta in metas){
Console.WriteLine("col_name:{0},col_type_code:{1},col_type:{2}({3})",meta.name,meta.type,meta.TypeName(),meta.size);
}
}
}
}
}
using System;
using Test.UtilsTools;
using TDengineDriver;
using System.Collections.Generic;
namespace Test.UtilsTools.DataSource
{
public class DataSource
......@@ -23,7 +23,10 @@ namespace Test.UtilsTools.DataSource
public static string[] binaryArrCn = new string[5] { "涛思数据", String.Empty, null, "taosdata涛思数据", "涛思数据TDengine" };
public static string[] NcharArrCn = new string[5] { "涛思数据", null, "taosdata涛思数据", "涛思数据TDengine", String.Empty };
public static TAOS_BIND[] getTags()
// Construct a TAOS_BIND array which contains normal character.
// For stmt bind tags,this will be used as tag info
public static TAOS_BIND[] GetTags()
{
TAOS_BIND[] binds = new TAOS_BIND[13];
binds[0] = TaosBind.BindBool(true);
......@@ -41,8 +44,59 @@ namespace Test.UtilsTools.DataSource
binds[12] = TaosBind.BindNchar("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKZXCVBNM`1234567890-=+_)(*&^%$#@!~[];,./<>?:{}");
return binds;
}
// Get the tag data within and string list
// Which will be retrieved as a string List
private static List<String> GetTagData()
{
List<String> tagData = new List<String>();
tagData.Add(true.ToString());
tagData.Add((-2).ToString());
tagData.Add((short.MaxValue).ToString());
tagData.Add((int.MaxValue).ToString());
tagData.Add((Int64.MaxValue).ToString());
tagData.Add((byte.MaxValue - 1).ToString());
tagData.Add((UInt16.MaxValue - 1).ToString());
tagData.Add((uint.MinValue + 1).ToString());
tagData.Add((UInt64.MinValue + 1).ToString());
tagData.Add((11.11F).ToString());
tagData.Add((22.22D).ToString());
tagData.Add("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKZXCVBNM`1234567890-=+_)(*&^%$#@!~[];,./<>?:{}");
tagData.Add("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKZXCVBNM`1234567890-=+_)(*&^%$#@!~[];,./<>?:{}");
return tagData;
}
public static TAOS_BIND[] getCNTags()
public static List<string> GetMultiBindStableRowData()
{
List<string> rowData = new List<String>();
List<string> tagData = GetTagData();
for (int i = 0; i < tsArr.Length; i++)
{
rowData.Add(tsArr[i].ToString());
rowData.Add(boolArr[i].Equals(null) ? "NULL" : boolArr[i].ToString());
rowData.Add(tinyIntArr[i].Equals(null) ? "NULL" : tinyIntArr[i].ToString());
rowData.Add(shortArr[i].Equals(null) ? "NULL" : shortArr[i].ToString());
rowData.Add(intArr[i].Equals(null) ? "NULL" : intArr[i].ToString());
rowData.Add(longArr[i].Equals(null) ? "NULL" : longArr[i].ToString());
rowData.Add(floatArr[i].Equals(null) ? "NULL" : floatArr[i].ToString());
rowData.Add(doubleArr[i].Equals(null) ? "NULL" : doubleArr[i].ToString());
rowData.Add(uTinyIntArr[i].Equals(null) ? "NULL" : uTinyIntArr[i].ToString());
rowData.Add(uShortArr[i].Equals(null) ? "NULL" : uShortArr[i].ToString());
rowData.Add(uIntArr[i].Equals(null) ? "NULL" : uIntArr[i].ToString());
rowData.Add(uLongArr[i].Equals(null) ? "NULL" : uLongArr[i].ToString());
rowData.Add(String.IsNullOrEmpty(binaryArr[i]) ? "NULL" : binaryArr[i]);
rowData.Add(String.IsNullOrEmpty(ncharArr[i]) ? "NULL" : ncharArr[i]);
rowData.AddRange(tagData);
// Console.WriteLine("binaryArrCn[{0}]:{1},ncharArr[{0}]:{2}",i,String.IsNullOrEmpty(binaryArrCn[i]) ? "NULL" : binaryArrCn[i],String.IsNullOrEmpty(ncharArr[i]) ? "NULL" : NcharArrCn[i]);
// Console.WriteLine("binaryArrCn[{0}]:{1},ncharArr[{0}]:{2}",i,String.IsNullOrEmpty(binaryArrCn[i]) ? 0 :binaryArrCn[i].Length, String.IsNullOrEmpty(ncharArr[i]) ? 0 : NcharArrCn[i].Length);
// Console.WriteLine("========");
}
return rowData;
}
// Construct a TAOS_BIND array which contains chinese character.
// For stmt bind tags,this will be used as tag info
public static TAOS_BIND[] GetCNTags()
{
TAOS_BIND[] binds = new TAOS_BIND[13];
binds[0] = TaosBind.BindBool(true);
......@@ -57,11 +111,32 @@ namespace Test.UtilsTools.DataSource
binds[9] = TaosBind.BindFloat(11.11F);
binds[10] = TaosBind.BindDouble(22.22D);
binds[11] = TaosBind.BindBinary("TDengine涛思数据");
binds[12] = TaosBind.BindNchar("涛思");
binds[12] = TaosBind.BindNchar("涛思数据taos");
return binds;
}
public static TAOS_BIND[] getNtableCNRow()
// Get the tag data within and string list
// Which will be retrieved as a string List
private static List<String> GetTagCnData()
{
List<String> tagData = new List<String>();
tagData.Add(true.ToString());
tagData.Add((-2).ToString());
tagData.Add((short.MaxValue - 1).ToString());
tagData.Add((int.MaxValue - 1).ToString());
tagData.Add((Int64.MaxValue - 1).ToString());
tagData.Add((byte.MaxValue - 1).ToString());
tagData.Add((UInt16.MaxValue - 1).ToString());
tagData.Add((uint.MinValue + 1).ToString());
tagData.Add((UInt64.MinValue + 1).ToString());
tagData.Add((11.11F).ToString());
tagData.Add((22.22D).ToString());
tagData.Add("TDengine涛思数据");
tagData.Add("涛思数据taos");
return tagData;
}
// A line of data that's without CN character.
// Which is construct as an TAOS_BIND array
public static TAOS_BIND[] GetNtableCNRow()
{
TAOS_BIND[] binds = new TAOS_BIND[15];
binds[0] = TaosBind.BindTimestamp(1637064040000);
......@@ -81,8 +156,40 @@ namespace Test.UtilsTools.DataSource
binds[14] = TaosBind.BindNil();
return binds;
}
//Get and list data that will be insert into table
public static List<String> GetNtableCNRowData()
{
var data = new List<string>{
"1637064040000",
"-2",
short.MaxValue.ToString(),
int.MaxValue.ToString(),
Int64.MaxValue.ToString(),
(byte.MaxValue - 1).ToString(),
(UInt16.MaxValue - 1).ToString(),
(uint.MinValue + 1).ToString(),
(UInt64.MinValue + 1).ToString(),
(11.11F).ToString(),
(22.22D).ToString(),
"TDengine数据",
"taosdata涛思数据",
"True",
"NULL"
};
return data;
}
// Get the data value and tag values which have chinese characters
// And retrieved as a string list.This is single Line.
public static List<String> GetStableCNRowData()
{
List<String> columnData = GetNtableCNRowData();
List<String> tagData = GetTagCnData();
columnData.AddRange(tagData);
return columnData;
}
public static TAOS_BIND[] getNtableRow()
// A line of data that's without CN character
public static TAOS_BIND[] GetNtableRow()
{
TAOS_BIND[] binds = new TAOS_BIND[15];
binds[0] = TaosBind.BindTimestamp(1637064040000);
......@@ -102,6 +209,31 @@ namespace Test.UtilsTools.DataSource
binds[14] = TaosBind.BindNil();
return binds;
}
// A List of data ,use as expectResData. The value is equal to getNtableRow()
public static List<String> GetNtableRowData()
{
var data = new List<string>{
"1637064040000",
"-2",
short.MaxValue.ToString(),
int.MaxValue.ToString(),
(Int64.MaxValue).ToString(),
(byte.MaxValue - 1).ToString(),
(UInt16.MaxValue - 1).ToString(),
(uint.MinValue + 1).ToString(),
(UInt64.MinValue + 1).ToString(),
(11.11F).ToString(),
(22.22D).ToString(),
"qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKZXCVBNM`1234567890-=+_)(*&^%$#@!~[];,./<>?:{}",
"qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKZXCVBNM`1234567890-=+_)(*&^%$#@!~[];,./<>?:{}",
true.ToString(),
"NULL"
};
return data;
}
// Five lines of data, that is construct as taos_mutli_bind array.
// There aren't any CN character
public static TAOS_MULTI_BIND[] GetMultiBindArr()
{
TAOS_MULTI_BIND[] mBinds = new TAOS_MULTI_BIND[14];
......@@ -121,6 +253,35 @@ namespace Test.UtilsTools.DataSource
mBinds[13] = TaosMultiBind.MultiBindNchar(ncharArr);
return mBinds;
}
// A List of data ,use as expectResData. The value is equal to GetMultiBindCNArr()
public static List<string> GetMultiBindResData()
{
var rowData = new List<string>();
for (int i = 0; i < tsArr.Length; i++)
{
rowData.Add(tsArr[i].ToString());
rowData.Add(boolArr[i].Equals(null) ? "NULL" : boolArr[i].ToString());
rowData.Add(tinyIntArr[i].Equals(null) ? "NULL" : tinyIntArr[i].ToString());
rowData.Add(shortArr[i].Equals(null) ? "NULL" : shortArr[i].ToString());
rowData.Add(intArr[i].Equals(null) ? "NULL" : intArr[i].ToString());
rowData.Add(longArr[i].Equals(null) ? "NULL" : longArr[i].ToString());
rowData.Add(floatArr[i].Equals(null) ? "NULL" : floatArr[i].ToString());
rowData.Add(doubleArr[i].Equals(null) ? "NULL" : doubleArr[i].ToString());
rowData.Add(uTinyIntArr[i].Equals(null) ? "NULL" : uTinyIntArr[i].ToString());
rowData.Add(uShortArr[i].Equals(null) ? "NULL" : uShortArr[i].ToString());
rowData.Add(uIntArr[i].Equals(null) ? "NULL" : uIntArr[i].ToString());
rowData.Add(uLongArr[i].Equals(null) ? "NULL" : uLongArr[i].ToString());
rowData.Add(String.IsNullOrEmpty(binaryArr[i]) ? "NULL" : binaryArr[i]);
rowData.Add(String.IsNullOrEmpty(ncharArr[i]) ? "NULL" : ncharArr[i]);
// Console.WriteLine("binaryArrCn[{0}]:{1},NcharArrCn[{0}]:{2}",i,String.IsNullOrEmpty(binaryArrCn[i]) ? "NULL" : binaryArrCn[i],String.IsNullOrEmpty(NcharArrCn[i]) ? "NULL" : NcharArrCn[i]);
// Console.WriteLine("binaryArrCn[{0}]:{1},NcharArrCn[{0}]:{2}",i,String.IsNullOrEmpty(binaryArrCn[i]) ? 0 :binaryArrCn[i].Length, String.IsNullOrEmpty(NcharArrCn[i]) ? 0 : NcharArrCn[i].Length);
// Console.WriteLine("========");
}
return rowData;
}
// Five lines of data, that is construct as taos_mutli_bind array.
// There aren some CN characters and letters.
public static TAOS_MULTI_BIND[] GetMultiBindCNArr()
{
TAOS_MULTI_BIND[] mBinds = new TAOS_MULTI_BIND[14];
......@@ -140,6 +301,62 @@ namespace Test.UtilsTools.DataSource
mBinds[13] = TaosMultiBind.MultiBindNchar(NcharArrCn);
return mBinds;
}
// A List of data ,use as expectResData. The value is equal to GetMultiBindCNArr()
public static List<string> GetMultiBindCNRowData()
{
var rowData = new List<string>();
for (int i = 0; i < tsArr.Length; i++)
{
rowData.Add(tsArr[i].ToString());
rowData.Add(boolArr[i].Equals(null) ? "NULL" : boolArr[i].ToString());
rowData.Add(tinyIntArr[i].Equals(null) ? "NULL" : tinyIntArr[i].ToString());
rowData.Add(shortArr[i].Equals(null) ? "NULL" : shortArr[i].ToString());
rowData.Add(intArr[i].Equals(null) ? "NULL" : intArr[i].ToString());
rowData.Add(longArr[i].Equals(null) ? "NULL" : longArr[i].ToString());
rowData.Add(floatArr[i].Equals(null) ? "NULL" : floatArr[i].ToString());
rowData.Add(doubleArr[i].Equals(null) ? "NULL" : doubleArr[i].ToString());
rowData.Add(uTinyIntArr[i].Equals(null) ? "NULL" : uTinyIntArr[i].ToString());
rowData.Add(uShortArr[i].Equals(null) ? "NULL" : uShortArr[i].ToString());
rowData.Add(uIntArr[i].Equals(null) ? "NULL" : uIntArr[i].ToString());
rowData.Add(uLongArr[i].Equals(null) ? "NULL" : uLongArr[i].ToString());
rowData.Add(String.IsNullOrEmpty(binaryArrCn[i]) ? "NULL" : binaryArrCn[i]);
rowData.Add(String.IsNullOrEmpty(NcharArrCn[i]) ? "NULL" : NcharArrCn[i]);
// Console.WriteLine("binaryArrCn[{0}]:{1},NcharArrCn[{0}]:{2}",i,String.IsNullOrEmpty(binaryArrCn[i]) ? "NULL" : binaryArrCn[i],String.IsNullOrEmpty(NcharArrCn[i]) ? "NULL" : NcharArrCn[i]);
// Console.WriteLine("binaryArrCn[{0}]:{1},NcharArrCn[{0}]:{2}",i,String.IsNullOrEmpty(binaryArrCn[i]) ? 0 :binaryArrCn[i].Length, String.IsNullOrEmpty(NcharArrCn[i]) ? 0 : NcharArrCn[i].Length);
// Console.WriteLine("========");
}
return rowData;
}
public static List<String> GetMultiBindStableCNRowData()
{
List<String> columnData = new List<string>();
List<String> tagData = GetTagCnData();
for (int i = 0; i < tsArr.Length; i++)
{
columnData.Add(tsArr[i].ToString());
columnData.Add(boolArr[i].Equals(null) ? "NULL" : boolArr[i].ToString());
columnData.Add(tinyIntArr[i].Equals(null) ? "NULL" : tinyIntArr[i].ToString());
columnData.Add(shortArr[i].Equals(null) ? "NULL" : shortArr[i].ToString());
columnData.Add(intArr[i].Equals(null) ? "NULL" : intArr[i].ToString());
columnData.Add(longArr[i].Equals(null) ? "NULL" : longArr[i].ToString());
columnData.Add(floatArr[i].Equals(null) ? "NULL" : floatArr[i].ToString());
columnData.Add(doubleArr[i].Equals(null) ? "NULL" : doubleArr[i].ToString());
columnData.Add(uTinyIntArr[i].Equals(null) ? "NULL" : uTinyIntArr[i].ToString());
columnData.Add(uShortArr[i].Equals(null) ? "NULL" : uShortArr[i].ToString());
columnData.Add(uIntArr[i].Equals(null) ? "NULL" : uIntArr[i].ToString());
columnData.Add(uLongArr[i].Equals(null) ? "NULL" : uLongArr[i].ToString());
columnData.Add(String.IsNullOrEmpty(binaryArrCn[i]) ? "NULL" : binaryArrCn[i]);
columnData.Add(String.IsNullOrEmpty(NcharArrCn[i]) ? "NULL" : NcharArrCn[i]);
columnData.AddRange(tagData);
// Console.WriteLine("binaryArrCn[{0}]:{1},NcharArrCn[{0}]:{2}",i,String.IsNullOrEmpty(binaryArrCn[i]) ? "NULL" : binaryArrCn[i],String.IsNullOrEmpty(NcharArrCn[i]) ? "NULL" : NcharArrCn[i]);
// Console.WriteLine("binaryArrCn[{0}]:{1},NcharArrCn[{0}]:{2}",i,String.IsNullOrEmpty(binaryArrCn[i]) ? 0 :binaryArrCn[i].Length, String.IsNullOrEmpty(NcharArrCn[i]) ? 0 : NcharArrCn[i].Length);
// Console.WriteLine("========");
}
return columnData;
}
public static TAOS_BIND[] GetQueryCondition()
{
......@@ -158,7 +375,47 @@ namespace Test.UtilsTools.DataSource
{
TaosMultiBind.FreeTaosBind(mbinds);
}
//Get the TDengineMeta list from the ddl either normal table or stable
public static List<TDengineMeta> GetMetaFromDLL(string dllStr)
{
var expectResMeta = new List<TDengineMeta>();
//"CREATE TABLE meters(ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS(location BINARY(30), groupId INT);";
int bracetInd = dllStr.IndexOf("(");
//(ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS(location BINARY(30), groupId INT);
string subDllStr = dllStr.Substring(bracetInd);
String[] stableSeparators = new String[] { "tags", "TAGS" };
//(ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT)
//(location BINARY(30), groupId INT)
String[] dllStrElements = subDllStr.Split(stableSeparators, StringSplitOptions.RemoveEmptyEntries);
//(ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT)
dllStrElements[0] = dllStrElements[0].Substring(1, dllStrElements[0].Length - 2);
String[] finalStr1 = dllStrElements[0].Split(',', StringSplitOptions.RemoveEmptyEntries);
foreach (string item in finalStr1)
{
//ts TIMESTAMP
string[] itemArr = item.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
// Console.WriteLine("GetMetaFromDLL():{0},{1}",itemArr[0],itemArr[1]);
expectResMeta.Add(UtilsTools.ConstructTDengineMeta(itemArr[0], itemArr[1]));
}
if (dllStr.Contains("TAGS") || dllStr.Contains("tags"))
{
//location BINARY(30), groupId INT
dllStrElements[1] = dllStrElements[1].Substring(1, dllStrElements[1].Length - 2);
//location BINARY(30) groupId INT
String[] finalStr2 = dllStrElements[1].Split(',', StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine("========");
foreach (string item in finalStr2)
{
//location BINARY(30)
string[] itemArr = item.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
// Console.WriteLine("GetMetaFromDLL():{0},{1}",itemArr[0],itemArr[1]);
expectResMeta.Add(UtilsTools.ConstructTDengineMeta(itemArr[0], itemArr[1]));
}
}
return expectResMeta;
}
}
}
\ No newline at end of file
using System;
using Test.UtilsTools;
using System.Collections.Generic;
using Xunit;
using TDengineDriver;
using Test.UtilsTools.ResultSet;
namespace Cases
{
public class FetchLengthCase
{
/// <author>xiaolei</author>
/// <Name>TestRetrieveBinary</Name>
/// <describe>TD-12103 C# connector fetch_row with binary data retrieving error</describe>
/// <filename>FetchLength.cs</filename>
/// <result>pass or failed </result>
[Fact(DisplayName = "Skip FetchLengthCase.TestRetrieveBinary()")]
public void TestRetrieveBinary()
{
IntPtr conn = UtilsTools.TDConnection();
var expectData = new List<string> { "log", "test", "db02", "db3" };
var expectMeta = new List<TDengineMeta>{
UtilsTools.ConstructTDengineMeta("ts","timestamp"),
UtilsTools.ConstructTDengineMeta("name","binary(10)"),
UtilsTools.ConstructTDengineMeta("n","int")
};
string sql0 = "drop table if exists stb1;";
string sql1 = "create stable if not exists stb1 (ts timestamp, name binary(10)) tags(n int);";
string sql2 = $"insert into tb1 using stb1 tags(1) values(now, '{expectData[0]}');";
string sql3 = $"insert into tb2 using stb1 tags(2) values(now, '{expectData[1]}');";
string sql4 = $"insert into tb3 using stb1 tags(3) values(now, '{expectData[2]}');";
string sql5 = $"insert into tb4 using stb1 tags(4) values(now, '{expectData[3]}');";
string sql6 = "select distinct(name) from stb1;";
UtilsTools.ExecuteQuery(conn, sql0);
UtilsTools.ExecuteQuery(conn, sql1);
UtilsTools.ExecuteQuery(conn, sql2);
UtilsTools.ExecuteQuery(conn, sql3);
UtilsTools.ExecuteQuery(conn, sql4);
UtilsTools.ExecuteQuery(conn, sql5);
IntPtr resPtr = IntPtr.Zero;
resPtr = UtilsTools.ExecuteQuery(conn, sql6);
ResultSet actualResult = new ResultSet(resPtr);
List<string> actualData = actualResult.GetResultData();
List<TDengineMeta> actualMeta = actualResult.GetResultMeta();
expectData.Reverse();
Assert.Equal(expectData[0], actualData[0]);
Assert.Equal(expectMeta[1].name, actualMeta[0].name);
Assert.Equal(expectMeta[1].size, actualMeta[0].size);
Assert.Equal(expectMeta[1].type, actualMeta[0].type);
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<NoWarn>CS1591;CS0168</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>..\doc\FunctionTest.XML</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\TDengineDriver\TDengineDriver.csproj" />
</ItemGroup>
</Project>
using System;
using TDengineDriver;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
namespace Test.UtilsTools.ResultSet
{
public class ResultSet
{
private List<TDengineMeta> resultMeta;
private List<String> resultData;
// private bool isValidResult = false;
public ResultSet(IntPtr res)
{
resultMeta = UtilsTools.GetResField(res);
resultData = UtilsTools.GetResData(res);
}
public ResultSet(List<TDengineMeta> metas, List<String> datas)
{
resultMeta = metas;
resultData = datas;
}
public List<String> GetResultData()
{
return resultData;
}
public List<TDengineMeta> GetResultMeta()
{
return resultMeta;
}
}
}
\ No newline at end of file
此差异已折叠。
using System;
using Test.UtilsTools;
using TDengineDriver;
using System.Collections.Generic;
using Xunit;
using Test.UtilsTools.ResultSet;
namespace Cases
{
public class FetchFieldCases
{
/// <author>xiaolei</author>
/// <Name>FetchFieldCases.TestFetchFieldJsonTag</Name>
/// <describe>test taos_fetch_fields(), check the meta data</describe>
/// <filename>TaosFeild.cs</filename>
/// <result>pass or failed </result>
[Fact(DisplayName = "FetchFieldCases.TestFetchFieldJsonTag()")]
public void TestFetchFieldJsonTag()
{
IntPtr conn = UtilsTools.TDConnection();
IntPtr _res = IntPtr.Zero;
string tableName = "fetchfeilds";
var expectResMeta = new List<TDengineMeta> {
UtilsTools.ConstructTDengineMeta("ts", "timestamp"),
UtilsTools.ConstructTDengineMeta("b", "bool"),
UtilsTools.ConstructTDengineMeta("v1", "tinyint"),
UtilsTools.ConstructTDengineMeta("v2", "smallint"),
UtilsTools.ConstructTDengineMeta("v4", "int"),
UtilsTools.ConstructTDengineMeta("v8", "bigint"),
UtilsTools.ConstructTDengineMeta("f4", "float"),
UtilsTools.ConstructTDengineMeta("f8", "double"),
UtilsTools.ConstructTDengineMeta("u1", "tinyint unsigned"),
UtilsTools.ConstructTDengineMeta("u2", "smallint unsigned"),
UtilsTools.ConstructTDengineMeta("u4", "int unsigned"),
UtilsTools.ConstructTDengineMeta("u8", "bigint unsigned"),
UtilsTools.ConstructTDengineMeta("bin", "binary(200)"),
UtilsTools.ConstructTDengineMeta("blob", "nchar(200)"),
UtilsTools.ConstructTDengineMeta("jsontag", "json"),
};
var expectResData = new List<String> { "1637064040000", "true", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "XI", "XII", "{\"k1\": \"v1\"}" };
String dropTb = "drop table if exists " + tableName;
String createTb = "create stable " + tableName
+ " (ts timestamp" +
",b bool" +
",v1 tinyint" +
",v2 smallint" +
",v4 int" +
",v8 bigint" +
",f4 float" +
",f8 double" +
",u1 tinyint unsigned" +
",u2 smallint unsigned" +
",u4 int unsigned" +
",u8 bigint unsigned" +
",bin binary(200)" +
",blob nchar(200)" +
")" +
"tags" +
"(jsontag json);";
String insertSql = "insert into " + tableName + "_t1 using " + tableName +
" tags('{\"k1\": \"v1\"}') " +
"values(1637064040000,true,1,2,3,4,5,6,7,8,9,10,'XI','XII')";
String selectSql = "select * from " + tableName;
String dropSql = "drop table " + tableName;
UtilsTools.ExecuteUpdate(conn, dropTb);
UtilsTools.ExecuteUpdate(conn, createTb);
UtilsTools.ExecuteUpdate(conn, insertSql);
_res = UtilsTools.ExecuteQuery(conn, selectSql);
ResultSet actualResult = new ResultSet(_res);
List<TDengineMeta> actualMeta = actualResult.GetResultMeta();
for (int i = 0; i < actualMeta.Count; i++)
{
Assert.Equal(expectResMeta[i].name, actualMeta[i].name);
Assert.Equal(expectResMeta[i].type, actualMeta[i].type);
Assert.Equal(expectResMeta[i].size, actualMeta[i].size);
}
}
}
}
using System;
using TDengineDriver;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
namespace Test.UtilsTools
{
public class UtilsTools
{
static string ip = "127.0.0.1";
static string user = "root";
static string password = "taosdata";
static string db = "";
static short port = 0;
public static IntPtr TDConnection()
{
TDengine.Options((int)TDengineInitOption.TDDB_OPTION_CONFIGDIR, GetConfigPath());
TDengine.Options((int)TDengineInitOption.TDDB_OPTION_SHELL_ACTIVITY_TIMER, "60");
TDengine.Init();
IntPtr conn = TDengine.Connect(ip, user, password, db, port);
// UtilsTools.ExecuteUpdate(conn, "drop database if exists csharp");
UtilsTools.ExecuteUpdate(conn, "create database if not exists csharp keep 3650");
UtilsTools.ExecuteUpdate(conn, "use csharp");
return conn;
}
public static string GetConfigPath()
{
string configDir = "" ;
if(OperatingSystem.IsOSPlatform("Windows"))
{
configDir = "C:/TDengine/cfg";
}
else if(OperatingSystem.IsOSPlatform("Linux"))
{
configDir = "/etc/taos";
}
else if(OperatingSystem.IsOSPlatform("macOS"))
{
configDir = "/etc/taos";
}
return configDir;
}
public static IntPtr ExecuteQuery(IntPtr conn, String sql)
{
IntPtr res = TDengine.Query(conn, sql);
if (!IsValidResult(res))
{
Console.Write(sql.ToString() + " failure, ");
ExitProgram();
}
else
{
Console.WriteLine(sql.ToString() + " success");
}
return res;
}
public static IntPtr ExecuteErrorQuery(IntPtr conn, String sql)
{
IntPtr res = TDengine.Query(conn, sql);
if (!IsValidResult(res))
{
Console.Write(sql.ToString() + " failure, ");
ExitProgram();
}
else
{
Console.WriteLine(sql.ToString() + " success");
}
return res;
}
public static void ExecuteUpdate(IntPtr conn, String sql)
{
IntPtr res = TDengine.Query(conn, sql);
if (!IsValidResult(res))
{
Console.Write(sql.ToString() + " failure, ");
ExitProgram();
}
else
{
Console.WriteLine(sql.ToString() + " success");
}
TDengine.FreeResult(res);
}
public static void DisplayRes(IntPtr res)
{
if (!IsValidResult(res))
{
ExitProgram();
}
List<TDengineMeta> metas = GetResField(res);
int fieldCount = metas.Count;
IntPtr rowdata;
// StringBuilder builder = new StringBuilder();
List<string> datas = QueryRes(res, metas);
Console.Write(" DisplayRes ---");
for (int i = 0; i < metas.Count; i++)
{
for (int j = 0; j < datas.Count; j++)
{
Console.Write(" {0} ---", datas[i * j + i]);
}
Console.WriteLine("");
}
// if (TDengine.ErrorNo(res) != 0)
// {
// Console.Write("Query is not complete, Error {0:G}", TDengine.ErrorNo(res), TDengine.Error(res));
// }
// TDengine.FreeResult(res); Console.WriteLine("");
}
public static List<List<string>> GetResultSet(IntPtr res)
{
List<List<string>> result = new List<List<string>>();
List<string> colName = new List<string>();
List<string> dataRaw = new List<string>();
if (!IsValidResult(res))
{
ExitProgram();
}
List<TDengineMeta> metas = GetResField(res);
result.Add(colName);
dataRaw = QueryRes(res, metas);
result.Add(dataRaw);
if (TDengine.ErrorNo(res) != 0)
{
Console.Write("Query is not complete, Error {0:G}", TDengine.ErrorNo(res), TDengine.Error(res));
}
return result;
}
public static bool IsValidResult(IntPtr res)
{
if ((res == IntPtr.Zero) || (TDengine.ErrorNo(res) != 0))
{
if (res != IntPtr.Zero)
{
Console.Write("reason: " + TDengine.Error(res));
return false;
}
Console.WriteLine("");
return false;
}
return true;
}
public static void CloseConnection(IntPtr conn)
{
ExecuteUpdate(conn, "drop database if exists csharp");
if (conn != IntPtr.Zero)
{
if (TDengine.Close(conn) == 0)
{
Console.WriteLine("close connection sucess");
}
else
{
Console.WriteLine("close Connection failed");
}
}
}
public static List<TDengineMeta> GetResField(IntPtr res)
{
List<TDengineMeta> metas = TDengine.FetchFields(res);
return metas;
}
public static void AssertEqual(string expectVal, string actualVal)
{
if (expectVal == actualVal)
{
Console.WriteLine("{0}=={1} pass", expectVal, actualVal);
}
else
{
Console.WriteLine("{0}=={1} failed", expectVal, actualVal);
ExitProgram();
}
}
public static void ExitProgram()
{
TDengine.Cleanup();
System.Environment.Exit(0);
}
public static List<String> GetResData(IntPtr res)
{
List<string> colName = new List<string>();
List<string> dataRaw = new List<string>();
if (!IsValidResult(res))
{
ExitProgram();
}
List<TDengineMeta> metas = GetResField(res);
dataRaw = QueryRes(res, metas);
return dataRaw;
}
public static TDengineMeta ConstructTDengineMeta(string name, string type)
{
TDengineMeta _meta = new TDengineMeta();
_meta.name = name;
char[] separators = new char[] { '(', ')' };
string[] subs = type.Split(separators, StringSplitOptions.RemoveEmptyEntries);
switch (subs[0].ToUpper())
{
case "BOOL":
_meta.type = 1;
_meta.size = 1;
break;
case "TINYINT":
_meta.type = 2;
_meta.size = 1;
break;
case "SMALLINT":
_meta.type = 3;
_meta.size = 2;
break;
case "INT":
_meta.type = 4;
_meta.size = 4;
break;
case "BIGINT":
_meta.type = 5;
_meta.size = 8;
break;
case "TINYINT UNSIGNED":
_meta.type = 11;
_meta.size = 1;
break;
case "SMALLINT UNSIGNED":
_meta.type = 12;
_meta.size = 2;
break;
case "INT UNSIGNED":
_meta.type = 13;
_meta.size = 4;
break;
case "BIGINT UNSIGNED":
_meta.type = 14;
_meta.size = 8;
break;
case "FLOAT":
_meta.type = 6;
_meta.size = 4;
break;
case "DOUBLE":
_meta.type = 7;
_meta.size = 8;
break;
case "BINARY":
_meta.type = 8;
_meta.size = short.Parse(subs[1]);
break;
case "TIMESTAMP":
_meta.type = 9;
_meta.size = 8;
break;
case "NCHAR":
_meta.type = 10;
_meta.size = short.Parse(subs[1]);
break;
case "JSON":
_meta.type = 15;
_meta.size = 4096;
break;
default:
_meta.type = byte.MaxValue;
_meta.size = 0;
break;
}
return _meta;
}
private static List<string> QueryRes(IntPtr res, List<TDengineMeta> metas)
{
IntPtr rowdata;
long queryRows = 0;
List<string> dataRaw = new List<string>();
int fieldCount = metas.Count;
while ((rowdata = TDengine.FetchRows(res)) != IntPtr.Zero)
{
queryRows++;
IntPtr colLengthPtr = TDengine.FetchLengths(res);
int[] colLengthArr = new int[fieldCount];
Marshal.Copy(colLengthPtr, colLengthArr, 0, fieldCount);
for (int fields = 0; fields < fieldCount; ++fields)
{
TDengineMeta meta = metas[fields];
int offset = IntPtr.Size * fields;
IntPtr data = Marshal.ReadIntPtr(rowdata, offset);
if (data == IntPtr.Zero)
{
dataRaw.Add("NULL");
continue;
}
switch ((TDengineDataType)meta.type)
{
case TDengineDataType.TSDB_DATA_TYPE_BOOL:
bool v1 = Marshal.ReadByte(data) == 0 ? false : true;
dataRaw.Add(v1.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_TINYINT:
sbyte v2 = (sbyte)Marshal.ReadByte(data);
dataRaw.Add(v2.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_SMALLINT:
short v3 = Marshal.ReadInt16(data);
dataRaw.Add(v3.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_INT:
int v4 = Marshal.ReadInt32(data);
dataRaw.Add(v4.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_BIGINT:
long v5 = Marshal.ReadInt64(data);
dataRaw.Add(v5.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_FLOAT:
float v6 = (float)Marshal.PtrToStructure(data, typeof(float));
dataRaw.Add(v6.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_DOUBLE:
double v7 = (double)Marshal.PtrToStructure(data, typeof(double));
dataRaw.Add(v7.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_BINARY:
string v8 = Marshal.PtrToStringAnsi(data, colLengthArr[fields]);
dataRaw.Add(v8);
break;
case TDengineDataType.TSDB_DATA_TYPE_TIMESTAMP:
long v9 = Marshal.ReadInt64(data);
dataRaw.Add(v9.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_NCHAR:
string v10 = Marshal.PtrToStringAnsi(data, colLengthArr[fields]);
dataRaw.Add(v10);
break;
case TDengineDataType.TSDB_DATA_TYPE_UTINYINT:
byte v12 = Marshal.ReadByte(data);
dataRaw.Add(v12.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_USMALLINT:
ushort v13 = (ushort)Marshal.ReadInt16(data);
dataRaw.Add(v13.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_UINT:
uint v14 = (uint)Marshal.ReadInt32(data);
dataRaw.Add(v14.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_UBIGINT:
ulong v15 = (ulong)Marshal.ReadInt64(data);
dataRaw.Add(v15.ToString());
break;
default:
dataRaw.Add("unknown value");
break;
}
}
}
if (TDengine.ErrorNo(res) != 0)
{
Console.Write("Query is not complete, Error {0:G}", TDengine.ErrorNo(res), TDengine.Error(res));
}
TDengine.FreeResult(res);
Console.WriteLine("");
return dataRaw;
}
}
}
......@@ -6,6 +6,11 @@ namespace TDengineDriver.Test
{
public class TestTDengineMeta
{
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameBool</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's bool meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameBool()
{
......@@ -17,7 +22,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameTINYINT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's TinnyInt's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameTINYINT()
{
......@@ -29,6 +38,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameSMALLINT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's SMALLINT's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameSMALLINT()
{
......@@ -40,6 +54,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameINT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's INT's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameINT()
{
......@@ -51,6 +70,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameBIGINT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's BIGINT's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameBIGINT()
{
......@@ -62,6 +86,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameUTINYINT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's TINYINT UNSIGNED's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameUTINYINT()
{
......@@ -73,6 +102,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameUSMALLINT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's SMALLINT UNSIGNED's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameUSMALLINT()
{
......@@ -84,6 +118,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameUINT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's INT UNSIGNED's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameUINT()
{
......@@ -95,6 +134,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameUBIGINT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's BIGINT UNSIGNED's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameUBIGINT()
{
......@@ -106,7 +150,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameFLOAT</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's FLOAT's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameFLOAT()
{
......@@ -118,6 +166,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameDOUBLE</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's DOUBLE's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameDOUBLE()
{
......@@ -129,10 +182,15 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameSTRING</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's BINARY's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameSTRING()
{
string typeName = "STRING";
string typeName = "BINARY";
TDengineDriver.TDengineMeta meta = new TDengineDriver.TDengineMeta();
meta.type = 8;
string metaTypeName = meta.TypeName();
......@@ -140,6 +198,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameTIMESTAMP</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's TIMESTAMP's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameTIMESTAMP()
{
......@@ -151,6 +214,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameNCHAR</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's NCHAR's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameNCHAR()
{
......@@ -162,6 +230,11 @@ namespace TDengineDriver.Test
Assert.Equal(metaTypeName, typeName);
}
/// <author>xiaolei</author>
/// <Name>TestTDengineMeta.TestTypeNameUndefined</Name>
/// <describe>Unit test for oject TDengineDriver.TDengineMeta's undefine's meta info</describe>
/// <filename>TestTDengineMeta.cs</filename>
/// <result>pass or failed </result>
[Fact]
public void TestTypeNameUndefined()
{
......
......@@ -173,6 +173,7 @@ typedef void *TsdbQueryHandleT; // Use void to hide implementation details
typedef struct STsdbQueryCond {
STimeWindow twindow;
int32_t order; // desc|asc order to iterate the data block
int64_t offset; // skip offset put down to tsdb
int32_t numOfCols;
SColumnInfo *colList;
bool loadExternalRows; // load external rows or not
......@@ -391,6 +392,9 @@ void tsdbResetQueryHandleForNewTable(TsdbQueryHandleT queryHandle, STsdbQueryCon
int32_t tsdbGetFileBlocksDistInfo(TsdbQueryHandleT* queryHandle, STableBlockDist* pTableBlockInfo);
// obtain queryHandle attribute
int64_t tsdbSkipOffset(TsdbQueryHandleT queryHandle);
/**
* get the statistics of repo usage
* @param repo. point to the tsdbrepo
......
......@@ -131,7 +131,7 @@ static void *shellCheckThreadFp(void *arg) {
char *tbname = tbNames[t];
if (tbname == NULL) break;
snprintf(sql, SHELL_SQL_LEN, "select last_row(_c0) from %s;", tbname);
snprintf(sql, SHELL_SQL_LEN, "select count(*) from %s;", tbname);
TAOS_RES *pSql = taos_query(pThread->taos, sql);
int32_t code = taos_errno(pSql);
......
......@@ -43,7 +43,7 @@ void mnodeCheckUnCreatedVgroup(SDnodeObj *pDnode, SVnodeLoad *pVloads, int32_
int32_t mnodeCreateVgroup(struct SMnodeMsg *pMsg);
void mnodeDropVgroup(SVgObj *pVgroup, void *ahandle);
void mnodeAlterVgroup(SVgObj *pVgroup, void *ahandle);
int32_t mnodeGetAvailableVgroup(struct SMnodeMsg *pMsg, SVgObj **pVgroup, int32_t *sid);
int32_t mnodeGetAvailableVgroup(struct SMnodeMsg *pMsg, SVgObj **pVgroup, int32_t *sid, int32_t vgId);
int32_t mnodeAddTableIntoVgroup(SVgObj *pVgroup, SCTableObj *pTable, bool needCheck);
void mnodeRemoveTableFromVgroup(SVgObj *pVgroup, SCTableObj *pTable);
......
......@@ -48,6 +48,12 @@
#define CREATE_CTABLE_RETRY_TIMES 10
#define CREATE_CTABLE_RETRY_SEC 14
// informal
#define META_SYNC_TABLE_NAME "_taos_meta_sync_table_name_taos_"
#define META_SYNC_TABLE_NAME_LEN 32
static int32_t tsMetaSyncOption = 0;
// informal
int64_t tsCTableRid = -1;
static void * tsChildTableSdb;
int64_t tsSTableRid = -1;
......@@ -1726,6 +1732,9 @@ int32_t mnodeRetrieveShowSuperTables(SShowObj *pShow, char *data, int32_t rows,
cols++;
numOfRows++;
mDebug("stable: %s, uid: %" PRIu64, prefix, pTable->uid);
mnodeDecTableRef(pTable);
}
......@@ -2227,9 +2236,19 @@ static int32_t mnodeProcessCreateChildTableMsg(SMnodeMsg *pMsg) {
if (pMsg->pTable == NULL) {
SVgObj *pVgroup = NULL;
int32_t tid = 0;
code = mnodeGetAvailableVgroup(pMsg, &pVgroup, &tid);
int32_t vgId = 0;
if (tsMetaSyncOption) {
char *pTbName = strchr(pCreate->tableName, '.');
if (pTbName && (pTbName = strchr(pTbName + 1, '.'))) {
if (0 == strncmp(META_SYNC_TABLE_NAME, ++pTbName, META_SYNC_TABLE_NAME_LEN)) {
vgId = atoi(pTbName + META_SYNC_TABLE_NAME_LEN);
}
}
}
code = mnodeGetAvailableVgroup(pMsg, &pVgroup, &tid, vgId);
if (code != TSDB_CODE_SUCCESS) {
mDebug("msg:%p, app:%p table:%s, failed to get available vgroup, reason:%s", pMsg, pMsg->rpcMsg.ahandle,
mError("msg:%p, app:%p table:%s, failed to get available vgroup, reason:%s", pMsg, pMsg->rpcMsg.ahandle,
pCreate->tableName, tstrerror(code));
return code;
}
......
......@@ -428,10 +428,47 @@ static int32_t mnodeAllocVgroupIdPool(SVgObj *pInputVgroup) {
return TSDB_CODE_SUCCESS;
}
int32_t mnodeGetAvailableVgroup(SMnodeMsg *pMsg, SVgObj **ppVgroup, int32_t *pSid) {
int32_t mnodeGetAvailableVgroup(SMnodeMsg *pMsg, SVgObj **ppVgroup, int32_t *pSid, int32_t vgId) {
SDbObj *pDb = pMsg->pDb;
pthread_mutex_lock(&pDb->mutex);
if (vgId > 0) {
for (int32_t v = 0; v < pDb->numOfVgroups; ++v) {
SVgObj *pVgroup = pDb->vgList[v];
if (pVgroup == NULL) {
mError("db:%s, vgroup: %d is null", pDb->name, v);
pthread_mutex_unlock(&pDb->mutex);
return TSDB_CODE_MND_APP_ERROR;
}
if (pVgroup->vgId != (uint32_t)vgId) { // find the target vgId
continue;
}
int32_t sid = taosAllocateId(pVgroup->idPool);
if (sid <= 0) {
int curMaxId = taosIdPoolMaxSize(pVgroup->idPool);
if ((taosUpdateIdPool(pVgroup->idPool, curMaxId + 1) < 0) || ((sid = taosAllocateId(pVgroup->idPool)) <= 0)) {
mError("msg:%p, app:%p db:%s, no enough sid in vgId:%d", pMsg, pMsg->rpcMsg.ahandle, pDb->name,
pVgroup->vgId);
pthread_mutex_unlock(&pDb->mutex);
return TSDB_CODE_MND_APP_ERROR;
}
}
mDebug("vgId:%d, alloc tid:%d", pVgroup->vgId, sid);
*pSid = sid;
*ppVgroup = pVgroup;
pDb->vgListIndex = v;
pthread_mutex_unlock(&pDb->mutex);
return TSDB_CODE_SUCCESS;
}
pthread_mutex_unlock(&pDb->mutex);
mError("db:%s, vgroup: %d not exist", pDb->name, vgId);
return TSDB_CODE_MND_APP_ERROR;
}
for (int32_t v = 0; v < pDb->numOfVgroups; ++v) {
int vgIndex = (v + pDb->vgListIndex) % pDb->numOfVgroups;
SVgObj *pVgroup = pDb->vgList[vgIndex];
......
......@@ -458,14 +458,18 @@ static void monBuildMonitorSql(char *sql, int32_t cmd) {
", expire_time int, timeseries_used int, timeseries_total int)",
tsMonitorDbName);
} else if (cmd == MON_CMD_CREATE_MT_RESTFUL) {
int usedLen = 0, len = 0;
int pos = snprintf(sql, SQL_LENGTH,
"create table if not exists %s.restful_info(ts timestamp", tsMonitorDbName);
usedLen += pos;
for (int i = 0; i < tListLen(monHttpStatusTable); ++i) {
pos += snprintf(sql + pos, SQL_LENGTH, ", `%s(%d)` int",
len = snprintf(sql + pos, SQL_LENGTH - usedLen, ", %s_%d int",
monHttpStatusTable[i].name,
monHttpStatusTable[i].code);
usedLen += len;
pos += len;
}
snprintf(sql + pos, SQL_LENGTH,
snprintf(sql + pos, SQL_LENGTH - usedLen,
") tags (dnode_id int, dnode_ep binary(%d))",
TSDB_EP_LEN);
} else if (cmd == MON_CMD_CREATE_TB_RESTFUL) {
......
Subproject commit fd84b35d3a30c9bcf3939d565f717b7f98ff9eb7
Subproject commit 47fb0b3e627ddadf1ca983c1d75b9a4e44cd98fd
......@@ -237,6 +237,7 @@ typedef struct SQueryAttr {
bool createFilterOperator; // if filter operator is needed
bool multigroupResult; // multigroup result can exist in one SSDataBlock
bool needSort; // need sort rowRes
bool skipOffset; // can skip offset if true
int32_t interBufSize; // intermediate buffer sizse
int32_t havingNum; // having expr number
......
......@@ -1620,33 +1620,65 @@ static bool first_last_function_setup(SQLFunctionCtx *pCtx, SResultRowCellInfo*
// todo opt for null block
static void first_function(SQLFunctionCtx *pCtx) {
if (pCtx->order == TSDB_ORDER_DESC) {
return;
}
SResultRowCellInfo* pResInfo = GET_RES_INFO(pCtx);
int32_t notNullElems = 0;
// handle the null value
for (int32_t i = 0; i < pCtx->size; ++i) {
char *data = GET_INPUT_DATA(pCtx, i);
if (pCtx->hasNull && isNull(data, pCtx->inputType)) {
continue;
}
memcpy(pCtx->pOutput, data, pCtx->inputBytes);
if (pCtx->ptsList != NULL) {
TSKEY k = GET_TS_DATA(pCtx, i);
DO_UPDATE_TAG_COLUMNS(pCtx, k);
int32_t step = 1;
int32_t i = 0;
bool inputAsc = true;
// input data come from sub query, input data order equal to sub query order
if(pCtx->numOfParams == 3) {
if(pCtx->param[2].nType == TSDB_DATA_TYPE_INT && pCtx->param[2].i64 == TSDB_ORDER_DESC) {
step = -1;
i = pCtx->size - 1;
inputAsc = false;
}
} else if (pCtx->order == TSDB_ORDER_DESC) {
return ;
}
if(pCtx->order == TSDB_ORDER_ASC && inputAsc) {
for (int32_t m = 0; m < pCtx->size; ++m, i+=step) {
char *data = GET_INPUT_DATA(pCtx, i);
if (pCtx->hasNull && isNull(data, pCtx->inputType)) {
continue;
}
memcpy(pCtx->pOutput, data, pCtx->inputBytes);
if (pCtx->ptsList != NULL) {
TSKEY k = GET_TS_DATA(pCtx, i);
DO_UPDATE_TAG_COLUMNS(pCtx, k);
}
SResultRowCellInfo *pInfo = GET_RES_INFO(pCtx);
pInfo->hasResult = DATA_SET_FLAG;
pInfo->complete = true;
notNullElems++;
break;
}
} else { // desc order
for (int32_t m = 0; m < pCtx->size; ++m, i+=step) {
char *data = GET_INPUT_DATA(pCtx, i);
if (pCtx->hasNull && isNull(data, pCtx->inputType) && (!pCtx->requireNull)) {
continue;
}
SResultRowCellInfo *pInfo = GET_RES_INFO(pCtx);
pInfo->hasResult = DATA_SET_FLAG;
pInfo->complete = true;
notNullElems++;
break;
TSKEY ts = pCtx->ptsList ? GET_TS_DATA(pCtx, i) : 0;
char* buf = GET_ROWCELL_INTERBUF(pResInfo);
if (pResInfo->hasResult != DATA_SET_FLAG || (*(TSKEY*)buf) > ts) {
pResInfo->hasResult = DATA_SET_FLAG;
memcpy(pCtx->pOutput, data, pCtx->inputBytes);
*(TSKEY*)buf = ts;
DO_UPDATE_TAG_COLUMNS(pCtx, ts);
}
notNullElems++;
break;
}
}
SET_VAL(pCtx, notNullElems, 1);
}
......@@ -1730,16 +1762,23 @@ static void first_dist_func_merge(SQLFunctionCtx *pCtx) {
* least one data in this block that is not null.(TODO opt for this case)
*/
static void last_function(SQLFunctionCtx *pCtx) {
if (pCtx->order != pCtx->param[0].i64) {
SResultRowCellInfo* pResInfo = GET_RES_INFO(pCtx);
int32_t notNullElems = 0;
int32_t step = -1;
int32_t i = pCtx->size - 1;
// input data come from sub query, input data order equal to sub query order
if(pCtx->numOfParams == 3) {
if(pCtx->param[2].nType == TSDB_DATA_TYPE_INT && pCtx->param[2].i64 == TSDB_ORDER_DESC) {
step = 1;
i = 0;
}
} else if (pCtx->order != pCtx->param[0].i64) {
return;
}
SResultRowCellInfo* pResInfo = GET_RES_INFO(pCtx);
int32_t notNullElems = 0;
if (pCtx->order == TSDB_ORDER_DESC) {
for (int32_t i = pCtx->size - 1; i >= 0; --i) {
for (int32_t m = pCtx->size - 1; m >= 0; --m, i += step) {
char *data = GET_INPUT_DATA(pCtx, i);
if (pCtx->hasNull && isNull(data, pCtx->inputType) && (!pCtx->requireNull)) {
continue;
......@@ -1756,7 +1795,7 @@ static void last_function(SQLFunctionCtx *pCtx) {
break;
}
} else { // ascending order
for (int32_t i = pCtx->size - 1; i >= 0; --i) {
for (int32_t m = pCtx->size - 1; m >= 0; --m, i += step) {
char *data = GET_INPUT_DATA(pCtx, i);
if (pCtx->hasNull && isNull(data, pCtx->inputType) && (!pCtx->requireNull)) {
continue;
......
......@@ -4905,6 +4905,11 @@ STsdbQueryCond createTsdbQueryCond(SQueryAttr* pQueryAttr, STimeWindow* win) {
.loadExternalRows = false,
};
// set offset with
if(pQueryAttr->skipOffset) {
cond.offset = pQueryAttr->limit.offset;
}
TIME_WINDOW_COPY(cond.twindow, *win);
return cond;
}
......@@ -5607,6 +5612,18 @@ static int32_t getTableScanOrder(STableScanInfo* pTableScanInfo) {
return pTableScanInfo->order;
}
// check all SQLFunctionCtx is completed
static bool allCtxCompleted(SOperatorInfo* pOperator, SQLFunctionCtx* pCtx) {
// only one false, return false
for(int32_t i = 0; i < pOperator->numOfOutput; i++) {
if(pCtx[i].resultInfo == NULL)
return false;
if(!pCtx[i].resultInfo->complete)
return false;
}
return true;
}
// this is a blocking operator
static SSDataBlock* doAggregate(void* param, bool* newgroup) {
SOperatorInfo* pOperator = (SOperatorInfo*) param;
......@@ -5645,6 +5662,9 @@ static SSDataBlock* doAggregate(void* param, bool* newgroup) {
// the pDataBlock are always the same one, no need to call this again
setInputDataBlock(pOperator, pInfo->pCtx, pBlock, order);
doAggregateImpl(pOperator, pQueryAttr->window.skey, pInfo->pCtx, pBlock);
// if all pCtx is completed, then query should be over
if(allCtxCompleted(pOperator, pInfo->pCtx))
break;
}
doSetOperatorCompleted(pOperator);
......@@ -5858,19 +5878,38 @@ static SSDataBlock* doLimit(void* param, bool* newgroup) {
return NULL;
}
bool move = false;
int32_t skip = 0;
int32_t remain = 0;
int64_t srows = tsdbSkipOffset(pRuntimeEnv->pQueryHandle);
if (pRuntimeEnv->currentOffset == 0) {
break;
}
else if(srows > 0) {
if(pRuntimeEnv->currentOffset - srows >= pBlock->info.rows) {
pRuntimeEnv->currentOffset -= pBlock->info.rows;
} else {
move = true;
skip = (int32_t)(pRuntimeEnv->currentOffset - srows);
remain = (int32_t)(pBlock->info.rows - skip);
}
} else if (pRuntimeEnv->currentOffset >= pBlock->info.rows) {
pRuntimeEnv->currentOffset -= pBlock->info.rows;
} else {
int32_t remain = (int32_t)(pBlock->info.rows - pRuntimeEnv->currentOffset);
move = true;
skip = (int32_t)pRuntimeEnv->currentOffset;
remain = (int32_t)(pBlock->info.rows - pRuntimeEnv->currentOffset);
}
// need move
if(move) {
pBlock->info.rows = remain;
for (int32_t i = 0; i < pBlock->info.numOfCols; ++i) {
SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, i);
int16_t bytes = pColInfoData->info.bytes;
memmove(pColInfoData->pData, pColInfoData->pData + bytes * pRuntimeEnv->currentOffset, remain * bytes);
memmove(pColInfoData->pData, pColInfoData->pData + skip * bytes, remain * bytes);
}
pRuntimeEnv->currentOffset = 0;
......@@ -8945,6 +8984,14 @@ SQInfo* createQInfoImpl(SQueryTableMsg* pQueryMsg, SGroupbyExpr* pGroupbyExpr, S
doUpdateExprColumnIndex(pQueryAttr);
// calc skipOffset
if(pQueryMsg->offset > 0 && TSDB_QUERY_HAS_TYPE(pQueryMsg->queryType, TSDB_QUERY_TYPE_PROJECTION_QUERY)) {
if(pQueryAttr->stableQuery)
pQueryAttr->skipOffset = false;
else
pQueryAttr->skipOffset = pQueryAttr->pFilters == NULL;
}
if (pSecExprs != NULL) {
int32_t resultRowSize = 0;
......
......@@ -39,6 +39,9 @@
.tid = (_checkInfo)->tableId.tid, \
.uid = (_checkInfo)->tableId.uid})
// limit offset start optimization for rows read over this value
#define OFFSET_SKIP_THRESHOLD 5000
enum {
TSDB_QUERY_TYPE_ALL = 1,
TSDB_QUERY_TYPE_LAST = 2,
......@@ -117,6 +120,9 @@ typedef struct STsdbQueryHandle {
STsdbRepo* pTsdb;
SQueryFilePos cur; // current position
int16_t order;
int64_t offset; // limit offset
int64_t srows; // skip offset rows
int64_t frows; // forbid skip offset rows
STimeWindow window; // the primary query time window that applies to all queries
SDataStatis* statis; // query level statistics, only one table block statistics info exists at any time
int32_t numOfBlocks;
......@@ -155,6 +161,11 @@ typedef struct STableGroupSupporter {
STSchema* pTagSchema;
} STableGroupSupporter;
typedef struct SRange {
int32_t from;
int32_t to;
} SRange;
static STimeWindow updateLastrowForEachGroup(STableGroupInfo *groupList);
static int32_t checkForCachedLastRow(STsdbQueryHandle* pQueryHandle, STableGroupInfo *groupList);
static int32_t checkForCachedLast(STsdbQueryHandle* pQueryHandle);
......@@ -413,6 +424,9 @@ static STsdbQueryHandle* tsdbQueryTablesImpl(STsdbRepo* tsdb, STsdbQueryCond* pC
}
pQueryHandle->order = pCond->order;
pQueryHandle->offset = pCond->offset;
pQueryHandle->srows = 0;
pQueryHandle->frows = 0;
pQueryHandle->pTsdb = tsdb;
pQueryHandle->type = TSDB_QUERY_TYPE_ALL;
pQueryHandle->cur.fid = INT32_MIN;
......@@ -529,6 +543,9 @@ void tsdbResetQueryHandle(TsdbQueryHandleT queryHandle, STsdbQueryCond *pCond) {
}
pQueryHandle->order = pCond->order;
pQueryHandle->offset = pCond->offset;
pQueryHandle->srows = 0;
pQueryHandle->frows = 0;
pQueryHandle->window = pCond->twindow;
pQueryHandle->type = TSDB_QUERY_TYPE_ALL;
pQueryHandle->cur.fid = -1;
......@@ -1073,63 +1090,302 @@ static int32_t binarySearchForBlock(SBlock* pBlock, int32_t numOfBlocks, TSKEY s
return midSlot;
}
static int32_t loadBlockInfo(STsdbQueryHandle * pQueryHandle, int32_t index, int32_t* numOfBlocks) {
int32_t code = 0;
// array :1 2 3 5 7 -2 (8 9) skip 4 and 6
int32_t memMoveByArray(SBlock *blocks, SArray *pArray) {
// pArray is NULL or size is zero , no need block to move
if(pArray == NULL)
return 0;
size_t count = taosArrayGetSize(pArray);
if(count == 0)
return 0;
STableCheckInfo* pCheckInfo = taosArrayGet(pQueryHandle->pTableCheckInfo, index);
pCheckInfo->numOfBlocks = 0;
// memmove
int32_t num = 0;
SRange* ranges = (SRange*)TARRAY_GET_START(pArray);
for(size_t i = 0; i < count; i++) {
int32_t step = ranges[i].to - ranges[i].from + 1;
memmove(blocks + num, blocks + ranges[i].from, sizeof(SBlock) * step);
num += step;
}
if (tsdbSetReadTable(&pQueryHandle->rhelper, pCheckInfo->pTableObj) != TSDB_CODE_SUCCESS) {
code = terrno;
return code;
return num;
}
// if block data in memory return false else true
bool blockNoItemInMem(STsdbQueryHandle* q, SBlock* pBlock) {
if(q->pMemRef == NULL) {
return false;
}
SBlockIdx* compIndex = pQueryHandle->rhelper.pBlkIdx;
// mem
if(q->pMemRef->snapshot.mem) {
SMemTable* mem = q->pMemRef->snapshot.mem;
if(timeIntersect(mem->keyFirst, mem->keyLast, pBlock->keyFirst, pBlock->keyLast))
return false;
}
// imem
if(q->pMemRef->snapshot.imem) {
SMemTable* imem = q->pMemRef->snapshot.imem;
if(timeIntersect(imem->keyFirst, imem->keyLast, pBlock->keyFirst, pBlock->keyLast))
return false;
}
// no data block in this file, try next file
if (compIndex == NULL || compIndex->uid != pCheckInfo->tableId.uid) {
return 0; // no data blocks in the file belongs to pCheckInfo->pTable
return true;
}
#define MAYBE_IN_MEMORY_ROWS 4000 // approximately the capacity of one block
// skip blocks . return value is skip blocks number, skip rows reduce from *pOffset
static int32_t offsetSkipBlock(STsdbQueryHandle* q, SBlockInfo* pBlockInfo, int64_t skey, int64_t ekey,
int32_t sblock, int32_t eblock, SArray** ppArray, bool order) {
int32_t num = 0;
SBlock* blocks = pBlockInfo->blocks;
SArray* pArray = NULL;
SRange range;
range.from = -1;
//
// ASC
//
if(order) {
for(int32_t i = sblock; i < eblock; i++) {
bool skip = false;
SBlock* pBlock = &blocks[i];
if(i == sblock && skey > pBlock->keyFirst) {
q->frows += pBlock->numOfRows; // some rows time < s
} else {
// check can skip
if(q->srows + q->frows + pBlock->numOfRows + MAYBE_IN_MEMORY_ROWS < q->offset) { // approximately calculate
if(blockNoItemInMem(q, pBlock)) {
// can skip
q->srows += pBlock->numOfRows;
skip = true;
} else {
q->frows += pBlock->numOfRows; // maybe have some row in memroy
}
} else {
// the remainder be put to pArray
if(pArray == NULL)
pArray = taosArrayInit(1, sizeof(SRange));
if(range.from == -1) {
range.from = i;
} else {
if(range.to + 1 != i) {
// add the previous
taosArrayPush(pArray, &range);
range.from = i;
}
}
range.to = eblock - 1;
taosArrayPush(pArray, &range);
range.from = -1;
break;
}
}
if(skip) {
num ++;
} else {
// can't skip, append block index to pArray
if(pArray == NULL)
pArray = taosArrayInit(10, sizeof(SRange));
if(range.from == -1) {
range.from = i;
} else {
if(range.to + 1 != i) {
// add the previous
taosArrayPush(pArray, &range);
range.from = i;
}
}
range.to = i;
}
}
// end append
if(range.from != -1) {
if(pArray == NULL)
pArray = taosArrayInit(1, sizeof(SRange));
taosArrayPush(pArray, &range);
}
// ASC return
*ppArray = pArray;
return num;
}
// DES
for(int32_t i = eblock - 1; i >= sblock; i--) {
bool skip = false;
SBlock* pBlock = &blocks[i];
if(i == eblock - 1 && ekey < pBlock->keyLast) {
q->frows += pBlock->numOfRows; // some rows time > e
} else {
// check can skip
if(q->srows + q->frows + pBlock->numOfRows + MAYBE_IN_MEMORY_ROWS < q->offset) { // approximately calculate
if(blockNoItemInMem(q, pBlock)) {
// can skip
q->srows += pBlock->numOfRows;
skip = true;
} else {
q->frows += pBlock->numOfRows; // maybe have some row in memroy
}
} else {
// the remainder be put to pArray
if(pArray == NULL)
pArray = taosArrayInit(1, sizeof(SRange));
if(range.from == -1) {
range.from = i;
} else {
if(range.to - 1 != i) {
// add the previous
taosArrayPush(pArray, &range);
range.from = i;
}
}
range.to = 0;
taosArrayPush(pArray, &range);
range.from = -1;
break;
}
}
if(skip) {
num ++;
} else {
// can't skip, append block index to pArray
if(pArray == NULL)
pArray = taosArrayInit(10, sizeof(SRange));
if(range.from == -1) {
range.from = i;
} else {
if(range.to + 1 != i) {
// add the previous
taosArrayPush(pArray, &range);
range.from = i;
}
}
range.to = i;
}
}
assert(compIndex->len > 0);
// end append
if(range.from != -1) {
if(pArray == NULL)
pArray = taosArrayInit(1, sizeof(SRange));
taosArrayPush(pArray, &range);
}
if(pArray == NULL)
return num;
if (tsdbLoadBlockInfo(&(pQueryHandle->rhelper), (void**)(&pCheckInfo->pCompInfo),
(uint32_t*)(&pCheckInfo->compSize)) < 0) {
return terrno;
// reverse array
size_t count = taosArrayGetSize(pArray);
SRange* ranges = TARRAY_GET_START(pArray);
SArray* pArray1 = taosArrayInit(count, sizeof(SRange));
size_t i = count - 1;
while(i >= 0) {
range.from = ranges[i].to;
range.to = ranges[i].from;
taosArrayPush(pArray1, &range);
if(i == 0)
break;
i --;
}
SBlockInfo* pCompInfo = pCheckInfo->pCompInfo;
TSKEY s = TSKEY_INITIAL_VAL, e = TSKEY_INITIAL_VAL;
*ppArray = pArray1;
taosArrayDestroy(&pArray);
return num;
}
if (ASCENDING_TRAVERSE(pQueryHandle->order)) {
// shrink blocks by condition of query
static void shrinkBlocksByQuery(STsdbQueryHandle *pQueryHandle, STableCheckInfo *pCheckInfo) {
SBlockInfo *pCompInfo = pCheckInfo->pCompInfo;
SBlockIdx *compIndex = pQueryHandle->rhelper.pBlkIdx;
bool order = ASCENDING_TRAVERSE(pQueryHandle->order);
if (order) {
assert(pCheckInfo->lastKey <= pQueryHandle->window.ekey && pQueryHandle->window.skey <= pQueryHandle->window.ekey);
} else {
assert(pCheckInfo->lastKey >= pQueryHandle->window.ekey && pQueryHandle->window.skey >= pQueryHandle->window.ekey);
}
TSKEY s = TSKEY_INITIAL_VAL, e = TSKEY_INITIAL_VAL;
s = MIN(pCheckInfo->lastKey, pQueryHandle->window.ekey);
e = MAX(pCheckInfo->lastKey, pQueryHandle->window.ekey);
// discard the unqualified data block based on the query time window
int32_t start = binarySearchForBlock(pCompInfo->blocks, compIndex->numOfBlocks, s, TSDB_ORDER_ASC);
int32_t end = start;
if (s > pCompInfo->blocks[start].keyLast) {
return 0;
return ;
}
// todo speedup the procedure of located end block
int32_t end = start;
// locate e index of blocks -> end
while (end < (int32_t)compIndex->numOfBlocks && (pCompInfo->blocks[end].keyFirst <= e)) {
end += 1;
}
pCheckInfo->numOfBlocks = (end - start);
// calc offset can skip blocks number
int32_t nSkip = 0;
SArray *pArray = NULL;
if(pQueryHandle->offset > 0) {
nSkip = offsetSkipBlock(pQueryHandle, pCompInfo, s, e, start, end, &pArray, order);
}
if(nSkip > 0) { // have offset and can skip
pCheckInfo->numOfBlocks = memMoveByArray(pCompInfo->blocks, pArray);
} else { // no offset
pCheckInfo->numOfBlocks = end - start;
if(start > 0)
memmove(pCompInfo->blocks, &pCompInfo->blocks[start], pCheckInfo->numOfBlocks * sizeof(SBlock));
}
if(pArray)
taosArrayDestroy(&pArray);
}
// load one table (tsd_index point to) need load blocks info and put into pCheckInfo->pCompInfo->blocks
static int32_t loadBlockInfo(STsdbQueryHandle * pQueryHandle, int32_t tsd_index, int32_t* numOfBlocks) {
//
// ONE PART. Load all blocks info from one table of tsd_index
//
int32_t code = 0;
STableCheckInfo* pCheckInfo = taosArrayGet(pQueryHandle->pTableCheckInfo, tsd_index);
pCheckInfo->numOfBlocks = 0;
if (tsdbSetReadTable(&pQueryHandle->rhelper, pCheckInfo->pTableObj) != TSDB_CODE_SUCCESS) {
code = terrno;
return code;
}
SBlockIdx* compIndex = pQueryHandle->rhelper.pBlkIdx;
// no data block in this file, try next file
if (compIndex == NULL || compIndex->uid != pCheckInfo->tableId.uid) {
return 0; // no data blocks in the file belongs to pCheckInfo->pTable
}
if (start > 0) {
memmove(pCompInfo->blocks, &pCompInfo->blocks[start], pCheckInfo->numOfBlocks * sizeof(SBlock));
if (pCheckInfo->compSize < (int32_t)compIndex->len) {
assert(compIndex->len > 0);
char* t = realloc(pCheckInfo->pCompInfo, compIndex->len);
if (t == NULL) {
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
code = TSDB_CODE_TDB_OUT_OF_MEMORY;
return code;
}
pCheckInfo->pCompInfo = (SBlockInfo*)t;
pCheckInfo->compSize = compIndex->len;
}
if (tsdbLoadBlockInfo(&(pQueryHandle->rhelper), (void**)(&pCheckInfo->pCompInfo),
(uint32_t*)(&pCheckInfo->compSize)) < 0) {
return terrno;
}
//
// TWO PART. shrink no need blocks from all blocks by condition of query
//
shrinkBlocksByQuery(pQueryHandle, pCheckInfo);
(*numOfBlocks) += pCheckInfo->numOfBlocks;
return 0;
}
......@@ -4312,4 +4568,11 @@ end:
return string;
}
// obtain queryHandle attribute
int64_t tsdbSkipOffset(TsdbQueryHandleT queryHandle) {
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*)queryHandle;
if (pQueryHandle) {
return pQueryHandle->srows;
}
return 0;
}
\ No newline at end of file
......@@ -58,6 +58,13 @@ static FORCE_INLINE void taosEncryptPass(uint8_t *inBuf, size_t inLen, char *tar
memcpy(target, context.digest, TSDB_KEY_LEN);
}
//
// TSKEY util
//
// if time area(s1,e1) intersect with time area(s2,e2) then return true else return false
bool timeIntersect(TSKEY s1, TSKEY e1, TSKEY s2, TSKEY e2);
#ifdef __cplusplus
}
#endif
......
......@@ -549,3 +549,16 @@ FORCE_INLINE double taos_align_get_double(const char* pBuf) {
memcpy(&dv, pBuf, sizeof(dv)); // in ARM, return *((const double*)(pBuf)) may cause problem
return dv;
}
//
// TSKEY util
//
// if time area(s1,e1) intersect with time area(s2,e2) then return true else return false
bool timeIntersect(TSKEY s1, TSKEY e1, TSKEY s2, TSKEY e2) {
// s1,e1 and s2,e2 have 7 scenarios, 5 is intersection, 2 is no intersection, so we pick up 2.
if(e2 < s1 || s2 > e1)
return false;
else
return true;
}
\ No newline at end of file
###################################################################
# 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<shenglian zhou>: [TS-2016]fix select * from (select * from empty_stable)
'''
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 td12229")
tdSql.execute("create database if not exists td12229")
tdSql.execute('use td12229')
tdSql.execute('create stable st(ts timestamp , value int ) tags (ind int)')
tdSql.execute('insert into tb1 using st tags(1) values(now ,1)')
tdSql.execute('insert into tb1 using st tags(1) values(now+1s ,2)')
tdSql.execute('insert into tb1 using st tags(1) values(now+2s ,3)')
tdSql.execute('create stable ste(ts timestamp , value int ) tags (ind int)')
tdSql.query('select * from st')
tdSql.checkRows(3)
tdSql.query('select * from (select * from ste)')
tdSql.checkRows(0)
tdSql.query('select * from st union all select * from ste')
tdSql.checkRows(3)
tdSql.query('select * from ste union all select * from st')
tdSql.checkRows(3)
tdSql.query('select elapsed(ts) from ste group by tbname union all select elapsed(ts) from st group by tbname;')
tdSql.checkRows(1)
tdSql.query('select elapsed(ts) from st group by tbname union all select elapsed(ts) from ste group by tbname;')
tdSql.checkRows(1)
tdSql.execute('drop database td12229')
def stop(self):
tdSql.close()
tdLog.success("%s successfully executed" % __file__)
tdCases.addWindows(__file__, TDTestCase())
tdCases.addLinux(__file__, TDTestCase())
......@@ -19,12 +19,14 @@ cd ../../
WKC=`pwd`
cd ${WKC}/src/connector/C#
dotnet test
dotnet run --project src/test/Cases/Cases.csproj
#dotnet run --project src/test/Cases/Cases.csproj
cd ${WKC}/tests/examples/C#
dotnet run --project C#checker/C#checker.csproj
dotnet run --project TDengineTest/TDengineTest.csproj
dotnet run --project schemaless/schemaless.csproj
dotnet run --project jsonTag/jsonTag.csproj
dotnet run --project stmt/stmt.csproj
cd ${WKC}/tests/examples/C#/taosdemo
dotnet build -c Release
......
python3 ./test.py -f 2-query/ts_hidden_column.py
python3 ./test.py -f 2-query/union-order.py
python3 ./test.py -f 2-query/session_two_stage.py
python3 ./test.py -f 2-query/ts_2016.py
......@@ -11,3 +11,5 @@ stmt/bin/
stmt/obj/
taosdemo/bin/
taosdemo/obj/
jsonTag/bin/
jsonTag/obj/
using System;
using Test.UtilsTools;
using Utils;
namespace Cases
{
public class JsonTagTest
class Program
{
static void Main(string[] args)
{
IntPtr conn = IntPtr.Zero;
Console.WriteLine("===================JsonTagTest====================");
conn = conn = UtilsTools.TDConnection("127.0.0.1", "root", "taosdata", "", 0);
UtilsTools.ExecuteUpdate(conn, "create database if not exists csharp_sample keep 3650");
UtilsTools.ExecuteUpdate(conn, "use csharp");
JsonTagSample jsonTagSample = new JsonTagSample();
jsonTagSample.Test(conn);
}
}
public class JsonTagSample
{
public void Test(IntPtr conn)
{
......
......@@ -3,9 +3,9 @@ using TDengineDriver;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
namespace Test.UtilsTools
namespace Utils
{
public class UtilsTools
public class UtilsTools
{
static string configDir = "/etc/taos";//"C:/TDengine/cfg";
......@@ -189,103 +189,6 @@ namespace Test.UtilsTools
TDengine.FreeResult(res); Console.WriteLine("");
}
public static List<List<string>> GetResultSet(IntPtr res)
{
List<List<string>> result = new List<List<string>>();
List<string> colName = new List<string>();
List<string> dataRaw = new List<string>();
long queryRows = 0;
if (!IsValidResult(res))
{
ExitProgram();
}
int fieldCount = TDengine.FieldCount(res);
List<TDengineMeta> metas = TDengine.FetchFields(res);
for (int j = 0; j < metas.Count; j++)
{
TDengineMeta meta = (TDengineMeta)metas[j];
colName.Add(meta.name);
}
result.Add(colName);
IntPtr rowdata;
while ((rowdata = TDengine.FetchRows(res)) != IntPtr.Zero)
{
queryRows++;
IntPtr colLengthPtr = TDengine.FetchLengths(res);
int[] colLengthArr = new int[fieldCount];
Marshal.Copy(colLengthPtr, colLengthArr, 0, fieldCount);
for (int fields = 0; fields < fieldCount; ++fields)
{
TDengineMeta meta = metas[fields];
int offset = IntPtr.Size * fields;
IntPtr data = Marshal.ReadIntPtr(rowdata, offset);
if (data == IntPtr.Zero)
{
dataRaw.Add("NULL");
continue;
}
switch ((TDengineDataType)meta.type)
{
case TDengineDataType.TSDB_DATA_TYPE_BOOL:
bool v1 = Marshal.ReadByte(data) == 0 ? false : true;
dataRaw.Add(v1.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_TINYINT:
byte v2 = Marshal.ReadByte(data);
dataRaw.Add(v2.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_SMALLINT:
short v3 = Marshal.ReadInt16(data);
dataRaw.Add(v3.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_INT:
int v4 = Marshal.ReadInt32(data);
dataRaw.Add(v4.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_BIGINT:
long v5 = Marshal.ReadInt64(data);
dataRaw.Add(v5.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_FLOAT:
float v6 = (float)Marshal.PtrToStructure(data, typeof(float));
dataRaw.Add(v6.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_DOUBLE:
double v7 = (double)Marshal.PtrToStructure(data, typeof(double));
dataRaw.Add(v7.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_BINARY:
string v8 = Marshal.PtrToStringAnsi(data, colLengthArr[fields]);
dataRaw.Add(v8);
break;
case TDengineDataType.TSDB_DATA_TYPE_TIMESTAMP:
long v9 = Marshal.ReadInt64(data);
dataRaw.Add(v9.ToString());
break;
case TDengineDataType.TSDB_DATA_TYPE_NCHAR:
string v10 = Marshal.PtrToStringAnsi(data, colLengthArr[fields]);
dataRaw.Add(v10);
break;
}
}
}
result.Add(dataRaw);
if (TDengine.ErrorNo(res) != 0)
{
Console.Write("Query is not complete, Error {0:G}", TDengine.ErrorNo(res), TDengine.Error(res));
}
TDengine.FreeResult(res); Console.WriteLine("");
return result;
}
public static bool IsValidResult(IntPtr res)
{
if ((res == IntPtr.Zero) || (TDengine.ErrorNo(res) != 0))
......@@ -314,27 +217,10 @@ namespace Test.UtilsTools
}
}
}
public static List<TDengineMeta> getField(IntPtr res)
{
List<TDengineMeta> metas = TDengine.FetchFields(res);
return metas;
}
public static void AssertEqual(string expectVal, string actualVal)
{
if (expectVal == actualVal)
{
Console.WriteLine("{0}=={1} pass", expectVal, actualVal);
}
else
{
Console.WriteLine("{0}=={1} failed", expectVal, actualVal);
ExitProgram();
}
}
public static void ExitProgram()
{
TDengine.Cleanup();
System.Environment.Exit(0);
}
}
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\TDengineDriver\TDengineDriver.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<NoWarn>CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>..\doc\FunctionTest.XML</DocumentationFile>
</PropertyGroup>
</Project>
<PackageReference Include="TDengine.Connector" Version="1.0.3" />
</ItemGroup>
</Project>
......@@ -53,7 +53,7 @@
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.0</version>
<version>2.17.1</version>
</dependency>
<!-- proxool -->
<dependency>
......
......@@ -88,7 +88,7 @@
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.0</version>
<version>2.17.1</version>
</dependency>
<!-- junit -->
<dependency>
......
from loguru import logger
import time
import os
import json
class HttpPerfCompard:
def __init__(self):
self.hostname = "vm85"
self.taosc_port = 6030
self.http_port = 6041
self.database = "test"
self.query_times = 1
self.concurrent = 1
self.column_count = 10
self.tag_count = 10
self.perfMonitorBin = '/home/ubuntu/perfMonitor'
self.taosBenchmarkBin = '/usr/local/bin/taosBenchmark'
self.sleep_time = 20
self.current_time = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(time.time()))
self.current_dir = os.path.dirname(os.path.realpath(__file__))
self.log_file = os.path.join(self.current_dir, f'./performance.log')
logger.add(self.log_file)
logger.info(f'init env success, log will be export to {self.log_file}')
self.sql_list = ['select last_row(*) from test.stb;',
'select * from test.stb limit 100000;',
'select count(*) from test.stb interval (1d);',
'select avg(c3), max(c4), min(c5) from test.stb interval (1d);',
'select count(*) from test.stb where t1 = "shanghai" interval (1h);',
'select avg(c3), max(c4), min(c5) from test.stb where t1 = "shanghai" interval (1d);',
'select avg(c3), max(c4), min(c5) from test.stb where ts > "2021-01-01 00:00:00" and ts < "2021-01-31 00:00:00" interval (1d);'
'select last(*) from test.stb;'
]
# self.sql_list = ['select * from test.stb limit 100000;']
def initLog(self):
self.exec_local_cmd(f'echo "" > {self.log_file}')
def exec_local_cmd(self,shell_cmd):
result = os.popen(shell_cmd).read().strip()
return result
def genQueryJsonFile(self, query_sql):
json_file = os.path.join(self.current_dir, f'./query.json')
jdict = {
"filetype": "query",
"cfgdir": "/etc/taos",
"host": self.hostname,
"port": self.taosc_port,
"user": "root",
"password": "taosdata",
"confirm_parameter_prompt": "no",
"databases": self.database,
"query_times": self.query_times,
"query_mode": "restful",
"specified_table_query": {
"concurrent": self.concurrent,
"sqls": [
{
"sql": query_sql,
"result": "./query_res0.txt"
}
]
}
}
with open(json_file, "w", encoding="utf-8") as f_w:
f_w.write(json.dumps(jdict))
def genInsertJsonFile(self, thread_count, table_count, row_count, batch_size):
json_file = os.path.join(self.current_dir, f'./insert.json')
jdict = {
"filetype": "insert",
"cfgdir": "/etc/taos",
"host": self.hostname,
"rest_host": self.hostname,
"port": self.taosc_port,
"rest_port": self.http_port,
"user": "root",
"password": "taosdata",
"thread_count": thread_count,
"thread_count_create_tbl": 1,
"result_file": self.log_file,
"databases": [{
"dbinfo": {
"name": self.database,
"drop": "yes"
},
"super_tables": [{
"name": "stb",
"childtable_count": table_count,
"childtable_prefix": "stb_",
"batch_create_tbl_num": 1,
"insert_mode": "rand",
"insert_iface": "rest",
"insert_rows": row_count,
"insert_interval": 0,
"batch_rows": batch_size,
"max_sql_len": 1048576,
"timestamp_step": 3000,
"start_timestamp": "2021-01-01 00:00:00.000",
"tags_file": "",
"partical_col_num": 0,
"columns": [{"type": "INT", "count": self.column_count}],
"tags": [{"type": "BINARY", "len": 16, "count": self.tag_count}]
}]
}]
}
with open(json_file, "w", encoding="utf-8") as f_w:
f_w.write(json.dumps(jdict))
def runTest(self):
self.initLog()
self.genInsertJsonFile(32, 100, 100000, 1)
logger.info('result of insert_perf with 32 threads and 1 batch_size:')
self.exec_local_cmd(f'{self.perfMonitorBin} -f insert.json')
time.sleep(self.sleep_time)
self.genInsertJsonFile(32, 500, 1000000, 1000)
logger.info('result of insert_perf with 32 threads and 1000 batch_size:')
self.exec_local_cmd(f'{self.perfMonitorBin} -f insert.json')
time.sleep(self.sleep_time)
for query_sql in self.sql_list:
self.genQueryJsonFile(query_sql)
self.exec_local_cmd(f'{self.taosBenchmarkBin} -f query.json > tmp.log')
res = self.exec_local_cmd('grep -Eo \'\<Spent.+s\>\' tmp.log |grep -v \'total queries\' |awk \'{sum+=$2}END{print "Average=",sum/NR,"s"}\'')
logger.info(query_sql)
logger.info(res)
time.sleep(self.sleep_time)
if __name__ == '__main__':
runPerf = HttpPerfCompard()
runPerf.runTest()
此差异已折叠。
......@@ -143,7 +143,7 @@ python3 ./test.py -f stream/stream1.py
python3 ./test.py -f stream/stream2.py
#python3 ./test.py -f stream/parser.py
python3 ./test.py -f stream/history.py
python3 ./test.py -f stream/sys.py
#python3 ./test.py -f stream/sys.py
python3 ./test.py -f stream/table_1.py
python3 ./test.py -f stream/table_n.py
python3 ./test.py -f stream/showStreamExecTimeisNull.py
......
......@@ -229,7 +229,8 @@ python3 test.py -f tools/taosdemoAllTest/taosdemoTestInsertAllType.py
python3 test.py -f tools/taosdemoAllTest/taosdemoTestInsertShell.py
#query
python3 test.py -f query/distinctOneColTb.py
python3 ./test.py -f query/queryBase.py
python3 ./test.py -f query/distinctOneColTb.py
python3 ./test.py -f query/filter.py
python3 ./test.py -f query/filterCombo.py
python3 ./test.py -f query/queryNormal.py
......@@ -286,6 +287,7 @@ python3 ./test.py -f query/queryCnameDisplay.py
python3 test.py -f query/nestedQuery/queryWithSpread.py
python3 ./test.py -f query/bug6586.py
# python3 ./test.py -f query/bug5903.py
python3 ./test.py -f query/queryLimit.py
#stream
python3 ./test.py -f stream/metric_1.py
......
......@@ -345,7 +345,9 @@ class ElapsedCase:
tdSql.error("select elapsed(*) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
tdSql.error("select elapsed(ts, '1s') from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
tdSql.error("select elapsed(ts, i) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
#tdSql.error("select elapsed(ts, now) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
tdSql.error("select elapsed(ts, now) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
tdSql.error("select elapsed(ts, now-7d+2h-3m+2s) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
tdSql.error("select elapsed(ts, 7d+2h+now+3m+2s) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
tdSql.error("select elapsed(ts, ts) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
tdSql.error("select elapsed(ts + 1) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
tdSql.error("select elapsed(ts, 1b) from t1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00'")
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册