diff --git a/docs/en/07-develop/05-stmt.md b/docs/en/07-develop/05-stmt.md index 16fe156cc3..b63efb903f 100644 --- a/docs/en/07-develop/05-stmt.md +++ b/docs/en/07-develop/05-stmt.md @@ -146,9 +146,19 @@ Not supported ``` + +The example code for binding parameters with stmt2 (TDengine v3.3.5.0 or higher is required) is as follows: + +```c +{{#include docs/examples/c/stmt2_insert_demo.c}} +``` + +The example code for binding parameters with stmt is as follows: + ```c {{#include docs/examples/c/stmt_insert_demo.c}} ``` + Not supported diff --git a/docs/examples/c/Makefile b/docs/examples/c/Makefile index 9fda575ec6..1b889459c2 100644 --- a/docs/examples/c/Makefile +++ b/docs/examples/c/Makefile @@ -9,6 +9,7 @@ TARGETS = connect_example \ with_reqid_demo \ sml_insert_demo \ stmt_insert_demo \ + stmt2_insert_demo \ tmq_demo SOURCES = connect_example.c \ @@ -18,6 +19,7 @@ SOURCES = connect_example.c \ with_reqid_demo.c \ sml_insert_demo.c \ stmt_insert_demo.c \ + stmt2_insert_demo.c \ tmq_demo.c LIBS = -ltaos -lpthread @@ -31,4 +33,4 @@ $(TARGETS): $(CC) $(CFLAGS) -o $@ $(wildcard $(@F).c) $(LIBS) clean: - rm -f $(TARGETS) \ No newline at end of file + rm -f $(TARGETS) diff --git a/docs/examples/c/stmt2_insert_demo.c b/docs/examples/c/stmt2_insert_demo.c new file mode 100644 index 0000000000..e446c5f631 --- /dev/null +++ b/docs/examples/c/stmt2_insert_demo.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +// TAOS standard API example. The same syntax as MySQL, but only a subset +// to compile: gcc -o stmt2_insert_demo stmt2_insert_demo.c -ltaos + +#include +#include +#include +#include +#include "taos.h" + +#define NUM_OF_SUB_TABLES 10 +#define NUM_OF_ROWS 10 + +/** + * @brief Executes an SQL query and checks for errors. + * + * @param taos Pointer to TAOS connection. + * @param sql SQL query string. + */ +void executeSQL(TAOS *taos, const char *sql) { + TAOS_RES *res = taos_query(taos, sql); + int code = taos_errno(res); + if (code != 0) { + fprintf(stderr, "Error: %s\n", taos_errstr(res)); + taos_free_result(res); + taos_close(taos); + exit(EXIT_FAILURE); + } + taos_free_result(res); +} + +/** + * @brief Checks return status and exits if an error occurs. + * + * @param stmt2 Pointer to TAOS_STMT2. + * @param code Error code. + * @param msg Error message prefix. + */ +void checkErrorCode(TAOS_STMT2 *stmt2, int code, const char *msg) { + if (code != 0) { + fprintf(stderr, "%s. Code: %d, Error: %s\n", msg, code, taos_stmt2_error(stmt2)); + taos_stmt2_close(stmt2); + exit(EXIT_FAILURE); + } +} + +/** + * @brief Prepares data bindings for batch insertion. + * + * @param table_name Pointer to store allocated table names. + * @param tags Pointer to store allocated tag bindings. + * @param params Pointer to store allocated parameter bindings. + */ +void prepareBindData(char ***table_name, TAOS_STMT2_BIND ***tags, TAOS_STMT2_BIND ***params) { + *table_name = (char **)malloc(NUM_OF_SUB_TABLES * sizeof(char *)); + *tags = (TAOS_STMT2_BIND **)malloc(NUM_OF_SUB_TABLES * sizeof(TAOS_STMT2_BIND *)); + *params = (TAOS_STMT2_BIND **)malloc(NUM_OF_SUB_TABLES * sizeof(TAOS_STMT2_BIND *)); + + for (int i = 0; i < NUM_OF_SUB_TABLES; i++) { + // Allocate and assign table name + (*table_name)[i] = (char *)malloc(20 * sizeof(char)); + sprintf((*table_name)[i], "d_bind_%d", i); + + // Allocate memory for tags data + int *gid = (int *)malloc(sizeof(int)); + int *gid_len = (int *)malloc(sizeof(int)); + *gid = i; + *gid_len = sizeof(int); + + char *location = (char *)malloc(20 * sizeof(char)); + int *location_len = (int *)malloc(sizeof(int)); + *location_len = sprintf(location, "location_%d", i); + + (*tags)[i] = (TAOS_STMT2_BIND *)malloc(2 * sizeof(TAOS_STMT2_BIND)); + (*tags)[i][0] = (TAOS_STMT2_BIND){TSDB_DATA_TYPE_INT, gid, gid_len, NULL, 1}; + (*tags)[i][1] = (TAOS_STMT2_BIND){TSDB_DATA_TYPE_BINARY, location, location_len, NULL, 1}; + + // Allocate memory for columns data + (*params)[i] = (TAOS_STMT2_BIND *)malloc(4 * sizeof(TAOS_STMT2_BIND)); + + int64_t *ts = (int64_t *)malloc(NUM_OF_ROWS * sizeof(int64_t)); + float *current = (float *)malloc(NUM_OF_ROWS * sizeof(float)); + int *voltage = (int *)malloc(NUM_OF_ROWS * sizeof(int)); + float *phase = (float *)malloc(NUM_OF_ROWS * sizeof(float)); + int32_t *ts_len = (int32_t *)malloc(NUM_OF_ROWS * sizeof(int32_t)); + int32_t *current_len = (int32_t *)malloc(NUM_OF_ROWS * sizeof(int32_t)); + int32_t *voltage_len = (int32_t *)malloc(NUM_OF_ROWS * sizeof(int32_t)); + int32_t *phase_len = (int32_t *)malloc(NUM_OF_ROWS * sizeof(int32_t)); + + (*params)[i][0] = (TAOS_STMT2_BIND){TSDB_DATA_TYPE_TIMESTAMP, ts, ts_len, NULL, NUM_OF_ROWS}; + (*params)[i][1] = (TAOS_STMT2_BIND){TSDB_DATA_TYPE_FLOAT, current, current_len, NULL, NUM_OF_ROWS}; + (*params)[i][2] = (TAOS_STMT2_BIND){TSDB_DATA_TYPE_INT, voltage, voltage_len, NULL, NUM_OF_ROWS}; + (*params)[i][3] = (TAOS_STMT2_BIND){TSDB_DATA_TYPE_FLOAT, phase, phase_len, NULL, NUM_OF_ROWS}; + + for (int j = 0; j < NUM_OF_ROWS; j++) { + struct timeval tv; + gettimeofday(&tv, NULL); + ts[j] = tv.tv_sec * 1000LL + tv.tv_usec / 1000 + j; + current[j] = (float)rand() / RAND_MAX * 30; + voltage[j] = rand() % 300; + phase[j] = (float)rand() / RAND_MAX; + + ts_len[j] = sizeof(int64_t); + current_len[j] = sizeof(float); + voltage_len[j] = sizeof(int); + phase_len[j] = sizeof(float); + } + } +} + +/** + * @brief Frees allocated memory for binding data. + * + * @param table_name Pointer to allocated table names. + * @param tags Pointer to allocated tag bindings. + * @param params Pointer to allocated parameter bindings. + */ +void freeBindData(char ***table_name, TAOS_STMT2_BIND ***tags, TAOS_STMT2_BIND ***params) { + for (int i = 0; i < NUM_OF_SUB_TABLES; i++) { + free((*table_name)[i]); + for (int j = 0; j < 2; j++) { + free((*tags)[i][j].buffer); + free((*tags)[i][j].length); + } + free((*tags)[i]); + + for (int j = 0; j < 4; j++) { + free((*params)[i][j].buffer); + free((*params)[i][j].length); + } + free((*params)[i]); + } + free(*table_name); + free(*tags); + free(*params); +} + +/** + * @brief Inserts data using the TAOS stmt2 API. + * + * @param taos Pointer to TAOS connection. + */ +void insertData(TAOS *taos) { + TAOS_STMT2_OPTION option = {0, false, false, NULL, NULL}; + TAOS_STMT2 *stmt2 = taos_stmt2_init(taos, &option); + if (!stmt2) { + fprintf(stderr, "Failed to initialize TAOS statement.\n"); + exit(EXIT_FAILURE); + } + // stmt2 prepare sql + checkErrorCode(stmt2, taos_stmt2_prepare(stmt2, "INSERT INTO ? USING meters TAGS(?,?) VALUES (?,?,?,?)", 0), + "Statement preparation failed"); + + char **table_name; + TAOS_STMT2_BIND **tags, **params; + prepareBindData(&table_name, &tags, ¶ms); + // stmt2 bind batch + TAOS_STMT2_BINDV bindv = {NUM_OF_SUB_TABLES, table_name, tags, params}; + checkErrorCode(stmt2, taos_stmt2_bind_param(stmt2, &bindv, -1), "Parameter binding failed"); + // stmt2 exec batch + int affected; + checkErrorCode(stmt2, taos_stmt2_exec(stmt2, &affected), "Execution failed"); + printf("Successfully inserted %d rows.\n", affected); + // free and close + freeBindData(&table_name, &tags, ¶ms); + taos_stmt2_close(stmt2); +} + +int main() { + const char *host = "localhost"; + const char *user = "root"; + const char *password = "taosdata"; + uint16_t port = 6030; + TAOS *taos = taos_connect(host, user, password, NULL, port); + if (taos == NULL) { + fprintf(stderr, "Failed to connect to %s:%hu, ErrCode: 0x%x, ErrMessage: %s.\n", host, port, taos_errno(NULL), + taos_errstr(NULL)); + taos_cleanup(); + exit(EXIT_FAILURE); + } + // create database and table + executeSQL(taos, "CREATE DATABASE IF NOT EXISTS power"); + executeSQL(taos, "USE power"); + executeSQL(taos, + "CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS " + "(groupId INT, location BINARY(24))"); + insertData(taos); + taos_close(taos); + taos_cleanup(); +} \ No newline at end of file diff --git a/docs/zh/07-develop/05-stmt.md b/docs/zh/07-develop/05-stmt.md index 56ed706bf2..29909f0aa1 100644 --- a/docs/zh/07-develop/05-stmt.md +++ b/docs/zh/07-develop/05-stmt.md @@ -141,9 +141,20 @@ stmt 绑定参数的示例代码如下: ``` + +stmt2 绑定参数的示例代码如下(需要 TDengine v3.3.5.0 及以上): + +```c +{{#include docs/examples/c/stmt2_insert_demo.c}} +``` + +stmt 绑定参数的示例代码如下: + ```c {{#include docs/examples/c/stmt_insert_demo.c}} ``` + + 不支持 diff --git a/tests/docs-examples-test/c.sh b/tests/docs-examples-test/c.sh index 54e334b22e..01b5428c82 100644 --- a/tests/docs-examples-test/c.sh +++ b/tests/docs-examples-test/c.sh @@ -34,6 +34,7 @@ declare -a TEST_EXES=( "query_data_demo" "with_reqid_demo" "stmt_insert_demo" + "stmt2_insert_demo" "tmq_demo" "sml_insert_demo" ) @@ -46,6 +47,7 @@ declare -a NEED_CLEAN=( "false" "false" "false" + "false" "true" ) @@ -89,4 +91,4 @@ if [ "$totalFailed" -ne "0" ]; then exit 1 fi -echo "All tests completed." \ No newline at end of file +echo "All tests completed."