C/C++ Connector

C/C++ 开发人员可以使用 TDengine 的客户端驱动,即 C/C++连接器 (以下都用 TDengine 客户端驱动表示),开发自己的应用来连接 TDengine 集群完成数据存储、查询以及其他功能。TDengine 客户端驱动的 API 类似于 MySQL 的 C API。应用程序使用时,需要包含 TDengine 头文件 taos.h,里面列出了提供的 API 的函数原型;应用程序还要链接到所在平台上对应的动态库。

  1. #include <taos.h>

TDengine 服务端或客户端安装后,taos.h 位于:

  • Linux:/usr/local/taos/include
  • Windows:C:\TDengine\include

TDengine 客户端驱动的动态库位于:

  • Linux: /usr/local/taos/driver/libtaos.so
  • Windows: C:\TDengine\taos.dll

支持的平台

请参考支持的平台列表

支持的版本

TDengine 客户端驱动的版本号与 TDengine 服务端的版本号是一一对应的强对应关系,建议使用与 TDengine 服务端完全相同的客户端驱动。虽然低版本的客户端驱动在前三段版本号一致(即仅第四段版本号不同)的情况下也能够与高版本的服务端相兼容,但这并非推荐用法。强烈不建议使用高版本的客户端驱动访问低版本的服务端。

安装步骤

TDengine 客户端驱动的安装请参考 安装指南

建立连接

使用客户端驱动访问 TDengine 集群的基本过程为:建立连接、查询和写入、关闭连接、清除资源。

下面为建立连接的示例代码,其中省略了查询和写入部分,展示了如何建立连接、关闭连接以及清除资源。

  1. TAOS *taos = taos_connect("localhost:6030", "root", "taosdata", NULL, 0);
  2. if (taos == NULL) {
  3. printf("failed to connect to server, reason:%s\n", "null taos" /*taos_errstr(taos)*/);
  4. exit(1);
  5. }
  6. /* put your code here for read and write */
  7. taos_close(taos);
  8. taos_cleanup();

在上面的示例代码中, taos_connect() 建立到客户端程序所在主机的 6030 端口的连接,taos_close()关闭当前连接,taos_cleanup()清除客户端驱动所申请和使用的资源。

C/C++ - 图1note
  • 如未特别说明,当 API 的返回值是整数时,0 代表成功,其它是代表失败原因的错误码,当返回值是指针时, NULL 表示失败。
  • 所有的错误码以及对应的原因描述在 taoserror.h 文件中。

示例程序

本节展示了使用客户端驱动访问 TDengine 集群的常见访问方式的示例代码。

同步查询示例

同步查询

  1. /*
  2. * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
  3. *
  4. * This program is free software: you can use, redistribute, and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3
  6. * or later ("AGPL"), as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE.
  11. *
  12. * You should have received a copy of the GNU Affero General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. // TAOS standard API example. The same syntax as MySQL, but only a subset
  16. // to compile: gcc -o demo demo.c -ltaos
  17. #include <inttypes.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <taos.h> // TAOS header file
  22. static void queryDB(TAOS *taos, char *command) {
  23. int i;
  24. TAOS_RES *pSql = NULL;
  25. int32_t code = -1;
  26. for (i = 0; i < 5; i++) {
  27. if (NULL != pSql) {
  28. taos_free_result(pSql);
  29. pSql = NULL;
  30. }
  31. pSql = taos_query(taos, command);
  32. code = taos_errno(pSql);
  33. if (0 == code) {
  34. break;
  35. }
  36. }
  37. if (code != 0) {
  38. fprintf(stderr, "Failed to run %s, reason: %s\n", command, taos_errstr(pSql));
  39. taos_free_result(pSql);
  40. taos_close(taos);
  41. exit(EXIT_FAILURE);
  42. }
  43. taos_free_result(pSql);
  44. }
  45. void Test(TAOS *taos, char *qstr, int i);
  46. int main(int argc, char *argv[]) {
  47. char qstr[1024];
  48. // connect to server
  49. if (argc < 2) {
  50. printf("please input server-ip \n");
  51. return 0;
  52. }
  53. TAOS *taos = taos_connect(argv[1], "root", "taosdata", NULL, 0);
  54. if (taos == NULL) {
  55. printf("failed to connect to server, reason:%s\n", "null taos" /*taos_errstr(taos)*/);
  56. exit(1);
  57. }
  58. for (int i = 0; i < 100; i++) {
  59. Test(taos, qstr, i);
  60. }
  61. taos_close(taos);
  62. taos_cleanup();
  63. }
  64. void Test(TAOS *taos, char *qstr, int index) {
  65. printf("==================test at %d\n================================", index);
  66. queryDB(taos, "drop database if exists demo");
  67. queryDB(taos, "create database demo");
  68. TAOS_RES *result;
  69. queryDB(taos, "use demo");
  70. queryDB(taos,
  71. "create table m1 (ts timestamp, ti tinyint, si smallint, i int, bi bigint, f float, d double, b binary(10))");
  72. printf("success to create table\n");
  73. int i = 0;
  74. for (i = 0; i < 10; ++i) {
  75. sprintf(qstr, "insert into m1 values (%" PRId64 ", %d, %d, %d, %d, %f, %lf, '%s')",
  76. (uint64_t)(1546300800000 + i * 1000), i, i, i, i * 10000000, i * 1.0, i * 2.0, "hello");
  77. printf("qstr: %s\n", qstr);
  78. // note: how do you wanna do if taos_query returns non-NULL
  79. // if (taos_query(taos, qstr)) {
  80. // printf("insert row: %i, reason:%s\n", i, taos_errstr(taos));
  81. // }
  82. TAOS_RES *result1 = taos_query(taos, qstr);
  83. if (result1 == NULL || taos_errno(result1) != 0) {
  84. printf("failed to insert row, reason:%s\n", taos_errstr(result1));
  85. taos_free_result(result1);
  86. exit(1);
  87. } else {
  88. printf("insert row: %i\n", i);
  89. }
  90. taos_free_result(result1);
  91. }
  92. printf("success to insert rows, total %d rows\n", i);
  93. // query the records
  94. sprintf(qstr, "SELECT * FROM m1");
  95. result = taos_query(taos, qstr);
  96. if (result == NULL || taos_errno(result) != 0) {
  97. printf("failed to select, reason:%s\n", taos_errstr(result));
  98. taos_free_result(result);
  99. exit(1);
  100. }
  101. TAOS_ROW row;
  102. int rows = 0;
  103. int num_fields = taos_field_count(result);
  104. TAOS_FIELD *fields = taos_fetch_fields(result);
  105. printf("num_fields = %d\n", num_fields);
  106. printf("select * from table, result:\n");
  107. // fetch the records row by row
  108. while ((row = taos_fetch_row(result))) {
  109. char temp[1024] = {0};
  110. rows++;
  111. taos_print_row(temp, row, fields, num_fields);
  112. printf("%s\n", temp);
  113. }
  114. taos_free_result(result);
  115. printf("====demo end====\n\n");
  116. }

查看源码

异步查询示例

异步查询

  1. /*
  2. * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
  3. *
  4. * This program is free software: you can use, redistribute, and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3
  6. * or later ("AGPL"), as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE.
  11. *
  12. * You should have received a copy of the GNU Affero General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. // TAOS asynchronous API example
  16. // this example opens multiple tables, insert/retrieve multiple tables
  17. // it is used by TAOS internally for one performance testing
  18. // to compiple: gcc -o asyncdemo asyncdemo.c -ltaos
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/time.h>
  23. #include <unistd.h>
  24. #include <taos.h>
  25. int points = 5;
  26. int numOfTables = 3;
  27. int tablesInsertProcessed = 0;
  28. int tablesSelectProcessed = 0;
  29. int64_t st, et;
  30. typedef struct {
  31. int id;
  32. TAOS * taos;
  33. char name[16];
  34. time_t timeStamp;
  35. int value;
  36. int rowsInserted;
  37. int rowsTried;
  38. int rowsRetrieved;
  39. } STable;
  40. void taos_insert_call_back(void *param, TAOS_RES *tres, int code);
  41. void taos_select_call_back(void *param, TAOS_RES *tres, int code);
  42. void taos_error(TAOS *taos);
  43. static void queryDB(TAOS *taos, char *command) {
  44. int i;
  45. TAOS_RES *pSql = NULL;
  46. int32_t code = -1;
  47. for (i = 0; i < 5; i++) {
  48. if (NULL != pSql) {
  49. taos_free_result(pSql);
  50. pSql = NULL;
  51. }
  52. pSql = taos_query(taos, command);
  53. code = taos_errno(pSql);
  54. if (0 == code) {
  55. break;
  56. }
  57. }
  58. if (code != 0) {
  59. fprintf(stderr, "Failed to run %s, reason: %s\n", command, taos_errstr(pSql));
  60. taos_free_result(pSql);
  61. taos_close(taos);
  62. taos_cleanup();
  63. exit(EXIT_FAILURE);
  64. }
  65. taos_free_result(pSql);
  66. }
  67. int main(int argc, char *argv[]) {
  68. TAOS * taos;
  69. struct timeval systemTime;
  70. int i;
  71. char sql[1024] = {0};
  72. char prefix[20] = {0};
  73. char db[128] = {0};
  74. STable * tableList;
  75. if (argc != 5) {
  76. printf("usage: %s server-ip dbname rowsPerTable numOfTables\n", argv[0]);
  77. exit(0);
  78. }
  79. // a simple way to parse input parameters
  80. if (argc >= 3) strcpy(db, argv[2]);
  81. if (argc >= 4) points = atoi(argv[3]);
  82. if (argc >= 5) numOfTables = atoi(argv[4]);
  83. size_t size = sizeof(STable) * (size_t)numOfTables;
  84. tableList = (STable *)malloc(size);
  85. memset(tableList, 0, size);
  86. taos = taos_connect(argv[1], "root", "taosdata", NULL, 0);
  87. if (taos == NULL) taos_error(taos);
  88. printf("success to connect to server\n");
  89. sprintf(sql, "drop database if exists %s", db);
  90. queryDB(taos, sql);
  91. sprintf(sql, "create database %s", db);
  92. queryDB(taos, sql);
  93. sprintf(sql, "use %s", db);
  94. queryDB(taos, sql);
  95. strcpy(prefix, "asytbl_");
  96. for (i = 0; i < numOfTables; ++i) {
  97. tableList[i].id = i;
  98. tableList[i].taos = taos;
  99. sprintf(tableList[i].name, "%s%d", prefix, i);
  100. sprintf(sql, "create table %s%d (ts timestamp, volume bigint)", prefix, i);
  101. queryDB(taos, sql);
  102. }
  103. gettimeofday(&systemTime, NULL);
  104. for (i = 0; i < numOfTables; ++i)
  105. tableList[i].timeStamp = (time_t)(systemTime.tv_sec) * 1000 + systemTime.tv_usec / 1000;
  106. printf("success to create tables, press any key to insert\n");
  107. getchar();
  108. printf("start to insert...\n");
  109. gettimeofday(&systemTime, NULL);
  110. st = systemTime.tv_sec * 1000000 + systemTime.tv_usec;
  111. tablesInsertProcessed = 0;
  112. tablesSelectProcessed = 0;
  113. for (i = 0; i < numOfTables; ++i) {
  114. // insert records in asynchronous API
  115. sprintf(sql, "insert into %s values(%ld, 0)", tableList[i].name, 1546300800000 + i);
  116. taos_query_a(taos, sql, taos_insert_call_back, (void *)(tableList + i));
  117. }
  118. printf("once insert finished, presse any key to query\n");
  119. getchar();
  120. while (1) {
  121. if (tablesInsertProcessed < numOfTables) {
  122. printf("wait for process finished\n");
  123. sleep(1);
  124. continue;
  125. }
  126. break;
  127. }
  128. printf("start to query...\n");
  129. gettimeofday(&systemTime, NULL);
  130. st = systemTime.tv_sec * 1000000 + systemTime.tv_usec;
  131. for (i = 0; i < numOfTables; ++i) {
  132. // select records in asynchronous API
  133. sprintf(sql, "select * from %s", tableList[i].name);
  134. taos_query_a(taos, sql, taos_select_call_back, (void *)(tableList + i));
  135. }
  136. printf("\nonce finished, press any key to exit\n");
  137. getchar();
  138. while (1) {
  139. if (tablesSelectProcessed < numOfTables) {
  140. printf("wait for process finished\n");
  141. sleep(1);
  142. continue;
  143. }
  144. break;
  145. }
  146. for (i = 0; i < numOfTables; ++i) {
  147. printf("%s inserted:%d retrieved:%d\n", tableList[i].name, tableList[i].rowsInserted, tableList[i].rowsRetrieved);
  148. }
  149. taos_close(taos);
  150. free(tableList);
  151. printf("==== async demo end====\n");
  152. printf("\n");
  153. return 0;
  154. }
  155. void taos_error(TAOS *con) {
  156. fprintf(stderr, "TDengine error: %s\n", taos_errstr(con));
  157. taos_close(con);
  158. taos_cleanup();
  159. exit(1);
  160. }
  161. void taos_insert_call_back(void *param, TAOS_RES *tres, int code) {
  162. STable * pTable = (STable *)param;
  163. struct timeval systemTime;
  164. char sql[128];
  165. pTable->rowsTried++;
  166. if (code < 0) {
  167. printf("%s insert failed, code:%d, rows:%d\n", pTable->name, code, pTable->rowsTried);
  168. } else if (code == 0) {
  169. printf("%s not inserted\n", pTable->name);
  170. } else {
  171. pTable->rowsInserted++;
  172. }
  173. if (pTable->rowsTried < points) {
  174. // for this demo, insert another record
  175. sprintf(sql, "insert into %s values(%ld, %d)", pTable->name, 1546300800000 + pTable->rowsTried * 1000,
  176. pTable->rowsTried);
  177. taos_query_a(pTable->taos, sql, taos_insert_call_back, (void *)pTable);
  178. } else {
  179. printf("%d rows data are inserted into %s\n", points, pTable->name);
  180. tablesInsertProcessed++;
  181. if (tablesInsertProcessed >= numOfTables) {
  182. gettimeofday(&systemTime, NULL);
  183. et = systemTime.tv_sec * 1000000 + systemTime.tv_usec;
  184. printf("%lld mseconds to insert %d data points\n", (et - st) / 1000, points * numOfTables);
  185. }
  186. }
  187. taos_free_result(tres);
  188. }
  189. void taos_retrieve_call_back(void *param, TAOS_RES *tres, int numOfRows) {
  190. STable * pTable = (STable *)param;
  191. struct timeval systemTime;
  192. if (numOfRows > 0) {
  193. for (int i = 0; i < numOfRows; ++i) {
  194. // synchronous API to retrieve a row from batch of records
  195. /*TAOS_ROW row = */ (void)taos_fetch_row(tres);
  196. // process row
  197. }
  198. pTable->rowsRetrieved += numOfRows;
  199. // retrieve next batch of rows
  200. taos_fetch_rows_a(tres, taos_retrieve_call_back, pTable);
  201. } else {
  202. if (numOfRows < 0) printf("%s retrieve failed, code:%d\n", pTable->name, numOfRows);
  203. // taos_free_result(tres);
  204. printf("%d rows data retrieved from %s\n", pTable->rowsRetrieved, pTable->name);
  205. tablesSelectProcessed++;
  206. if (tablesSelectProcessed >= numOfTables) {
  207. gettimeofday(&systemTime, NULL);
  208. et = systemTime.tv_sec * 1000000 + systemTime.tv_usec;
  209. printf("%lld mseconds to query %d data rows\n", (et - st) / 1000, points * numOfTables);
  210. }
  211. taos_free_result(tres);
  212. }
  213. }
  214. void taos_select_call_back(void *param, TAOS_RES *tres, int code) {
  215. STable *pTable = (STable *)param;
  216. if (code == 0 && tres) {
  217. // asynchronous API to fetch a batch of records
  218. taos_fetch_rows_a(tres, taos_retrieve_call_back, pTable);
  219. } else {
  220. printf("%s select failed, code:%d\n", pTable->name, code);
  221. taos_free_result(tres);
  222. taos_cleanup();
  223. exit(1);
  224. }
  225. }

查看源码

参数绑定示例

参数绑定

  1. // TAOS standard API example. The same syntax as MySQL, but only a subet
  2. // to compile: gcc -o prepare prepare.c -ltaos
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <taos.h>
  7. #include <unistd.h>
  8. void taosMsleep(int mseconds);
  9. void verify_prepare(TAOS* taos) {
  10. TAOS_RES* result = taos_query(taos, "drop database if exists test;");
  11. taos_free_result(result);
  12. usleep(100000);
  13. result = taos_query(taos, "create database test;");
  14. int code = taos_errno(result);
  15. if (code != 0) {
  16. printf("\033[31mfailed to create database, reason:%s\033[0m\n", taos_errstr(result));
  17. taos_free_result(result);
  18. exit(EXIT_FAILURE);
  19. }
  20. taos_free_result(result);
  21. usleep(100000);
  22. taos_select_db(taos, "test");
  23. // create table
  24. const char* sql =
  25. "create table m1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin "
  26. "binary(40), blob nchar(10), u1 tinyint unsigned, u2 smallint unsigned, u4 int unsigned, u8 bigint unsigned)";
  27. result = taos_query(taos, sql);
  28. code = taos_errno(result);
  29. if (code != 0) {
  30. printf("\033[31mfailed to create table, reason:%s\033[0m\n", taos_errstr(result));
  31. taos_free_result(result);
  32. exit(EXIT_FAILURE);
  33. }
  34. taos_free_result(result);
  35. // insert 10 records
  36. struct {
  37. int64_t ts;
  38. int8_t b;
  39. int8_t v1;
  40. int16_t v2;
  41. int32_t v4;
  42. int64_t v8;
  43. float f4;
  44. double f8;
  45. char bin[40];
  46. char blob[80];
  47. uint8_t u1;
  48. uint16_t u2;
  49. uint32_t u4;
  50. uint64_t u8;
  51. } v = {0};
  52. TAOS_STMT* stmt = taos_stmt_init(taos);
  53. TAOS_BIND params[14];
  54. params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP;
  55. params[0].buffer_length = sizeof(v.ts);
  56. params[0].buffer = &v.ts;
  57. params[0].length = &params[0].buffer_length;
  58. params[0].is_null = NULL;
  59. params[1].buffer_type = TSDB_DATA_TYPE_BOOL;
  60. params[1].buffer_length = sizeof(v.b);
  61. params[1].buffer = &v.b;
  62. params[1].length = &params[1].buffer_length;
  63. params[1].is_null = NULL;
  64. params[2].buffer_type = TSDB_DATA_TYPE_TINYINT;
  65. params[2].buffer_length = sizeof(v.v1);
  66. params[2].buffer = &v.v1;
  67. params[2].length = &params[2].buffer_length;
  68. params[2].is_null = NULL;
  69. params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  70. params[3].buffer_length = sizeof(v.v2);
  71. params[3].buffer = &v.v2;
  72. params[3].length = &params[3].buffer_length;
  73. params[3].is_null = NULL;
  74. params[4].buffer_type = TSDB_DATA_TYPE_INT;
  75. params[4].buffer_length = sizeof(v.v4);
  76. params[4].buffer = &v.v4;
  77. params[4].length = &params[4].buffer_length;
  78. params[4].is_null = NULL;
  79. params[5].buffer_type = TSDB_DATA_TYPE_BIGINT;
  80. params[5].buffer_length = sizeof(v.v8);
  81. params[5].buffer = &v.v8;
  82. params[5].length = &params[5].buffer_length;
  83. params[5].is_null = NULL;
  84. params[6].buffer_type = TSDB_DATA_TYPE_FLOAT;
  85. params[6].buffer_length = sizeof(v.f4);
  86. params[6].buffer = &v.f4;
  87. params[6].length = &params[6].buffer_length;
  88. params[6].is_null = NULL;
  89. params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE;
  90. params[7].buffer_length = sizeof(v.f8);
  91. params[7].buffer = &v.f8;
  92. params[7].length = &params[7].buffer_length;
  93. params[7].is_null = NULL;
  94. params[8].buffer_type = TSDB_DATA_TYPE_BINARY;
  95. params[8].buffer_length = sizeof(v.bin);
  96. params[8].buffer = v.bin;
  97. params[8].length = &params[8].buffer_length;
  98. params[8].is_null = NULL;
  99. strcpy(v.blob, "一二三四五六七八九十");
  100. params[9].buffer_type = TSDB_DATA_TYPE_NCHAR;
  101. params[9].buffer_length = strlen(v.blob);
  102. params[9].buffer = v.blob;
  103. params[9].length = &params[9].buffer_length;
  104. params[9].is_null = NULL;
  105. params[10].buffer_type = TSDB_DATA_TYPE_UTINYINT;
  106. params[10].buffer_length = sizeof(v.u1);
  107. params[10].buffer = &v.u1;
  108. params[10].length = &params[10].buffer_length;
  109. params[10].is_null = NULL;
  110. params[11].buffer_type = TSDB_DATA_TYPE_USMALLINT;
  111. params[11].buffer_length = sizeof(v.u2);
  112. params[11].buffer = &v.u2;
  113. params[11].length = &params[11].buffer_length;
  114. params[11].is_null = NULL;
  115. params[12].buffer_type = TSDB_DATA_TYPE_UINT;
  116. params[12].buffer_length = sizeof(v.u4);
  117. params[12].buffer = &v.u4;
  118. params[12].length = &params[12].buffer_length;
  119. params[12].is_null = NULL;
  120. params[13].buffer_type = TSDB_DATA_TYPE_UBIGINT;
  121. params[13].buffer_length = sizeof(v.u8);
  122. params[13].buffer = &v.u8;
  123. params[13].length = &params[13].buffer_length;
  124. params[13].is_null = NULL;
  125. int is_null = 1;
  126. sql = "insert into m1 values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
  127. code = taos_stmt_prepare(stmt, sql, 0);
  128. if (code != 0) {
  129. printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt));
  130. taos_stmt_close(stmt);
  131. exit(EXIT_FAILURE);
  132. }
  133. v.ts = 1591060628000;
  134. for (int i = 0; i < 10; ++i) {
  135. v.ts += 1;
  136. for (int j = 1; j < 10; ++j) {
  137. params[j].is_null = ((i == j) ? &is_null : 0);
  138. }
  139. v.b = (int8_t)i % 2;
  140. v.v1 = (int8_t)i;
  141. v.v2 = (int16_t)(i * 2);
  142. v.v4 = (int32_t)(i * 4);
  143. v.v8 = (int64_t)(i * 8);
  144. v.f4 = (float)(i * 40);
  145. v.f8 = (double)(i * 80);
  146. for (int j = 0; j < sizeof(v.bin); ++j) {
  147. v.bin[j] = (char)(i + '0');
  148. }
  149. v.u1 = (uint8_t)i;
  150. v.u2 = (uint16_t)(i * 2);
  151. v.u4 = (uint32_t)(i * 4);
  152. v.u8 = (uint64_t)(i * 8);
  153. taos_stmt_bind_param(stmt, params);
  154. taos_stmt_add_batch(stmt);
  155. }
  156. if (taos_stmt_execute(stmt) != 0) {
  157. printf("\033[31mfailed to execute insert statement.error:%s\033[0m\n", taos_stmt_errstr(stmt));
  158. taos_stmt_close(stmt);
  159. exit(EXIT_FAILURE);
  160. }
  161. int affectedRows = taos_stmt_affected_rows(stmt);
  162. printf("sucessfully inserted %d rows\n", affectedRows);
  163. taos_stmt_close(stmt);
  164. // query the records
  165. stmt = taos_stmt_init(taos);
  166. taos_stmt_prepare(stmt, "SELECT * FROM m1 WHERE v1 > ? AND v2 < ?", 0);
  167. v.v1 = 5;
  168. v.v2 = 15;
  169. taos_stmt_bind_param(stmt, params + 2);
  170. if (taos_stmt_execute(stmt) != 0) {
  171. printf("\033[31mfailed to execute select statement.error:%s\033[0m\n", taos_stmt_errstr(stmt));
  172. taos_stmt_close(stmt);
  173. exit(EXIT_FAILURE);
  174. }
  175. result = taos_stmt_use_result(stmt);
  176. TAOS_ROW row;
  177. int rows = 0;
  178. int num_fields = taos_num_fields(result);
  179. TAOS_FIELD* fields = taos_fetch_fields(result);
  180. // fetch the records row by row
  181. while ((row = taos_fetch_row(result))) {
  182. char temp[256] = {0};
  183. rows++;
  184. taos_print_row(temp, row, fields, num_fields);
  185. printf("%s\n", temp);
  186. }
  187. taos_free_result(result);
  188. taos_stmt_close(stmt);
  189. }
  190. void verify_prepare2(TAOS* taos) {
  191. TAOS_RES* result = taos_query(taos, "drop database if exists test;");
  192. taos_free_result(result);
  193. usleep(100000);
  194. result = taos_query(taos, "create database test;");
  195. int code = taos_errno(result);
  196. if (code != 0) {
  197. printf("\033[31mfailed to create database, reason:%s\033[0m\n", taos_errstr(result));
  198. taos_free_result(result);
  199. exit(EXIT_FAILURE);
  200. }
  201. taos_free_result(result);
  202. usleep(100000);
  203. taos_select_db(taos, "test");
  204. // create table
  205. const char* sql =
  206. "create table m1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin "
  207. "binary(40), blob nchar(10), u1 tinyint unsigned, u2 smallint unsigned, u4 int unsigned, u8 bigint unsigned)";
  208. result = taos_query(taos, sql);
  209. code = taos_errno(result);
  210. if (code != 0) {
  211. printf("\033[31mfailed to create table, reason:%s\033[0m\n", taos_errstr(result));
  212. taos_free_result(result);
  213. exit(EXIT_FAILURE);
  214. }
  215. taos_free_result(result);
  216. // insert 10 records
  217. struct {
  218. int64_t ts;
  219. int8_t b;
  220. int8_t v1;
  221. int16_t v2;
  222. int32_t v4;
  223. int64_t v8;
  224. float f4;
  225. double f8;
  226. char bin[40];
  227. char blob[80];
  228. uint8_t u1;
  229. uint16_t u2;
  230. uint32_t u4;
  231. uint64_t u8;
  232. } v = {0};
  233. TAOS_STMT* stmt = taos_stmt_init(taos);
  234. TAOS_BIND params[14];
  235. params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP;
  236. params[0].buffer_length = sizeof(v.ts);
  237. params[0].buffer = &v.ts;
  238. params[0].length = &params[0].buffer_length;
  239. params[0].is_null = NULL;
  240. params[1].buffer_type = TSDB_DATA_TYPE_BOOL;
  241. params[1].buffer_length = sizeof(v.b);
  242. params[1].buffer = &v.b;
  243. params[1].length = &params[1].buffer_length;
  244. params[1].is_null = NULL;
  245. params[2].buffer_type = TSDB_DATA_TYPE_TINYINT;
  246. params[2].buffer_length = sizeof(v.v1);
  247. params[2].buffer = &v.v1;
  248. params[2].length = &params[2].buffer_length;
  249. params[2].is_null = NULL;
  250. params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  251. params[3].buffer_length = sizeof(v.v2);
  252. params[3].buffer = &v.v2;
  253. params[3].length = &params[3].buffer_length;
  254. params[3].is_null = NULL;
  255. params[4].buffer_type = TSDB_DATA_TYPE_INT;
  256. params[4].buffer_length = sizeof(v.v4);
  257. params[4].buffer = &v.v4;
  258. params[4].length = &params[4].buffer_length;
  259. params[4].is_null = NULL;
  260. params[5].buffer_type = TSDB_DATA_TYPE_BIGINT;
  261. params[5].buffer_length = sizeof(v.v8);
  262. params[5].buffer = &v.v8;
  263. params[5].length = &params[5].buffer_length;
  264. params[5].is_null = NULL;
  265. params[6].buffer_type = TSDB_DATA_TYPE_FLOAT;
  266. params[6].buffer_length = sizeof(v.f4);
  267. params[6].buffer = &v.f4;
  268. params[6].length = &params[6].buffer_length;
  269. params[6].is_null = NULL;
  270. params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE;
  271. params[7].buffer_length = sizeof(v.f8);
  272. params[7].buffer = &v.f8;
  273. params[7].length = &params[7].buffer_length;
  274. params[7].is_null = NULL;
  275. params[8].buffer_type = TSDB_DATA_TYPE_BINARY;
  276. params[8].buffer_length = sizeof(v.bin);
  277. params[8].buffer = v.bin;
  278. params[8].length = &params[8].buffer_length;
  279. params[8].is_null = NULL;
  280. strcpy(v.blob, "一二三四五六七八九十");
  281. params[9].buffer_type = TSDB_DATA_TYPE_NCHAR;
  282. params[9].buffer_length = strlen(v.blob);
  283. params[9].buffer = v.blob;
  284. params[9].length = &params[9].buffer_length;
  285. params[9].is_null = NULL;
  286. params[10].buffer_type = TSDB_DATA_TYPE_UTINYINT;
  287. params[10].buffer_length = sizeof(v.u1);
  288. params[10].buffer = &v.u1;
  289. params[10].length = &params[10].buffer_length;
  290. params[10].is_null = NULL;
  291. params[11].buffer_type = TSDB_DATA_TYPE_USMALLINT;
  292. params[11].buffer_length = sizeof(v.u2);
  293. params[11].buffer = &v.u2;
  294. params[11].length = &params[11].buffer_length;
  295. params[11].is_null = NULL;
  296. params[12].buffer_type = TSDB_DATA_TYPE_UINT;
  297. params[12].buffer_length = sizeof(v.u4);
  298. params[12].buffer = &v.u4;
  299. params[12].length = &params[12].buffer_length;
  300. params[12].is_null = NULL;
  301. params[13].buffer_type = TSDB_DATA_TYPE_UBIGINT;
  302. params[13].buffer_length = sizeof(v.u8);
  303. params[13].buffer = &v.u8;
  304. params[13].length = &params[13].buffer_length;
  305. params[13].is_null = NULL;
  306. sql = "insert into ? values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
  307. code = taos_stmt_prepare(stmt, sql, 0);
  308. if (code != 0) {
  309. printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt));
  310. taos_stmt_close(stmt);
  311. exit(EXIT_FAILURE);
  312. }
  313. code = taos_stmt_set_tbname(stmt, "m1");
  314. if (code != 0) {
  315. printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt));
  316. taos_stmt_close(stmt);
  317. exit(EXIT_FAILURE);
  318. }
  319. int is_null = 1;
  320. v.ts = 1591060628000;
  321. for (int i = 0; i < 10; ++i) {
  322. v.ts += 1;
  323. for (int j = 1; j < 10; ++j) {
  324. params[j].is_null = ((i == j) ? &is_null : 0);
  325. }
  326. v.b = (int8_t)i % 2;
  327. v.v1 = (int8_t)i;
  328. v.v2 = (int16_t)(i * 2);
  329. v.v4 = (int32_t)(i * 4);
  330. v.v8 = (int64_t)(i * 8);
  331. v.f4 = (float)(i * 40);
  332. v.f8 = (double)(i * 80);
  333. for (int j = 0; j < sizeof(v.bin); ++j) {
  334. v.bin[j] = (char)(i + '0');
  335. }
  336. v.u1 = (uint8_t)i;
  337. v.u2 = (uint16_t)(i * 2);
  338. v.u4 = (uint32_t)(i * 4);
  339. v.u8 = (uint64_t)(i * 8);
  340. taos_stmt_bind_param(stmt, params);
  341. taos_stmt_add_batch(stmt);
  342. }
  343. if (taos_stmt_execute(stmt) != 0) {
  344. printf("\033[31mfailed to execute insert statement.error:%s\033[0m\n", taos_stmt_errstr(stmt));
  345. taos_stmt_close(stmt);
  346. exit(EXIT_FAILURE);
  347. }
  348. int affectedRows = taos_stmt_affected_rows(stmt);
  349. printf("sucessfully inserted %d rows\n", affectedRows);
  350. taos_stmt_close(stmt);
  351. // query the records
  352. stmt = taos_stmt_init(taos);
  353. taos_stmt_prepare(stmt, "SELECT * FROM m1 WHERE v1 > ? AND v2 < ?", 0);
  354. TAOS_BIND qparams[2];
  355. int8_t v1 = 5;
  356. int16_t v2 = 15;
  357. qparams[0].buffer_type = TSDB_DATA_TYPE_TINYINT;
  358. qparams[0].buffer_length = sizeof(v1);
  359. qparams[0].buffer = &v1;
  360. qparams[0].length = &qparams[0].buffer_length;
  361. qparams[0].is_null = NULL;
  362. qparams[1].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  363. qparams[1].buffer_length = sizeof(v2);
  364. qparams[1].buffer = &v2;
  365. qparams[1].length = &qparams[1].buffer_length;
  366. qparams[1].is_null = NULL;
  367. taos_stmt_bind_param(stmt, qparams);
  368. if (taos_stmt_execute(stmt) != 0) {
  369. printf("\033[31mfailed to execute select statement.error:%s\033[0m\n", taos_stmt_errstr(stmt));
  370. taos_stmt_close(stmt);
  371. exit(EXIT_FAILURE);
  372. }
  373. result = taos_stmt_use_result(stmt);
  374. TAOS_ROW row;
  375. int rows = 0;
  376. int num_fields = taos_num_fields(result);
  377. TAOS_FIELD* fields = taos_fetch_fields(result);
  378. // fetch the records row by row
  379. while ((row = taos_fetch_row(result))) {
  380. char temp[256] = {0};
  381. rows++;
  382. taos_print_row(temp, row, fields, num_fields);
  383. printf("%s\n", temp);
  384. }
  385. taos_free_result(result);
  386. taos_stmt_close(stmt);
  387. }
  388. void verify_prepare3(TAOS* taos) {
  389. TAOS_RES* result = taos_query(taos, "drop database if exists test;");
  390. taos_free_result(result);
  391. usleep(100000);
  392. result = taos_query(taos, "create database test;");
  393. int code = taos_errno(result);
  394. if (code != 0) {
  395. printf("\033[31mfailed to create database, reason:%s\033[0m\n", taos_errstr(result));
  396. taos_free_result(result);
  397. exit(EXIT_FAILURE);
  398. }
  399. taos_free_result(result);
  400. usleep(100000);
  401. taos_select_db(taos, "test");
  402. // create table
  403. const char* sql =
  404. "create stable st1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin "
  405. "binary(40), blob nchar(10), u1 tinyint unsigned, u2 smallint unsigned, u4 int unsigned, u8 bigint unsigned) "
  406. "tags "
  407. "(b_tag bool, v1_tag tinyint, v2_tag smallint, v4_tag int, v8_tag bigint, f4_tag float, f8_tag double, bin_tag "
  408. "binary(40), blob_tag nchar(10), u1_tag tinyint unsigned, u2_tag smallint unsigned, u4_tag int unsigned, u8_tag "
  409. "bigint "
  410. "unsigned)";
  411. result = taos_query(taos, sql);
  412. code = taos_errno(result);
  413. if (code != 0) {
  414. printf("\033[31mfailed to create table, reason:%s\033[0m\n", taos_errstr(result));
  415. taos_free_result(result);
  416. exit(EXIT_FAILURE);
  417. }
  418. taos_free_result(result);
  419. TAOS_BIND tags[13];
  420. struct {
  421. int8_t b;
  422. int8_t v1;
  423. int16_t v2;
  424. int32_t v4;
  425. int64_t v8;
  426. float f4;
  427. double f8;
  428. char bin[40];
  429. char blob[80];
  430. uint8_t u1;
  431. uint16_t u2;
  432. uint32_t u4;
  433. uint64_t u8;
  434. } id = {0};
  435. id.b = (int8_t)1;
  436. id.v1 = (int8_t)1;
  437. id.v2 = (int16_t)2;
  438. id.v4 = (int32_t)4;
  439. id.v8 = (int64_t)8;
  440. id.f4 = (float)40;
  441. id.f8 = (double)80;
  442. for (int j = 0; j < sizeof(id.bin); ++j) {
  443. id.bin[j] = (char)('1' + '0');
  444. }
  445. strcpy(id.blob, "一二三四五六七八九十");
  446. id.u1 = (uint8_t)1;
  447. id.u2 = (uint16_t)2;
  448. id.u4 = (uint32_t)4;
  449. id.u8 = (uint64_t)8;
  450. tags[0].buffer_type = TSDB_DATA_TYPE_BOOL;
  451. tags[0].buffer_length = sizeof(id.b);
  452. tags[0].buffer = &id.b;
  453. tags[0].length = &tags[0].buffer_length;
  454. tags[0].is_null = NULL;
  455. tags[1].buffer_type = TSDB_DATA_TYPE_TINYINT;
  456. tags[1].buffer_length = sizeof(id.v1);
  457. tags[1].buffer = &id.v1;
  458. tags[1].length = &tags[1].buffer_length;
  459. tags[1].is_null = NULL;
  460. tags[2].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  461. tags[2].buffer_length = sizeof(id.v2);
  462. tags[2].buffer = &id.v2;
  463. tags[2].length = &tags[2].buffer_length;
  464. tags[2].is_null = NULL;
  465. tags[3].buffer_type = TSDB_DATA_TYPE_INT;
  466. tags[3].buffer_length = sizeof(id.v4);
  467. tags[3].buffer = &id.v4;
  468. tags[3].length = &tags[3].buffer_length;
  469. tags[3].is_null = NULL;
  470. tags[4].buffer_type = TSDB_DATA_TYPE_BIGINT;
  471. tags[4].buffer_length = sizeof(id.v8);
  472. tags[4].buffer = &id.v8;
  473. tags[4].length = &tags[4].buffer_length;
  474. tags[4].is_null = NULL;
  475. tags[5].buffer_type = TSDB_DATA_TYPE_FLOAT;
  476. tags[5].buffer_length = sizeof(id.f4);
  477. tags[5].buffer = &id.f4;
  478. tags[5].length = &tags[5].buffer_length;
  479. tags[5].is_null = NULL;
  480. tags[6].buffer_type = TSDB_DATA_TYPE_DOUBLE;
  481. tags[6].buffer_length = sizeof(id.f8);
  482. tags[6].buffer = &id.f8;
  483. tags[6].length = &tags[6].buffer_length;
  484. tags[6].is_null = NULL;
  485. tags[7].buffer_type = TSDB_DATA_TYPE_BINARY;
  486. tags[7].buffer_length = sizeof(id.bin);
  487. tags[7].buffer = &id.bin;
  488. tags[7].length = &tags[7].buffer_length;
  489. tags[7].is_null = NULL;
  490. tags[8].buffer_type = TSDB_DATA_TYPE_NCHAR;
  491. tags[8].buffer_length = strlen(id.blob);
  492. tags[8].buffer = &id.blob;
  493. tags[8].length = &tags[8].buffer_length;
  494. tags[8].is_null = NULL;
  495. tags[9].buffer_type = TSDB_DATA_TYPE_UTINYINT;
  496. tags[9].buffer_length = sizeof(id.u1);
  497. tags[9].buffer = &id.u1;
  498. tags[9].length = &tags[9].buffer_length;
  499. tags[9].is_null = NULL;
  500. tags[10].buffer_type = TSDB_DATA_TYPE_USMALLINT;
  501. tags[10].buffer_length = sizeof(id.u2);
  502. tags[10].buffer = &id.u2;
  503. tags[10].length = &tags[10].buffer_length;
  504. tags[10].is_null = NULL;
  505. tags[11].buffer_type = TSDB_DATA_TYPE_UINT;
  506. tags[11].buffer_length = sizeof(id.u4);
  507. tags[11].buffer = &id.u4;
  508. tags[11].length = &tags[11].buffer_length;
  509. tags[11].is_null = NULL;
  510. tags[12].buffer_type = TSDB_DATA_TYPE_UBIGINT;
  511. tags[12].buffer_length = sizeof(id.u8);
  512. tags[12].buffer = &id.u8;
  513. tags[12].length = &tags[12].buffer_length;
  514. tags[12].is_null = NULL;
  515. // insert 10 records
  516. struct {
  517. int64_t ts[10];
  518. int8_t b[10];
  519. int8_t v1[10];
  520. int16_t v2[10];
  521. int32_t v4[10];
  522. int64_t v8[10];
  523. float f4[10];
  524. double f8[10];
  525. char bin[10][40];
  526. char blob[10][80];
  527. uint8_t u1[10];
  528. uint16_t u2[10];
  529. uint32_t u4[10];
  530. uint64_t u8[10];
  531. } v;
  532. int32_t* t8_len = malloc(sizeof(int32_t) * 10);
  533. int32_t* t16_len = malloc(sizeof(int32_t) * 10);
  534. int32_t* t32_len = malloc(sizeof(int32_t) * 10);
  535. int32_t* t64_len = malloc(sizeof(int32_t) * 10);
  536. int32_t* float_len = malloc(sizeof(int32_t) * 10);
  537. int32_t* double_len = malloc(sizeof(int32_t) * 10);
  538. int32_t* bin_len = malloc(sizeof(int32_t) * 10);
  539. int32_t* blob_len = malloc(sizeof(int32_t) * 10);
  540. int32_t* u8_len = malloc(sizeof(int32_t) * 10);
  541. int32_t* u16_len = malloc(sizeof(int32_t) * 10);
  542. int32_t* u32_len = malloc(sizeof(int32_t) * 10);
  543. int32_t* u64_len = malloc(sizeof(int32_t) * 10);
  544. TAOS_STMT* stmt = taos_stmt_init(taos);
  545. TAOS_MULTI_BIND params[14];
  546. char is_null[10] = {0};
  547. params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP;
  548. params[0].buffer_length = sizeof(v.ts[0]);
  549. params[0].buffer = v.ts;
  550. params[0].length = t64_len;
  551. params[0].is_null = is_null;
  552. params[0].num = 10;
  553. params[1].buffer_type = TSDB_DATA_TYPE_BOOL;
  554. params[1].buffer_length = sizeof(v.b[0]);
  555. params[1].buffer = v.b;
  556. params[1].length = t8_len;
  557. params[1].is_null = is_null;
  558. params[1].num = 10;
  559. params[2].buffer_type = TSDB_DATA_TYPE_TINYINT;
  560. params[2].buffer_length = sizeof(v.v1[0]);
  561. params[2].buffer = v.v1;
  562. params[2].length = t8_len;
  563. params[2].is_null = is_null;
  564. params[2].num = 10;
  565. params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  566. params[3].buffer_length = sizeof(v.v2[0]);
  567. params[3].buffer = v.v2;
  568. params[3].length = t16_len;
  569. params[3].is_null = is_null;
  570. params[3].num = 10;
  571. params[4].buffer_type = TSDB_DATA_TYPE_INT;
  572. params[4].buffer_length = sizeof(v.v4[0]);
  573. params[4].buffer = v.v4;
  574. params[4].length = t32_len;
  575. params[4].is_null = is_null;
  576. params[4].num = 10;
  577. params[5].buffer_type = TSDB_DATA_TYPE_BIGINT;
  578. params[5].buffer_length = sizeof(v.v8[0]);
  579. params[5].buffer = v.v8;
  580. params[5].length = t64_len;
  581. params[5].is_null = is_null;
  582. params[5].num = 10;
  583. params[6].buffer_type = TSDB_DATA_TYPE_FLOAT;
  584. params[6].buffer_length = sizeof(v.f4[0]);
  585. params[6].buffer = v.f4;
  586. params[6].length = float_len;
  587. params[6].is_null = is_null;
  588. params[6].num = 10;
  589. params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE;
  590. params[7].buffer_length = sizeof(v.f8[0]);
  591. params[7].buffer = v.f8;
  592. params[7].length = double_len;
  593. params[7].is_null = is_null;
  594. params[7].num = 10;
  595. params[8].buffer_type = TSDB_DATA_TYPE_BINARY;
  596. params[8].buffer_length = sizeof(v.bin[0]);
  597. params[8].buffer = v.bin;
  598. params[8].length = bin_len;
  599. params[8].is_null = is_null;
  600. params[8].num = 10;
  601. params[9].buffer_type = TSDB_DATA_TYPE_NCHAR;
  602. params[9].buffer_length = sizeof(v.blob[0]);
  603. params[9].buffer = v.blob;
  604. params[9].length = blob_len;
  605. params[9].is_null = is_null;
  606. params[9].num = 10;
  607. params[10].buffer_type = TSDB_DATA_TYPE_UTINYINT;
  608. params[10].buffer_length = sizeof(v.u1[0]);
  609. params[10].buffer = v.u1;
  610. params[10].length = u8_len;
  611. params[10].is_null = is_null;
  612. params[10].num = 10;
  613. params[11].buffer_type = TSDB_DATA_TYPE_USMALLINT;
  614. params[11].buffer_length = sizeof(v.u2[0]);
  615. params[11].buffer = v.u2;
  616. params[11].length = u16_len;
  617. params[11].is_null = is_null;
  618. params[11].num = 10;
  619. params[12].buffer_type = TSDB_DATA_TYPE_UINT;
  620. params[12].buffer_length = sizeof(v.u4[0]);
  621. params[12].buffer = v.u4;
  622. params[12].length = u32_len;
  623. params[12].is_null = is_null;
  624. params[12].num = 10;
  625. params[13].buffer_type = TSDB_DATA_TYPE_UBIGINT;
  626. params[13].buffer_length = sizeof(v.u8[0]);
  627. params[13].buffer = v.u8;
  628. params[13].length = u64_len;
  629. params[13].is_null = is_null;
  630. params[13].num = 10;
  631. sql = "insert into ? using st1 tags(?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
  632. code = taos_stmt_prepare(stmt, sql, 0);
  633. if (code != 0) {
  634. printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt));
  635. taos_stmt_close(stmt);
  636. exit(EXIT_FAILURE);
  637. }
  638. code = taos_stmt_set_tbname_tags(stmt, "m1", tags);
  639. if (code != 0) {
  640. printf("\033[31mfailed to execute taos_stmt_set_tbname_tags. error:%s\033[0m\n", taos_stmt_errstr(stmt));
  641. taos_stmt_close(stmt);
  642. exit(EXIT_FAILURE);
  643. }
  644. int64_t ts = 1591060628000;
  645. for (int i = 0; i < 10; ++i) {
  646. v.ts[i] = ts++;
  647. is_null[i] = 0;
  648. v.b[i] = (int8_t)i % 2;
  649. v.v1[i] = (int8_t)i;
  650. v.v2[i] = (int16_t)(i * 2);
  651. v.v4[i] = (int32_t)(i * 4);
  652. v.v8[i] = (int64_t)(i * 8);
  653. v.f4[i] = (float)(i * 40);
  654. v.f8[i] = (double)(i * 80);
  655. for (int j = 0; j < sizeof(v.bin[0]); ++j) {
  656. v.bin[i][j] = (char)(i + '0');
  657. }
  658. strcpy(v.blob[i], "一二三四五六七八九十");
  659. v.u1[i] = (uint8_t)i;
  660. v.u2[i] = (uint16_t)(i * 2);
  661. v.u4[i] = (uint32_t)(i * 4);
  662. v.u8[i] = (uint64_t)(i * 8);
  663. t8_len[i] = sizeof(int8_t);
  664. t16_len[i] = sizeof(int16_t);
  665. t32_len[i] = sizeof(int32_t);
  666. t64_len[i] = sizeof(int64_t);
  667. float_len[i] = sizeof(float);
  668. double_len[i] = sizeof(double);
  669. bin_len[i] = sizeof(v.bin[0]);
  670. blob_len[i] = (int32_t)strlen(v.blob[i]);
  671. u8_len[i] = sizeof(uint8_t);
  672. u16_len[i] = sizeof(uint16_t);
  673. u32_len[i] = sizeof(uint32_t);
  674. u64_len[i] = sizeof(uint64_t);
  675. }
  676. taos_stmt_bind_param_batch(stmt, params);
  677. taos_stmt_add_batch(stmt);
  678. if (taos_stmt_execute(stmt) != 0) {
  679. printf("\033[31mfailed to execute insert statement.error:%s\033[0m\n", taos_stmt_errstr(stmt));
  680. taos_stmt_close(stmt);
  681. exit(EXIT_FAILURE);
  682. }
  683. int affectedRows = taos_stmt_affected_rows(stmt);
  684. printf("successfully inserted %d rows\n", affectedRows);
  685. taos_stmt_close(stmt);
  686. // query the records
  687. stmt = taos_stmt_init(taos);
  688. taos_stmt_prepare(stmt, "SELECT * FROM m1 WHERE v1 > ? AND v2 < ?", 0);
  689. TAOS_BIND qparams[2];
  690. int8_t v1 = 5;
  691. int16_t v2 = 15;
  692. qparams[0].buffer_type = TSDB_DATA_TYPE_TINYINT;
  693. qparams[0].buffer_length = sizeof(v1);
  694. qparams[0].buffer = &v1;
  695. qparams[0].length = &qparams[0].buffer_length;
  696. qparams[0].is_null = NULL;
  697. qparams[1].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  698. qparams[1].buffer_length = sizeof(v2);
  699. qparams[1].buffer = &v2;
  700. qparams[1].length = &qparams[1].buffer_length;
  701. qparams[1].is_null = NULL;
  702. taos_stmt_bind_param(stmt, qparams);
  703. if (taos_stmt_execute(stmt) != 0) {
  704. printf("\033[31mfailed to execute select statement.error:%s\033[0m\n", taos_stmt_errstr(stmt));
  705. taos_stmt_close(stmt);
  706. exit(EXIT_FAILURE);
  707. }
  708. result = taos_stmt_use_result(stmt);
  709. TAOS_ROW row;
  710. int rows = 0;
  711. int num_fields = taos_num_fields(result);
  712. TAOS_FIELD* fields = taos_fetch_fields(result);
  713. // fetch the records row by row
  714. while ((row = taos_fetch_row(result))) {
  715. char temp[256] = {0};
  716. rows++;
  717. taos_print_row(temp, row, fields, num_fields);
  718. printf("%s\n", temp);
  719. }
  720. taos_free_result(result);
  721. taos_stmt_close(stmt);
  722. free(t8_len);
  723. free(t16_len);
  724. free(t32_len);
  725. free(t64_len);
  726. free(float_len);
  727. free(double_len);
  728. free(bin_len);
  729. free(blob_len);
  730. free(u8_len);
  731. free(u16_len);
  732. free(u32_len);
  733. free(u64_len);
  734. }
  735. /**
  736. * @brief Verify the upper/lower case of tableName for create(by setTableName)/query/show/describe/drop.
  737. * https://jira.taosdata.com:18080/browse/TS-904
  738. * https://jira.taosdata.com:18090/pages/viewpage.action?pageId=129140555
  739. * @param taos
  740. */
  741. void verify_prepare4(TAOS* taos) {
  742. printf("Verify the upper/lower case of tableName for create(by setTableName)/query/show/describe/drop etc.\n");
  743. TAOS_RES* result = taos_query(taos, "drop database if exists test;");
  744. taos_free_result(result);
  745. usleep(100000);
  746. result = taos_query(taos, "create database test;");
  747. int code = taos_errno(result);
  748. if (code != 0) {
  749. printf("\033[31mfailed to create database, reason:%s\033[0m\n", taos_errstr(result));
  750. taos_free_result(result);
  751. exit(EXIT_FAILURE);
  752. }
  753. taos_free_result(result);
  754. usleep(100000);
  755. taos_select_db(taos, "test");
  756. // create table
  757. const char* sql =
  758. "create stable st1 (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin "
  759. "binary(40), blob nchar(10), u1 tinyint unsigned, u2 smallint unsigned, u4 int unsigned, u8 bigint unsigned) "
  760. "tags "
  761. "(b_tag bool, v1_tag tinyint, v2_tag smallint, v4_tag int, v8_tag bigint, f4_tag float, f8_tag double, bin_tag "
  762. "binary(40), blob_tag nchar(10), u1_tag tinyint unsigned, u2_tag smallint unsigned, u4_tag int unsigned, u8_tag "
  763. "bigint "
  764. "unsigned)";
  765. result = taos_query(taos, sql);
  766. code = taos_errno(result);
  767. if (code != 0) {
  768. printf("\033[31mfailed to create table, reason:%s\033[0m\n", taos_errstr(result));
  769. taos_free_result(result);
  770. exit(EXIT_FAILURE);
  771. }
  772. taos_free_result(result);
  773. TAOS_BIND tags[13];
  774. struct {
  775. int8_t b;
  776. int8_t v1;
  777. int16_t v2;
  778. int32_t v4;
  779. int64_t v8;
  780. float f4;
  781. double f8;
  782. char bin[40];
  783. char blob[80];
  784. uint8_t u1;
  785. uint16_t u2;
  786. uint32_t u4;
  787. uint64_t u8;
  788. } id = {0};
  789. id.b = (int8_t)1;
  790. id.v1 = (int8_t)1;
  791. id.v2 = (int16_t)2;
  792. id.v4 = (int32_t)4;
  793. id.v8 = (int64_t)8;
  794. id.f4 = (float)40;
  795. id.f8 = (double)80;
  796. for (int j = 0; j < sizeof(id.bin); ++j) {
  797. id.bin[j] = (char)('1' + '0');
  798. }
  799. strcpy(id.blob, "一二三四五六七八九十");
  800. id.u1 = (uint8_t)1;
  801. id.u2 = (uint16_t)2;
  802. id.u4 = (uint32_t)4;
  803. id.u8 = (uint64_t)8;
  804. tags[0].buffer_type = TSDB_DATA_TYPE_BOOL;
  805. tags[0].buffer_length = sizeof(id.b);
  806. tags[0].buffer = &id.b;
  807. tags[0].length = &tags[0].buffer_length;
  808. tags[0].is_null = NULL;
  809. tags[1].buffer_type = TSDB_DATA_TYPE_TINYINT;
  810. tags[1].buffer_length = sizeof(id.v1);
  811. tags[1].buffer = &id.v1;
  812. tags[1].length = &tags[1].buffer_length;
  813. tags[1].is_null = NULL;
  814. tags[2].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  815. tags[2].buffer_length = sizeof(id.v2);
  816. tags[2].buffer = &id.v2;
  817. tags[2].length = &tags[2].buffer_length;
  818. tags[2].is_null = NULL;
  819. tags[3].buffer_type = TSDB_DATA_TYPE_INT;
  820. tags[3].buffer_length = sizeof(id.v4);
  821. tags[3].buffer = &id.v4;
  822. tags[3].length = &tags[3].buffer_length;
  823. tags[3].is_null = NULL;
  824. tags[4].buffer_type = TSDB_DATA_TYPE_BIGINT;
  825. tags[4].buffer_length = sizeof(id.v8);
  826. tags[4].buffer = &id.v8;
  827. tags[4].length = &tags[4].buffer_length;
  828. tags[4].is_null = NULL;
  829. tags[5].buffer_type = TSDB_DATA_TYPE_FLOAT;
  830. tags[5].buffer_length = sizeof(id.f4);
  831. tags[5].buffer = &id.f4;
  832. tags[5].length = &tags[5].buffer_length;
  833. tags[5].is_null = NULL;
  834. tags[6].buffer_type = TSDB_DATA_TYPE_DOUBLE;
  835. tags[6].buffer_length = sizeof(id.f8);
  836. tags[6].buffer = &id.f8;
  837. tags[6].length = &tags[6].buffer_length;
  838. tags[6].is_null = NULL;
  839. tags[7].buffer_type = TSDB_DATA_TYPE_BINARY;
  840. tags[7].buffer_length = sizeof(id.bin);
  841. tags[7].buffer = &id.bin;
  842. tags[7].length = &tags[7].buffer_length;
  843. tags[7].is_null = NULL;
  844. tags[8].buffer_type = TSDB_DATA_TYPE_NCHAR;
  845. tags[8].buffer_length = strlen(id.blob);
  846. tags[8].buffer = &id.blob;
  847. tags[8].length = &tags[8].buffer_length;
  848. tags[8].is_null = NULL;
  849. tags[9].buffer_type = TSDB_DATA_TYPE_UTINYINT;
  850. tags[9].buffer_length = sizeof(id.u1);
  851. tags[9].buffer = &id.u1;
  852. tags[9].length = &tags[9].buffer_length;
  853. tags[9].is_null = NULL;
  854. tags[10].buffer_type = TSDB_DATA_TYPE_USMALLINT;
  855. tags[10].buffer_length = sizeof(id.u2);
  856. tags[10].buffer = &id.u2;
  857. tags[10].length = &tags[10].buffer_length;
  858. tags[10].is_null = NULL;
  859. tags[11].buffer_type = TSDB_DATA_TYPE_UINT;
  860. tags[11].buffer_length = sizeof(id.u4);
  861. tags[11].buffer = &id.u4;
  862. tags[11].length = &tags[11].buffer_length;
  863. tags[11].is_null = NULL;
  864. tags[12].buffer_type = TSDB_DATA_TYPE_UBIGINT;
  865. tags[12].buffer_length = sizeof(id.u8);
  866. tags[12].buffer = &id.u8;
  867. tags[12].length = &tags[12].buffer_length;
  868. tags[12].is_null = NULL;
  869. // insert 10 records
  870. struct {
  871. int64_t ts[10];
  872. int8_t b[10];
  873. int8_t v1[10];
  874. int16_t v2[10];
  875. int32_t v4[10];
  876. int64_t v8[10];
  877. float f4[10];
  878. double f8[10];
  879. char bin[10][40];
  880. char blob[10][80];
  881. uint8_t u1[10];
  882. uint16_t u2[10];
  883. uint32_t u4[10];
  884. uint64_t u8[10];
  885. } v;
  886. int32_t* t8_len = malloc(sizeof(int32_t) * 10);
  887. int32_t* t16_len = malloc(sizeof(int32_t) * 10);
  888. int32_t* t32_len = malloc(sizeof(int32_t) * 10);
  889. int32_t* t64_len = malloc(sizeof(int32_t) * 10);
  890. int32_t* float_len = malloc(sizeof(int32_t) * 10);
  891. int32_t* double_len = malloc(sizeof(int32_t) * 10);
  892. int32_t* bin_len = malloc(sizeof(int32_t) * 10);
  893. int32_t* blob_len = malloc(sizeof(int32_t) * 10);
  894. int32_t* u8_len = malloc(sizeof(int32_t) * 10);
  895. int32_t* u16_len = malloc(sizeof(int32_t) * 10);
  896. int32_t* u32_len = malloc(sizeof(int32_t) * 10);
  897. int32_t* u64_len = malloc(sizeof(int32_t) * 10);
  898. TAOS_MULTI_BIND params[14];
  899. char is_null[10] = {0};
  900. params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP;
  901. params[0].buffer_length = sizeof(v.ts[0]);
  902. params[0].buffer = v.ts;
  903. params[0].length = t64_len;
  904. params[0].is_null = is_null;
  905. params[0].num = 10;
  906. params[1].buffer_type = TSDB_DATA_TYPE_BOOL;
  907. params[1].buffer_length = sizeof(v.b[0]);
  908. params[1].buffer = v.b;
  909. params[1].length = t8_len;
  910. params[1].is_null = is_null;
  911. params[1].num = 10;
  912. params[2].buffer_type = TSDB_DATA_TYPE_TINYINT;
  913. params[2].buffer_length = sizeof(v.v1[0]);
  914. params[2].buffer = v.v1;
  915. params[2].length = t8_len;
  916. params[2].is_null = is_null;
  917. params[2].num = 10;
  918. params[3].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  919. params[3].buffer_length = sizeof(v.v2[0]);
  920. params[3].buffer = v.v2;
  921. params[3].length = t16_len;
  922. params[3].is_null = is_null;
  923. params[3].num = 10;
  924. params[4].buffer_type = TSDB_DATA_TYPE_INT;
  925. params[4].buffer_length = sizeof(v.v4[0]);
  926. params[4].buffer = v.v4;
  927. params[4].length = t32_len;
  928. params[4].is_null = is_null;
  929. params[4].num = 10;
  930. params[5].buffer_type = TSDB_DATA_TYPE_BIGINT;
  931. params[5].buffer_length = sizeof(v.v8[0]);
  932. params[5].buffer = v.v8;
  933. params[5].length = t64_len;
  934. params[5].is_null = is_null;
  935. params[5].num = 10;
  936. params[6].buffer_type = TSDB_DATA_TYPE_FLOAT;
  937. params[6].buffer_length = sizeof(v.f4[0]);
  938. params[6].buffer = v.f4;
  939. params[6].length = float_len;
  940. params[6].is_null = is_null;
  941. params[6].num = 10;
  942. params[7].buffer_type = TSDB_DATA_TYPE_DOUBLE;
  943. params[7].buffer_length = sizeof(v.f8[0]);
  944. params[7].buffer = v.f8;
  945. params[7].length = double_len;
  946. params[7].is_null = is_null;
  947. params[7].num = 10;
  948. params[8].buffer_type = TSDB_DATA_TYPE_BINARY;
  949. params[8].buffer_length = sizeof(v.bin[0]);
  950. params[8].buffer = v.bin;
  951. params[8].length = bin_len;
  952. params[8].is_null = is_null;
  953. params[8].num = 10;
  954. params[9].buffer_type = TSDB_DATA_TYPE_NCHAR;
  955. params[9].buffer_length = sizeof(v.blob[0]);
  956. params[9].buffer = v.blob;
  957. params[9].length = blob_len;
  958. params[9].is_null = is_null;
  959. params[9].num = 10;
  960. params[10].buffer_type = TSDB_DATA_TYPE_UTINYINT;
  961. params[10].buffer_length = sizeof(v.u1[0]);
  962. params[10].buffer = v.u1;
  963. params[10].length = u8_len;
  964. params[10].is_null = is_null;
  965. params[10].num = 10;
  966. params[11].buffer_type = TSDB_DATA_TYPE_USMALLINT;
  967. params[11].buffer_length = sizeof(v.u2[0]);
  968. params[11].buffer = v.u2;
  969. params[11].length = u16_len;
  970. params[11].is_null = is_null;
  971. params[11].num = 10;
  972. params[12].buffer_type = TSDB_DATA_TYPE_UINT;
  973. params[12].buffer_length = sizeof(v.u4[0]);
  974. params[12].buffer = v.u4;
  975. params[12].length = u32_len;
  976. params[12].is_null = is_null;
  977. params[12].num = 10;
  978. params[13].buffer_type = TSDB_DATA_TYPE_UBIGINT;
  979. params[13].buffer_length = sizeof(v.u8[0]);
  980. params[13].buffer = v.u8;
  981. params[13].length = u64_len;
  982. params[13].is_null = is_null;
  983. params[13].num = 10;
  984. // verify table names for upper/lower case
  985. #define VERIFY_CNT 5
  986. typedef struct {
  987. char setTbName[20];
  988. char showName[20];
  989. char describeName[20];
  990. char queryName[20];
  991. char dropName[20];
  992. } STbNames;
  993. /**
  994. * @brief
  995. * 0 - success expected
  996. * NonZero - fail expected
  997. */
  998. typedef struct {
  999. int32_t setTbName;
  1000. int32_t showName;
  1001. int32_t describeName;
  1002. int32_t queryName;
  1003. int32_t dropName;
  1004. } STbNamesResult;
  1005. STbNames tbName[VERIFY_CNT] = {0};
  1006. STbNamesResult tbNameResult[VERIFY_CNT] = {0};
  1007. STbNames* pTbName = NULL;
  1008. STbNamesResult* pTbNameResult = NULL;
  1009. pTbName = &tbName[0];
  1010. pTbNameResult = &tbNameResult[0];
  1011. strcpy(pTbName->setTbName, "Mn1");
  1012. strcpy(pTbName->showName, "mn1");
  1013. strcpy(pTbName->describeName, "mn1");
  1014. strcpy(pTbName->queryName, "mn1");
  1015. strcpy(pTbName->dropName, "mn1");
  1016. pTbName = &tbName[1];
  1017. pTbNameResult = &tbNameResult[1];
  1018. strcpy(pTbName->setTbName, "'Mn1'");
  1019. strcpy(pTbName->showName, "'mn1'");
  1020. strcpy(pTbName->describeName, "'mn1'");
  1021. strcpy(pTbName->queryName, "'mn1'");
  1022. strcpy(pTbName->dropName, "'mn1'");
  1023. pTbName = &tbName[2];
  1024. pTbNameResult = &tbNameResult[2];
  1025. strcpy(pTbName->setTbName, "\"Mn1\"");
  1026. strcpy(pTbName->showName, "\"mn1\"");
  1027. strcpy(pTbName->describeName, "\"mn1\"");
  1028. strcpy(pTbName->queryName, "\"mn1\"");
  1029. strcpy(pTbName->dropName, "\"mn1\"");
  1030. pTbName = &tbName[3];
  1031. pTbNameResult = &tbNameResult[3];
  1032. strcpy(pTbName->setTbName, "\"Mn1\"");
  1033. strcpy(pTbName->showName, "'mn1'");
  1034. strcpy(pTbName->describeName, "'mn1'");
  1035. strcpy(pTbName->queryName, "mn1");
  1036. strcpy(pTbName->dropName, "\"mn1\"");
  1037. pTbName = &tbName[4];
  1038. pTbNameResult = &tbNameResult[4];
  1039. strcpy(pTbName->setTbName, "`Mn1`");
  1040. strcpy(pTbName->showName, "Mn1"); // TODO support uniform of ``
  1041. strcpy(pTbName->describeName, "`Mn1`");
  1042. strcpy(pTbName->queryName, "`Mn1`");
  1043. strcpy(pTbName->dropName, "`Mn1`");
  1044. TAOS_STMT* stmt = NULL;
  1045. for (int n = 0; n < VERIFY_CNT; ++n) {
  1046. printf("\033[31m[%d] ===================================\033[0m\n", n);
  1047. pTbName = &tbName[n];
  1048. pTbNameResult = &tbNameResult[n];
  1049. char tmpStr[256] = {0};
  1050. // set table name
  1051. stmt = taos_stmt_init(taos);
  1052. if (!stmt) {
  1053. printf("\033[31m[%d] failed to execute taos_stmt_init. error:%s\033[0m\n", n);
  1054. exit(EXIT_FAILURE);
  1055. }
  1056. sql = "insert into ? using st1 tags(?,?,?,?,?,?,?,?,?,?,?,?,?) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
  1057. code = taos_stmt_prepare(stmt, sql, 0);
  1058. if (code != 0) {
  1059. printf("\033[31mfailed to execute taos_stmt_prepare. error:%s\033[0m\n", taos_stmt_errstr(stmt));
  1060. taos_stmt_close(stmt);
  1061. exit(EXIT_FAILURE);
  1062. }
  1063. printf("[%d] taos_stmt_set_tbname_tags, tbname=%s\n", n, pTbName->setTbName);
  1064. code = taos_stmt_set_tbname_tags(stmt, pTbName->setTbName, tags);
  1065. if ((!pTbNameResult->setTbName && (0 != code)) || (pTbNameResult->setTbName && (0 == code))) {
  1066. printf("\033[31m[%d] failed to execute taos_stmt_set_tbname_tags. error:%s\033[0m\n", n, taos_stmt_errstr(stmt));
  1067. taos_stmt_close(stmt);
  1068. exit(EXIT_FAILURE);
  1069. }
  1070. if (code == 0) {
  1071. int64_t ts = 1591060628000 + 1000 * n;
  1072. for (int i = 0; i < 10; ++i) {
  1073. v.ts[i] = ts++;
  1074. is_null[i] = 0;
  1075. v.b[i] = (int8_t)i % 2;
  1076. v.v1[i] = (int8_t)i;
  1077. v.v2[i] = (int16_t)(i * 2);
  1078. v.v4[i] = (int32_t)(i * 4);
  1079. v.v8[i] = (int64_t)(i * 8);
  1080. v.f4[i] = (float)(i * 40);
  1081. v.f8[i] = (double)(i * 80);
  1082. for (int j = 0; j < sizeof(v.bin[0]); ++j) {
  1083. v.bin[i][j] = (char)(i + '0');
  1084. }
  1085. strcpy(v.blob[i], "一二三四五六七八九十");
  1086. v.u1[i] = (uint8_t)i;
  1087. v.u2[i] = (uint16_t)(i * 2);
  1088. v.u4[i] = (uint32_t)(i * 4);
  1089. v.u8[i] = (uint64_t)(i * 8);
  1090. t8_len[i] = sizeof(int8_t);
  1091. t16_len[i] = sizeof(int16_t);
  1092. t32_len[i] = sizeof(int32_t);
  1093. t64_len[i] = sizeof(int64_t);
  1094. float_len[i] = sizeof(float);
  1095. double_len[i] = sizeof(double);
  1096. bin_len[i] = sizeof(v.bin[0]);
  1097. blob_len[i] = (int32_t)strlen(v.blob[i]);
  1098. u8_len[i] = sizeof(uint8_t);
  1099. u16_len[i] = sizeof(uint16_t);
  1100. u32_len[i] = sizeof(uint32_t);
  1101. u64_len[i] = sizeof(uint64_t);
  1102. }
  1103. taos_stmt_bind_param_batch(stmt, params);
  1104. taos_stmt_add_batch(stmt);
  1105. if (taos_stmt_execute(stmt) != 0) {
  1106. printf("\033[31m[%d] failed to execute insert statement.error:%s\033[0m\n", n, taos_stmt_errstr(stmt));
  1107. taos_stmt_close(stmt);
  1108. exit(EXIT_FAILURE);
  1109. }
  1110. }
  1111. taos_stmt_close(stmt);
  1112. // show the table
  1113. printf("[%d] show tables, tbName = %s\n", n, pTbName->showName);
  1114. stmt = taos_stmt_init(taos);
  1115. sprintf(tmpStr, "show tables like %s", pTbName->showName);
  1116. taos_stmt_prepare(stmt, tmpStr, 0);
  1117. code = taos_stmt_execute(stmt);
  1118. if ((!pTbNameResult->showName && (0 != code)) || (pTbNameResult->showName && (0 == code))) {
  1119. printf("\033[31m[%d] failed to execute show tables like. error:%s\033[0m\n", n, taos_stmt_errstr(stmt));
  1120. taos_stmt_close(stmt);
  1121. exit(EXIT_FAILURE);
  1122. }
  1123. taos_stmt_close(stmt);
  1124. // describe the table
  1125. printf("[%d] describe tables, tbName = %s\n", n, pTbName->describeName);
  1126. stmt = taos_stmt_init(taos);
  1127. sprintf(tmpStr, "describe %s", pTbName->describeName);
  1128. taos_stmt_prepare(stmt, tmpStr, 0);
  1129. code = taos_stmt_execute(stmt);
  1130. if ((!pTbNameResult->describeName && (0 != code)) || (pTbNameResult->describeName && (0 == code))) {
  1131. printf("\033[31m[%d] failed to execute describe tables. error:%s\033[0m\n", n, taos_stmt_errstr(stmt));
  1132. taos_stmt_close(stmt);
  1133. exit(EXIT_FAILURE);
  1134. }
  1135. taos_stmt_close(stmt);
  1136. // query the records
  1137. printf("[%d] select statement, tbName = %s\n", n, pTbName->queryName);
  1138. stmt = taos_stmt_init(taos);
  1139. sprintf(tmpStr, "SELECT * FROM %s", pTbName->queryName);
  1140. taos_stmt_prepare(stmt, tmpStr, 0);
  1141. TAOS_BIND qparams[2];
  1142. int8_t v1 = 5;
  1143. int16_t v2 = 15;
  1144. qparams[0].buffer_type = TSDB_DATA_TYPE_TINYINT;
  1145. qparams[0].buffer_length = sizeof(v1);
  1146. qparams[0].buffer = &v1;
  1147. qparams[0].length = &qparams[0].buffer_length;
  1148. qparams[0].is_null = NULL;
  1149. qparams[1].buffer_type = TSDB_DATA_TYPE_SMALLINT;
  1150. qparams[1].buffer_length = sizeof(v2);
  1151. qparams[1].buffer = &v2;
  1152. qparams[1].length = &qparams[1].buffer_length;
  1153. qparams[1].is_null = NULL;
  1154. taos_stmt_bind_param(stmt, qparams);
  1155. code = taos_stmt_execute(stmt);
  1156. if ((!pTbNameResult->queryName && (0 != code)) || (pTbNameResult->queryName && (0 == code))) {
  1157. printf("\033[31m[%d] failed to execute select statement.error:%s\033[0m\n", n, taos_stmt_errstr(stmt));
  1158. taos_stmt_close(stmt);
  1159. exit(EXIT_FAILURE);
  1160. }
  1161. result = taos_stmt_use_result(stmt);
  1162. TAOS_ROW row;
  1163. int rows = 0;
  1164. int num_fields = taos_num_fields(result);
  1165. TAOS_FIELD* fields = taos_fetch_fields(result);
  1166. // fetch the records row by row
  1167. while ((row = taos_fetch_row(result))) {
  1168. char temp[256] = {0};
  1169. rows++;
  1170. taos_print_row(temp, row, fields, num_fields);
  1171. printf("[%d] row = %s\n", n, temp);
  1172. }
  1173. taos_free_result(result);
  1174. taos_stmt_close(stmt);
  1175. // drop table
  1176. printf("[%d] drop table, tbName = %s\n", n, pTbName->dropName);
  1177. stmt = taos_stmt_init(taos);
  1178. sprintf(tmpStr, "drop table %s", pTbName->dropName);
  1179. taos_stmt_prepare(stmt, tmpStr, 0);
  1180. code = taos_stmt_execute(stmt);
  1181. if ((!pTbNameResult->dropName && (0 != code)) || (pTbNameResult->dropName && (0 == code))) {
  1182. printf("\033[31m[%d] failed to drop table. error:%s\033[0m\n", n, taos_stmt_errstr(stmt));
  1183. taos_stmt_close(stmt);
  1184. exit(EXIT_FAILURE);
  1185. }
  1186. taos_stmt_close(stmt);
  1187. }
  1188. free(t8_len);
  1189. free(t16_len);
  1190. free(t32_len);
  1191. free(t64_len);
  1192. free(float_len);
  1193. free(double_len);
  1194. free(bin_len);
  1195. free(blob_len);
  1196. free(u8_len);
  1197. free(u16_len);
  1198. free(u32_len);
  1199. free(u64_len);
  1200. }
  1201. int main(int argc, char* argv[]) {
  1202. const char* host = "127.0.0.1";
  1203. const char* user = "root";
  1204. const char* passwd = "taosdata";
  1205. taos_options(TSDB_OPTION_TIMEZONE, "GMT-8");
  1206. TAOS* taos = taos_connect(host, user, passwd, "", 0);
  1207. if (taos == NULL) {
  1208. printf("\033[31mfailed to connect to db, reason:%s\033[0m\n", taos_errstr(taos));
  1209. exit(1);
  1210. }
  1211. char* info = taos_get_server_info(taos);
  1212. printf("server info: %s\n", info);
  1213. info = taos_get_client_info(taos);
  1214. printf("client info: %s\n", info);
  1215. printf("************ verify prepare *************\n");
  1216. verify_prepare(taos);
  1217. printf("************ verify prepare2 *************\n");
  1218. verify_prepare2(taos);
  1219. printf("************ verify prepare3 *************\n");
  1220. verify_prepare3(taos);
  1221. printf("************ verify prepare4 *************\n");
  1222. verify_prepare4(taos);
  1223. printf("************ verify end *************\n");
  1224. exit(EXIT_SUCCESS);
  1225. }

查看源码

无模式写入示例

无模式写入

  1. #include "os.h"
  2. #include "taos.h"
  3. #include "taoserror.h"
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <sys/time.h>
  7. #include <time.h>
  8. #include <unistd.h>
  9. bool verbose = false;
  10. void printThreadId(pthread_t id, char* buf)
  11. {
  12. size_t i;
  13. for (i = sizeof(i); i; --i)
  14. sprintf(buf + strlen(buf), "%02x", *(((unsigned char*) &id) + i - 1));
  15. }
  16. static int64_t getTimeInUs() {
  17. struct timeval systemTime;
  18. gettimeofday(&systemTime, NULL);
  19. return (int64_t)systemTime.tv_sec * 1000000L + (int64_t)systemTime.tv_usec;
  20. }
  21. typedef struct {
  22. char** lines;
  23. int numLines;
  24. } SThreadLinesBatch;
  25. typedef struct {
  26. TAOS* taos;
  27. int protocol;
  28. int numBatches;
  29. SThreadLinesBatch *batches;
  30. int64_t costTime;
  31. } SThreadInsertArgs;
  32. static void* insertLines(void* args) {
  33. SThreadInsertArgs* insertArgs = (SThreadInsertArgs*) args;
  34. char tidBuf[32] = {0};
  35. printThreadId(pthread_self(), tidBuf);
  36. for (int i = 0; i < insertArgs->numBatches; ++i) {
  37. SThreadLinesBatch* batch = insertArgs->batches + i;
  38. if (verbose) printf("%s, thread: 0x%s\n", "begin taos_insert_lines", tidBuf);
  39. int64_t begin = getTimeInUs();
  40. //int32_t code = taos_insert_lines(insertArgs->taos, batch->lines, batch->numLines);
  41. TAOS_RES * res = taos_schemaless_insert(insertArgs->taos, batch->lines, batch->numLines, insertArgs->protocol, TSDB_SML_TIMESTAMP_MILLI_SECONDS);
  42. int32_t code = taos_errno(res);
  43. int64_t end = getTimeInUs();
  44. insertArgs->costTime += end - begin;
  45. if (verbose) printf("code: %d, %s. time used:%"PRId64", thread: 0x%s\n", code, tstrerror(code), end - begin, tidBuf);
  46. }
  47. return NULL;
  48. }
  49. int32_t getTelenetTemplate(char* lineTemplate, int templateLen) {
  50. char* sample = "sta%d %lld 44.3 t0=False t1=127i8 t2=32 t3=%di32 t4=9223372036854775807i64 t5=11.12345f32 t6=22.123456789f64 t7=\"hpxzrdiw\" t8=\"ncharTagValue\" t9=127i8";
  51. snprintf(lineTemplate, templateLen, "%s", sample);
  52. return 0;
  53. }
  54. int32_t getLineTemplate(char* lineTemplate, int templateLen, int numFields) {
  55. if (numFields <= 4) {
  56. char* sample = "sta%d,t3=%di32 c3=2147483647i32,c4=9223372036854775807i64,c9=11.12345f32,c10=22.123456789f64 %lld";
  57. snprintf(lineTemplate, templateLen, "%s", sample);
  58. return 0;
  59. }
  60. if (numFields <= 13) {
  61. char* sample = "sta%d,t0=true,t1=127i8,t2=32767i16,t3=%di32,t4=9223372036854775807i64,t9=11.12345f32,t10=22.123456789f64,t11=\"binaryTagValue\",t12=L\"ncharTagValue\" c0=true,c1=127i8,c2=32767i16,c3=2147483647i32,c4=9223372036854775807i64,c5=254u8,c6=32770u16,c7=2147483699u32,c8=9223372036854775899u64,c9=11.12345f32,c10=22.123456789f64,c11=\"binaryValue\",c12=L\"ncharValue\" %lld";
  62. snprintf(lineTemplate, templateLen, "%s", sample);
  63. return 0;
  64. }
  65. char* lineFormatTable = "sta%d,t0=true,t1=127i8,t2=32767i16,t3=%di32 ";
  66. snprintf(lineTemplate+strlen(lineTemplate), templateLen-strlen(lineTemplate), "%s", lineFormatTable);
  67. int offset[] = {numFields*2/5, numFields*4/5, numFields};
  68. for (int i = 0; i < offset[0]; ++i) {
  69. snprintf(lineTemplate+strlen(lineTemplate), templateLen-strlen(lineTemplate), "c%d=%di32,", i, i);
  70. }
  71. for (int i=offset[0]+1; i < offset[1]; ++i) {
  72. snprintf(lineTemplate+strlen(lineTemplate), templateLen-strlen(lineTemplate), "c%d=%d.43f64,", i, i);
  73. }
  74. for (int i = offset[1]+1; i < offset[2]; ++i) {
  75. snprintf(lineTemplate+strlen(lineTemplate), templateLen-strlen(lineTemplate), "c%d=\"%d\",", i, i);
  76. }
  77. char* lineFormatTs = " %lld";
  78. snprintf(lineTemplate+strlen(lineTemplate)-1, templateLen-strlen(lineTemplate)+1, "%s", lineFormatTs);
  79. return 0;
  80. }
  81. int32_t generateLine(char* line, int lineLen, char* lineTemplate, int protocol, int superTable, int childTable, int64_t ts) {
  82. if (protocol == TSDB_SML_LINE_PROTOCOL) {
  83. snprintf(line, lineLen, lineTemplate, superTable, childTable, ts);
  84. } else if (protocol == TSDB_SML_TELNET_PROTOCOL) {
  85. snprintf(line, lineLen, lineTemplate, superTable, ts, childTable);
  86. }
  87. return TSDB_CODE_SUCCESS;
  88. }
  89. int32_t setupSuperTables(TAOS* taos, char* lineTemplate, int protocol,
  90. int numSuperTables, int numChildTables, int numRowsPerChildTable,
  91. int maxBatchesPerThread, int64_t ts) {
  92. printf("setup supertables...");
  93. {
  94. char** linesStb = calloc(numSuperTables, sizeof(char*));
  95. for (int i = 0; i < numSuperTables; i++) {
  96. char* lineStb = calloc(strlen(lineTemplate)+128, 1);
  97. generateLine(lineStb, strlen(lineTemplate)+128, lineTemplate, protocol, i,
  98. numSuperTables * numChildTables,
  99. ts + numSuperTables * numChildTables * numRowsPerChildTable);
  100. linesStb[i] = lineStb;
  101. }
  102. SThreadInsertArgs args = {0};
  103. args.protocol = protocol;
  104. args.batches = calloc(maxBatchesPerThread, sizeof(maxBatchesPerThread));
  105. args.taos = taos;
  106. args.batches[0].lines = linesStb;
  107. args.batches[0].numLines = numSuperTables;
  108. insertLines(&args);
  109. free(args.batches);
  110. for (int i = 0; i < numSuperTables; ++i) {
  111. free(linesStb[i]);
  112. }
  113. free(linesStb);
  114. }
  115. return TSDB_CODE_SUCCESS;
  116. }
  117. int main(int argc, char* argv[]) {
  118. int numThreads = 8;
  119. int maxBatchesPerThread = 1024;
  120. int numSuperTables = 1;
  121. int numChildTables = 256;
  122. int numRowsPerChildTable = 8192;
  123. int numFields = 13;
  124. int maxLinesPerBatch = 16384;
  125. int protocol = TSDB_SML_TELNET_PROTOCOL;
  126. int assembleSTables = 0;
  127. int opt;
  128. while ((opt = getopt(argc, argv, "s:c:r:f:t:b:p:w:hv")) != -1) {
  129. switch (opt) {
  130. case 's':
  131. numSuperTables = atoi(optarg);
  132. break;
  133. case 'c':
  134. numChildTables = atoi(optarg);
  135. break;
  136. case 'r':
  137. numRowsPerChildTable = atoi(optarg);
  138. break;
  139. case 'f':
  140. numFields = atoi(optarg);
  141. break;
  142. case 't':
  143. numThreads = atoi(optarg);
  144. break;
  145. case 'b':
  146. maxLinesPerBatch = atoi(optarg);
  147. break;
  148. case 'v':
  149. verbose = true;
  150. break;
  151. case 'a':
  152. assembleSTables = atoi(optarg);
  153. break;
  154. case 'p':
  155. if (optarg[0] == 't') {
  156. protocol = TSDB_SML_TELNET_PROTOCOL;
  157. } else if (optarg[0] == 'l') {
  158. protocol = TSDB_SML_LINE_PROTOCOL;
  159. } else if (optarg[0] == 'j') {
  160. protocol = TSDB_SML_JSON_PROTOCOL;
  161. }
  162. break;
  163. case 'h':
  164. fprintf(stderr, "Usage: %s -s supertable -c childtable -r rows -f fields -t threads -b maxlines_per_batch -p [t|l|j] -a assemble-stables -v\n",
  165. argv[0]);
  166. exit(0);
  167. default: /* '?' */
  168. fprintf(stderr, "Usage: %s -s supertable -c childtable -r rows -f fields -t threads -b maxlines_per_batch -p [t|l|j] -a assemble-stables -v\n",
  169. argv[0]);
  170. exit(-1);
  171. }
  172. }
  173. TAOS_RES* result;
  174. //const char* host = "127.0.0.1";
  175. const char* host = NULL;
  176. const char* user = "root";
  177. const char* passwd = "taosdata";
  178. taos_options(TSDB_OPTION_TIMEZONE, "GMT-8");
  179. TAOS* taos = taos_connect(host, user, passwd, "", 0);
  180. if (taos == NULL) {
  181. printf("\033[31mfailed to connect to db, reason:%s\033[0m\n", taos_errstr(taos));
  182. exit(1);
  183. }
  184. maxBatchesPerThread = (numSuperTables*numChildTables*numRowsPerChildTable)/(numThreads * maxLinesPerBatch) + 1;
  185. char* info = taos_get_server_info(taos);
  186. printf("server info: %s\n", info);
  187. info = taos_get_client_info(taos);
  188. printf("client info: %s\n", info);
  189. result = taos_query(taos, "drop database if exists db;");
  190. taos_free_result(result);
  191. usleep(100000);
  192. result = taos_query(taos, "create database db precision 'us';");
  193. taos_free_result(result);
  194. usleep(100000);
  195. (void)taos_select_db(taos, "db");
  196. time_t ct = time(0);
  197. int64_t ts = ct * 1000 ;
  198. char* lineTemplate = calloc(65536, sizeof(char));
  199. if (protocol == TSDB_SML_LINE_PROTOCOL) {
  200. getLineTemplate(lineTemplate, 65535, numFields);
  201. } else if (protocol == TSDB_SML_TELNET_PROTOCOL ) {
  202. getTelenetTemplate(lineTemplate, 65535);
  203. }
  204. if (assembleSTables) {
  205. setupSuperTables(taos, lineTemplate, protocol,
  206. numSuperTables, numChildTables, numRowsPerChildTable, maxBatchesPerThread, ts);
  207. }
  208. printf("generate lines...\n");
  209. pthread_t* tids = calloc(numThreads, sizeof(pthread_t));
  210. SThreadInsertArgs* argsThread = calloc(numThreads, sizeof(SThreadInsertArgs));
  211. for (int i = 0; i < numThreads; ++i) {
  212. argsThread[i].batches = calloc(maxBatchesPerThread, sizeof(SThreadLinesBatch));
  213. argsThread[i].taos = taos;
  214. argsThread[i].numBatches = 0;
  215. argsThread[i].protocol = protocol;
  216. }
  217. int64_t totalLines = numSuperTables * numChildTables * numRowsPerChildTable;
  218. int totalBatches = (int) ((totalLines) / maxLinesPerBatch);
  219. if (totalLines % maxLinesPerBatch != 0) {
  220. totalBatches += 1;
  221. }
  222. char*** allBatches = calloc(totalBatches, sizeof(char**));
  223. for (int i = 0; i < totalBatches; ++i) {
  224. allBatches[i] = calloc(maxLinesPerBatch, sizeof(char*));
  225. int threadNo = i % numThreads;
  226. int batchNo = i / numThreads;
  227. argsThread[threadNo].batches[batchNo].lines = allBatches[i];
  228. argsThread[threadNo].numBatches = batchNo + 1;
  229. }
  230. int l = 0;
  231. for (int i = 0; i < numSuperTables; ++i) {
  232. for (int j = 0; j < numChildTables; ++j) {
  233. for (int k = 0; k < numRowsPerChildTable; ++k) {
  234. int stIdx = i;
  235. int ctIdx = numSuperTables*numChildTables + j;
  236. char* line = calloc(strlen(lineTemplate)+128, 1);
  237. generateLine(line, strlen(lineTemplate)+128, lineTemplate, protocol, stIdx, ctIdx, ts + l);
  238. int batchNo = l / maxLinesPerBatch;
  239. int lineNo = l % maxLinesPerBatch;
  240. allBatches[batchNo][lineNo] = line;
  241. argsThread[batchNo % numThreads].batches[batchNo/numThreads].numLines = lineNo + 1;
  242. ++l;
  243. }
  244. }
  245. }
  246. printf("begin multi-thread insertion...\n");
  247. int64_t begin = taosGetTimestampUs();
  248. for (int i=0; i < numThreads; ++i) {
  249. pthread_create(tids+i, NULL, insertLines, argsThread+i);
  250. }
  251. for (int i = 0; i < numThreads; ++i) {
  252. pthread_join(tids[i], NULL);
  253. }
  254. int64_t end = taosGetTimestampUs();
  255. size_t linesNum = numSuperTables*numChildTables*numRowsPerChildTable;
  256. printf("TOTAL LINES: %zu\n", linesNum);
  257. printf("THREADS: %d\n", numThreads);
  258. printf("TIME: %d(ms)\n", (int)(end-begin)/1000);
  259. double throughput = (double)(totalLines)/(double)(end-begin) * 1000000;
  260. printf("THROUGHPUT:%d/s\n", (int)throughput);
  261. for (int i = 0; i < totalBatches; ++i) {
  262. free(allBatches[i]);
  263. }
  264. free(allBatches);
  265. for (int i = 0; i < numThreads; i++) {
  266. free(argsThread[i].batches);
  267. }
  268. free(argsThread);
  269. free(tids);
  270. free(lineTemplate);
  271. taos_close(taos);
  272. return 0;
  273. }

查看源码

订阅和消费示例

订阅和消费

// sample code for TDengine subscribe/consume API
// to compile: gcc -o subscribe subscribe.c -ltaos

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <taos.h>  // include TDengine header file
#include <unistd.h>

int nTotalRows;

void print_result(TAOS_RES* res, int blockFetch) {
  TAOS_ROW    row = NULL;
  int         num_fields = taos_num_fields(res);
  TAOS_FIELD* fields = taos_fetch_fields(res);
  int         nRows = 0;

  if (blockFetch) {
    nRows = taos_fetch_block(res, &row);
    // for (int i = 0; i < nRows; i++) {
    //  taos_print_row(buf, row + i, fields, num_fields);
    //  puts(buf);
    //}
  } else {
    while ((row = taos_fetch_row(res))) {
      char buf[4096] = {0};
      taos_print_row(buf, row, fields, num_fields);
      puts(buf);
      nRows++;
    }
  }

  nTotalRows += nRows;
  printf("%d rows consumed.\n", nRows);
}

void subscribe_callback(TAOS_SUB* tsub, TAOS_RES* res, void* param, int code) { print_result(res, *(int*)param); }

void check_row_count(int line, TAOS_RES* res, int expected) {
  int      actual = 0;
  TAOS_ROW row;
  while ((row = taos_fetch_row(res))) {
    actual++;
  }
  if (actual != expected) {
    printf("line %d: row count mismatch, expected: %d, actual: %d\n", line, expected, actual);
  } else {
    printf("line %d: %d rows consumed as expected\n", line, actual);
  }
}

void do_query(TAOS* taos, const char* sql) {
  TAOS_RES* res = taos_query(taos, sql);
  taos_free_result(res);
}

void run_test(TAOS* taos) {
  do_query(taos, "drop database if exists test;");

  usleep(100000);
  do_query(taos, "create database test;");
  usleep(100000);
  do_query(taos, "use test;");

  usleep(100000);
  do_query(taos, "create table meters(ts timestamp, a int) tags(area int);");

  do_query(taos, "create table t0 using meters tags(0);");
  do_query(taos, "create table t1 using meters tags(1);");
  do_query(taos, "create table t2 using meters tags(2);");
  do_query(taos, "create table t3 using meters tags(3);");
  do_query(taos, "create table t4 using meters tags(4);");
  do_query(taos, "create table t5 using meters tags(5);");
  do_query(taos, "create table t6 using meters tags(6);");
  do_query(taos, "create table t7 using meters tags(7);");
  do_query(taos, "create table t8 using meters tags(8);");
  do_query(taos, "create table t9 using meters tags(9);");

  do_query(taos, "insert into t0 values('2020-01-01 00:00:00.000', 0);");
  do_query(taos, "insert into t0 values('2020-01-01 00:01:00.000', 0);");
  do_query(taos, "insert into t0 values('2020-01-01 00:02:00.000', 0);");
  do_query(taos, "insert into t1 values('2020-01-01 00:00:00.000', 0);");
  do_query(taos, "insert into t1 values('2020-01-01 00:01:00.000', 0);");
  do_query(taos, "insert into t1 values('2020-01-01 00:02:00.000', 0);");
  do_query(taos, "insert into t1 values('2020-01-01 00:03:00.000', 0);");
  do_query(taos, "insert into t2 values('2020-01-01 00:00:00.000', 0);");
  do_query(taos, "insert into t2 values('2020-01-01 00:01:00.000', 0);");
  do_query(taos, "insert into t2 values('2020-01-01 00:01:01.000', 0);");
  do_query(taos, "insert into t2 values('2020-01-01 00:01:02.000', 0);");
  do_query(taos, "insert into t3 values('2020-01-01 00:01:02.000', 0);");
  do_query(taos, "insert into t4 values('2020-01-01 00:01:02.000', 0);");
  do_query(taos, "insert into t5 values('2020-01-01 00:01:02.000', 0);");
  do_query(taos, "insert into t6 values('2020-01-01 00:01:02.000', 0);");
  do_query(taos, "insert into t7 values('2020-01-01 00:01:02.000', 0);");
  do_query(taos, "insert into t8 values('2020-01-01 00:01:02.000', 0);");
  do_query(taos, "insert into t9 values('2020-01-01 00:01:02.000', 0);");

  // super tables subscription
  usleep(1000000);

  TAOS_SUB* tsub = taos_subscribe(taos, 0, "test", "select * from meters;", NULL, NULL, 0);
  TAOS_RES* res = taos_consume(tsub);
  check_row_count(__LINE__, res, 18);

  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 0);

  do_query(taos, "insert into t0 values('2020-01-01 00:02:00.001', 0);");
  do_query(taos, "insert into t8 values('2020-01-01 00:01:03.000', 0);");
  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 2);

  do_query(taos, "insert into t2 values('2020-01-01 00:01:02.001', 0);");
  do_query(taos, "insert into t1 values('2020-01-01 00:03:00.001', 0);");
  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 2);

  do_query(taos, "insert into t1 values('2020-01-01 00:03:00.002', 0);");
  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 1);

  // keep progress information and restart subscription
  taos_unsubscribe(tsub, 1);
  do_query(taos, "insert into t0 values('2020-01-01 00:04:00.000', 0);");
  tsub = taos_subscribe(taos, 1, "test", "select * from meters;", NULL, NULL, 0);
  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 24);

  // keep progress information and continue previous subscription
  taos_unsubscribe(tsub, 1);
  tsub = taos_subscribe(taos, 0, "test", "select * from meters;", NULL, NULL, 0);
  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 0);

  // don't keep progress information and continue previous subscription
  taos_unsubscribe(tsub, 0);
  tsub = taos_subscribe(taos, 0, "test", "select * from meters;", NULL, NULL, 0);
  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 24);

  // single meter subscription

  taos_unsubscribe(tsub, 0);
  tsub = taos_subscribe(taos, 0, "test", "select * from t0;", NULL, NULL, 0);
  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 5);

  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 0);

  do_query(taos, "insert into t0 values('2020-01-01 00:04:00.001', 0);");
  res = taos_consume(tsub);
  check_row_count(__LINE__, res, 1);

  taos_unsubscribe(tsub, 0);
}

int main(int argc, char* argv[]) {
  const char* host = "127.0.0.1";
  const char* user = "root";
  const char* passwd = "taosdata";
  const char* sql = "select * from meters;";
  const char* topic = "test-multiple";
  int         async = 1, restart = 0, keep = 1, test = 0, blockFetch = 0;

  for (int i = 1; i < argc; i++) {
    if (strncmp(argv[i], "-h=", 3) == 0) {
      host = argv[i] + 3;
      continue;
    }
    if (strncmp(argv[i], "-u=", 3) == 0) {
      user = argv[i] + 3;
      continue;
    }
    if (strncmp(argv[i], "-p=", 3) == 0) {
      passwd = argv[i] + 3;
      continue;
    }
    if (strcmp(argv[i], "-sync") == 0) {
      async = 0;
      continue;
    }
    if (strcmp(argv[i], "-restart") == 0) {
      restart = 1;
      continue;
    }
    if (strcmp(argv[i], "-single") == 0) {
      sql = "select * from t0;";
      topic = "test-single";
      continue;
    }
    if (strcmp(argv[i], "-nokeep") == 0) {
      keep = 0;
      continue;
    }
    if (strncmp(argv[i], "-sql=", 5) == 0) {
      sql = argv[i] + 5;
      topic = "test-custom";
      continue;
    }
    if (strcmp(argv[i], "-test") == 0) {
      test = 1;
      continue;
    }
    if (strcmp(argv[i], "-block-fetch") == 0) {
      blockFetch = 1;
      continue;
    }
  }

  TAOS* taos = taos_connect(host, user, passwd, "", 0);
  if (taos == NULL) {
    printf("failed to connect to db, reason:%s\n", taos_errstr(taos));
    exit(1);
  }

  if (test) {
    run_test(taos);
    taos_close(taos);
    exit(0);
  }

  taos_select_db(taos, "test");
  TAOS_SUB* tsub = NULL;
  if (async) {
    // create an asynchronized subscription, the callback function will be called every 1s
    tsub = taos_subscribe(taos, restart, topic, sql, subscribe_callback, &blockFetch, 1000);
  } else {
    // create an synchronized subscription, need to call 'taos_consume' manually
    tsub = taos_subscribe(taos, restart, topic, sql, NULL, NULL, 0);
  }

  if (tsub == NULL) {
    printf("failed to create subscription.\n");
    exit(0);
  }

  if (async) {
    getchar();
  } else
    while (1) {
      TAOS_RES* res = taos_consume(tsub);
      if (res == NULL) {
        printf("failed to consume data.");
        break;
      } else {
        print_result(res, blockFetch);
        getchar();
      }
    }

  printf("total rows consumed: %d\n", nTotalRows);
  taos_unsubscribe(tsub, keep);
  taos_close(taos);

  return 0;
}

查看源码

C/C++ - 图2info

更多示例代码及下载请见 GitHub。 也可以在安装目录下的 examples/c 路径下找到。 该目录下有 makefile,在 Linux 环境下,直接执行 make 就可以编译得到执行文件。 提示:在 ARM 环境下编译时,请将 makefile 中的 -msse4.2 去掉,这个选项只有在 x64/x86 硬件平台上才能支持。

API 参考

以下分别介绍 TDengine 客户端驱动的基础 API、同步 API、异步 API、订阅 API 和无模式写入 API。

基础 API

基础 API 用于完成创建数据库连接等工作,为其它 API 的执行提供运行时环境。

  • void taos_init()

    初始化运行环境。如果没有主动调用该 API,那么调用 taos_connect() 时驱动将自动调用该 API,故程序一般无需手动调用。

  • void taos_cleanup()

    清理运行环境,应用退出前应调用。

  • int taos_options(TSDB_OPTION option, const void * arg, ...)

    设置客户端选项,目前支持区域设置(TSDB_OPTION_LOCALE)、字符集设置(TSDB_OPTION_CHARSET)、时区设置(TSDB_OPTION_TIMEZONE)、配置文件路径设置(TSDB_OPTION_CONFIGDIR)。区域设置、字符集、时区默认为操作系统当前设置。

  • char *taos_get_client_info()

    获取客户端版本信息。

  • TAOS *taos_connect(const char *host, const char *user, const char *pass, const char *db, int port)

    创建数据库连接,初始化连接上下文。其中需要用户提供的参数包含:

    • host:TDengine 集群中任一节点的 FQDN
    • user:用户名
    • pass:密码
    • db: 数据库名字,如果用户没有提供,也可以正常连接,用户可以通过该连接创建新的数据库,如果用户提供了数据库名字,则说明该数据库用户已经创建好,缺省使用该数据库
    • port:taosd 程序监听的端口

    返回值为空表示失败。应用程序需要保存返回的参数,以便后续使用。

    C/C++ - 图3info

    同一进程可以根据不同的 host/port 连接多个 TDengine 集群

  • char *taos_get_server_info(TAOS *taos)

    获取服务端版本信息。

  • int taos_select_db(TAOS *taos, const char *db)

    将当前的缺省数据库设置为 db

  • void taos_close(TAOS *taos)

    关闭连接,其中taostaos_connect() 返回的句柄。

同步查询 API

本小节介绍 API 均属于同步接口。应用调用后,会阻塞等待响应,直到获得返回结果或错误信息。

  • TAOS_RES* taos_query(TAOS *taos, const char *sql)

    执行 SQL 语句,可以是 DQL、DML 或 DDL 语句。 其中的 taos 参数是通过 taos_connect() 获得的句柄。不能通过返回值是否是 NULL 来判断执行结果是否失败,而是需要用 taos_errno() 函数解析结果集中的错误代码来进行判断。

  • int taos_result_precision(TAOS_RES *res)

    返回结果集时间戳字段的精度,0 代表毫秒,1 代表微秒,2 代表纳秒。

  • TAOS_ROW taos_fetch_row(TAOS_RES *res)

    按行获取查询结果集中的数据。

  • int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows)

    批量获取查询结果集中的数据,返回值为获取到的数据的行数。

  • int taos_num_fields(TAOS_RES *res)int taos_field_count(TAOS_RES *res)

    这两个 API 等价,用于获取查询结果集中的列数。

  • int* taos_fetch_lengths(TAOS_RES *res)

    获取结果集中每个字段的长度。返回值是一个数组,其长度为结果集的列数。

  • int taos_affected_rows(TAOS_RES *res)

    获取被所执行的 SQL 语句影响的行数。

  • TAOS_FIELD *taos_fetch_fields(TAOS_RES *res)

    获取查询结果集每列数据的属性(列的名称、列的数据类型、列的长度),与 taos_num_fileds() 配合使用,可用来解析 taos_fetch_row() 返回的一个元组(一行)的数据。 TAOS_FIELD 的结构如下:

typedef struct taosField {
  char     name[65];  // column name
  uint8_t  type;      // data type
  int16_t  bytes;     // length, in bytes
} TAOS_FIELD;
  • void taos_stop_query(TAOS_RES *res)

    停止当前查询的执行。

  • void taos_free_result(TAOS_RES *res)

    释放查询结果集以及相关的资源。查询完成后,务必调用该 API 释放资源,否则可能导致应用内存泄露。但也需注意,释放资源后,如果再调用 taos_consume() 等获取查询结果的函数,将导致应用崩溃。

  • char *taos_errstr(TAOS_RES *res)

    获取最近一次 API 调用失败的原因,返回值为字符串标识的错误提示信息。

  • int taos_errno(TAOS_RES *res)

    获取最近一次 API 调用失败的原因,返回值为错误代码。

C/C++ - 图4note

2.0 及以上版本 TDengine 推荐数据库应用的每个线程都建立一个独立的连接,或基于线程建立连接池。而不推荐在应用中将该连接 (TAOS*) 结构体传递到不同的线程共享使用。基于 TAOS 结构体发出的查询、写入等操作具有多线程安全性,但 “USE statement” 等状态量有可能在线程之间相互干扰。此外,C 语言的连接器可以按照需求动态建立面向数据库的新连接(该过程对用户不可见),同时建议只有在程序最后退出的时候才调用 taos_close() 关闭连接。

异步查询 API

TDengine 还提供性能更高的异步 API 处理数据插入、查询操作。在软硬件环境相同的情况下,异步 API 处理数据插入的速度比同步 API 快 2 ~ 4 倍。异步 API 采用非阻塞式的调用方式,在系统真正完成某个具体数据库操作前,立即返回。调用的线程可以去处理其他工作,从而可以提升整个应用的性能。异步 API 在网络延迟严重的情况下,优势尤为突出。

异步 API 都需要应用提供相应的回调函数,回调函数参数设置如下:前两个参数都是一致的,第三个参数依不同的 API 而定。第一个参数 param 是应用调用异步 API 时提供给系统的,用于回调时,应用能够找回具体操作的上下文,依具体实现而定。第二个参数是 SQL 操作的结果集,如果为空,比如 insert 操作,表示没有记录返回,如果不为空,比如 select 操作,表示有记录返回。

异步 API 对于使用者的要求相对较高,用户可根据具体应用场景选择性使用。下面是两个重要的异步 API:

  • void taos_query_a(TAOS *taos, const char *sql, void (*fp)(void *param, TAOS_RES *, int code), void *param);

    异步执行 SQL 语句。

    • taos:调用 taos_connect() 返回的数据库连接
    • sql:需要执行的 SQL 语句
    • fp:用户定义的回调函数,其第三个参数 code 用于指示操作是否成功,0 表示成功,负数表示失败(调用 taos_errstr() 可获取失败原因)。应用在定义回调函数的时候,主要处理第二个参数 TAOS_RES *,该参数是查询返回的结果集
    • param:应用提供一个用于回调的参数
  • void taos_fetch_rows_a(TAOS_RES *res, void (*fp)(void *param, TAOS_RES *, int numOfRows), void *param);

    批量获取异步查询的结果集,只能与 taos_query_a() 配合使用。其中:

    • res:taos_query_a() 回调时返回的结果集
    • fp:回调函数。其参数 param 是用户可定义的传递给回调函数的参数结构体;numOfRows 是获取到的数据的行数(不是整个查询结果集的函数)。 在回调函数中,应用可以通过调用 taos_fetch_row() 前向迭代获取批量记录中每一行记录。读完一块内的所有记录后,应用需要在回调函数中继续调用 taos_fetch_rows_a() 获取下一批记录进行处理,直到返回的记录数 numOfRows 为零(结果返回完成)或记录数为负值(查询出错)。

TDengine 的异步 API 均采用非阻塞调用模式。应用程序可以用多线程同时打开多张表,并可以同时对每张打开的表进行查询或者插入操作。需要指出的是,客户端应用必须确保对同一张表的操作完全串行化,即对同一个表的插入或查询操作未完成时(未返回时),不能够执行第二个插入或查询操作。

参数绑定 API

除了直接调用 taos_query() 进行查询,TDengine 也提供了支持参数绑定的 Prepare API,风格与 MySQL 类似,目前也仅支持用问号 ? 来代表待绑定的参数。

从 2.1.1.0 和 2.1.2.0 版本开始,TDengine 大幅改进了参数绑定接口对数据写入(INSERT)场景的支持。这样在通过参数绑定接口写入数据时,就避免了 SQL 语法解析的资源消耗,从而在绝大多数情况下显著提升写入性能。此时的典型操作步骤如下:

  1. 调用 taos_stmt_init() 创建参数绑定对象;
  2. 调用 taos_stmt_prepare() 解析 INSERT 语句;
  3. 如果 INSERT 语句中预留了表名但没有预留 TAGS,那么调用 taos_stmt_set_tbname() 来设置表名;
  4. 如果 INSERT 语句中既预留了表名又预留了 TAGS(例如 INSERT 语句采取的是自动建表的方式),那么调用 taos_stmt_set_tbname_tags() 来设置表名和 TAGS 的值;
  5. 调用 taos_stmt_bind_param_batch() 以多行的方式设置 VALUES 的值,或者调用 taos_stmt_bind_param() 以单行的方式设置 VALUES 的值;
  6. 调用 taos_stmt_add_batch() 把当前绑定的参数加入批处理;
  7. 可以重复第 3 ~ 6 步,为批处理加入更多的数据行;
  8. 调用 taos_stmt_execute() 执行已经准备好的批处理指令;
  9. 执行完毕,调用 taos_stmt_close() 释放所有资源。

说明:如果 taos_stmt_execute() 执行成功,假如不需要改变 SQL 语句的话,那么是可以复用 taos_stmt_prepare() 的解析结果,直接进行第 3 ~ 6 步绑定新数据的。但如果执行出错,那么并不建议继续在当前的环境上下文下继续工作,而是建议释放资源,然后从 taos_stmt_init() 步骤重新开始。

接口相关的具体函数如下(也可以参考 prepare.c 文件中使用对应函数的方式):

  • TAOS_STMT* taos_stmt_init(TAOS *taos)

    创建一个 TAOS_STMT 对象用于后续调用。

  • int taos_stmt_prepare(TAOS_STMT *stmt, const char *sql, unsigned long length)

    解析一条 SQL 语句,将解析结果和参数信息绑定到 stmt 上,如果参数 length 大于 0,将使用此参数作为 SQL 语句的长度,如等于 0,将自动判断 SQL 语句的长度。

  • int taos_stmt_bind_param(TAOS_STMT *stmt, TAOS_BIND *bind)

    不如 taos_stmt_bind_param_batch() 效率高,但可以支持非 INSERT 类型的 SQL 语句。 进行参数绑定,bind 指向一个数组(代表所要绑定的一行数据),需保证此数组中的元素数量和顺序与 SQL 语句中的参数完全一致。TAOS_BIND 的使用方法与 MySQL 中的 MYSQL_BIND 类似,具体定义如下:

    typedef struct TAOS_BIND {
      int            buffer_type;
      void *         buffer;
      uintptr_t      buffer_length;  // not in use
      uintptr_t *    length;
      int *          is_null;
      int            is_unsigned;    // not in use
      int *          error;          // not in use
    } TAOS_BIND;
    
  • int taos_stmt_set_tbname(TAOS_STMT* stmt, const char* name)

    (2.1.1.0 版本新增,仅支持用于替换 INSERT 语句中的参数值) 当 SQL 语句中的表名使用了 ? 占位时,可以使用此函数绑定一个具体的表名。

  • int taos_stmt_set_tbname_tags(TAOS_STMT* stmt, const char* name, TAOS_BIND* tags)

    (2.1.2.0 版本新增,仅支持用于替换 INSERT 语句中的参数值) 当 SQL 语句中的表名和 TAGS 都使用了 ? 占位时,可以使用此函数绑定具体的表名和具体的 TAGS 取值。最典型的使用场景是使用了自动建表功能的 INSERT 语句(目前版本不支持指定具体的 TAGS 列)。TAGS 参数中的列数量需要与 SQL 语句中要求的 TAGS 数量完全一致。

  • int taos_stmt_bind_param_batch(TAOS_STMT* stmt, TAOS_MULTI_BIND* bind)

    (2.1.1.0 版本新增,仅支持用于替换 INSERT 语句中的参数值) 以多列的方式传递待绑定的数据,需要保证这里传递的数据列的顺序、列的数量与 SQL 语句中的 VALUES 参数完全一致。TAOS_MULTI_BIND 的具体定义如下:

    typedef struct TAOS_MULTI_BIND {
      int          buffer_type;
      void *       buffer;
      uintptr_t    buffer_length;
      uintptr_t *  length;
      char *       is_null;
      int          num;             // the number of columns
    } TAOS_MULTI_BIND;
    
  • int taos_stmt_add_batch(TAOS_STMT *stmt)

    将当前绑定的参数加入批处理中,调用此函数后,可以再次调用 taos_stmt_bind_param()taos_stmt_bind_param_batch() 绑定新的参数。需要注意,此函数仅支持 INSERT/IMPORT 语句,如果是 SELECT 等其他 SQL 语句,将返回错误。

  • int taos_stmt_execute(TAOS_STMT *stmt)

    执行准备好的语句。目前,一条语句只能执行一次。

  • TAOS_RES* taos_stmt_use_result(TAOS_STMT *stmt)

    获取语句的结果集。结果集的使用方式与非参数化调用时一致,使用完成后,应对此结果集调用 taos_free_result() 以释放资源。

  • int taos_stmt_close(TAOS_STMT *stmt)

    执行完毕,释放所有资源。

  • char * taos_stmt_errstr(TAOS_STMT *stmt)

    (2.1.3.0 版本新增) 用于在其他 STMT API 返回错误(返回错误码或空指针)时获取错误信息。

无模式(schemaless)写入 API

除了使用 SQL 方式或者使用参数绑定 API 写入数据外,还可以使用 Schemaless 的方式完成写入。Schemaless 可以免于预先创建超级表/数据子表的数据结构,而是可以直接写入数据,TDengine 系统会根据写入的数据内容自动创建和维护所需要的表结构。Schemaless 的使用方式详见 Schemaless 写入 章节,这里介绍与之配套使用的 C/C++ API。

  • TAOS_RES* taos_schemaless_insert(TAOS* taos, const char* lines[], int numLines, int protocol, int precision)

    功能说明 该接口将行协议的文本数据写入到 TDengine 中。

    参数说明 taos: 数据库连接,通过 taos_connect() 函数建立的数据库连接。 lines:文本数据。满足解析格式要求的无模式文本字符串。 numLines:文本数据的行数,不能为 0 。 protocol: 行协议类型,用于标识文本数据格式。 precision:文本数据中的时间戳精度字符串。

    返回值 TAOS_RES 结构体,应用可以通过使用 taos_errstr() 获得错误信息,也可以使用 taos_errno() 获得错误码。 在某些情况下,返回的 TAOS_RES 为 NULL,此时仍然可以调用 taos_errno() 来安全地获得错误码信息。 返回的 TAOS_RES 需要调用方来负责释放,否则会出现内存泄漏。

    说明 协议类型是枚举类型,包含以下三种格式:

    • TSDB_SML_LINE_PROTOCOL:InfluxDB 行协议(Line Protocol)
    • TSDB_SML_TELNET_PROTOCOL: OpenTSDB Telnet 文本行协议
    • TSDB_SML_JSON_PROTOCOL: OpenTSDB Json 协议格式

    时间戳分辨率的定义,定义在 taos.h 文件中,具体内容如下:

    • TSDB_SML_TIMESTAMP_NOT_CONFIGURED = 0,
    • TSDB_SML_TIMESTAMP_HOURS,
    • TSDB_SML_TIMESTAMP_MINUTES,
    • TSDB_SML_TIMESTAMP_SECONDS,
    • TSDB_SML_TIMESTAMP_MILLI_SECONDS,
    • TSDB_SML_TIMESTAMP_MICRO_SECONDS,
    • TSDB_SML_TIMESTAMP_NANO_SECONDS

    需要注意的是,时间戳分辨率参数只在协议类型为 SML_LINE_PROTOCOL 的时候生效。 对于 OpenTSDB 的文本协议,时间戳的解析遵循其官方解析规则 — 按照时间戳包含的字符的数量来确认时间精度。

    支持版本 该功能接口从 2.3.0.0 版本开始支持。

订阅和消费 API

订阅 API 目前支持订阅一张或多张表,并通过定期轮询的方式不断获取写入表中的最新数据。

  • TAOS_SUB *taos_subscribe(TAOS* taos, int restart, const char* topic, const char *sql, TAOS_SUBSCRIBE_CALLBACK fp, void *param, int interval)

    该函数负责启动订阅服务,成功时返回订阅对象,失败时返回 NULL,其参数为:

    • taos:已经建立好的数据库连接
    • restart:如果订阅已经存在,是重新开始,还是继续之前的订阅
    • topic:订阅的主题(即名称),此参数是订阅的唯一标识
    • sql:订阅的查询语句,此语句只能是 select 语句,只应查询原始数据,只能按时间正序查询数据
    • fp:收到查询结果时的回调函数(稍后介绍函数原型),只在异步调用时使用,同步调用时此参数应该传 NULL
    • param:调用回调函数时的附加参数,系统 API 将其原样传递到回调函数,不进行任何处理
    • interval:轮询周期,单位为毫秒。异步调用时,将根据此参数周期性的调用回调函数,为避免对系统性能造成影响,不建议将此参数设置的过小;同步调用时,如两次调用 taos_consume() 的间隔小于此周期,API 将会阻塞,直到时间间隔超过此周期。
  • typedef void (*TAOS_SUBSCRIBE_CALLBACK)(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code)

    异步模式下,回调函数的原型,其参数为:

    • tsub:订阅对象
    • res:查询结果集,注意结果集中可能没有记录
    • param:调用 taos_subscribe() 时客户程序提供的附加参数
    • code:错误码
    C/C++ - 图5note

    在这个回调函数里不可以做耗时过长的处理,尤其是对于返回的结果集中数据较多的情况,否则有可能导致客户端阻塞等异常状态。如果必须进行复杂计算,则建议在另外的线程中进行处理。

  • TAOS_RES *taos_consume(TAOS_SUB *tsub)

    同步模式下,该函数用来获取订阅的结果。 用户应用程序将其置于一个循环之中。 如两次调用 taos_consume() 的间隔小于订阅的轮询周期,API 将会阻塞,直到时间间隔超过此周期。如果数据库有新记录到达,该 API 将返回该最新的记录,否则返回一个没有记录的空结果集。 如果返回值为 NULL,说明系统出错。 异步模式下,用户程序不应调用此 API。

    C/C++ - 图6note

    在调用 taos_consume() 之后,用户应用应确保尽快调用 taos_fetch_row()taos_fetch_block() 来处理订阅结果,否则服务端会持续缓存查询结果数据等待客户端读取,极端情况下会导致服务端内存消耗殆尽,影响服务稳定性。

  • void taos_unsubscribe(TAOS_SUB *tsub, int keepProgress)

    取消订阅。 如参数 keepProgress 不为 0,API 会保留订阅的进度信息,后续调用 taos_subscribe() 时可以基于此进度继续;否则将删除进度信息,后续只能重新开始读取数据。